pax_global_header00006660000000000000000000000064132532322350014512gustar00rootroot0000000000000052 comment=d2771ca93ba9461a823240e3f3b7be9f4af12f65 quagga-1.2.4/000077500000000000000000000000001325323223500127635ustar00rootroot00000000000000quagga-1.2.4/AUTHORS000066400000000000000000000003261325323223500140340ustar00rootroot00000000000000Kunihiro Ishiguro Toshiaki Takada Yasuhiro Ohara Alex D. Zinin Gleb Natapov Akihiro Mizutani quagga-1.2.4/COPYING000066400000000000000000000430711325323223500140230ustar00rootroot00000000000000 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. quagga-1.2.4/COPYING.LIB000066400000000000000000000612721325323223500144330ustar00rootroot00000000000000 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! quagga-1.2.4/ChangeLog000066400000000000000000000002051325323223500145320ustar00rootroot00000000000000ChangeLog information for Quagga is now recorded in our source-code management system. Please see: http://www.quagga.net/devel.php quagga-1.2.4/INSTALL000066400000000000000000000366101325323223500140220ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command `./configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. 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, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. 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 you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' 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. Running `configure' might take a while. 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, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. 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. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. 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 can use 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 `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer 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. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' 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. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= 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'. 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. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS 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 machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. 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. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. quagga-1.2.4/INSTALL.quagga.txt000066400000000000000000000106111325323223500160750ustar00rootroot00000000000000-------------------------------------------------------------------------- Building and Installing Quagga from releases or snapshots: The 'INSTALL' file contains generic instructions on how to use 'configure' scripts. Quagga requires a C compiler (and associated header files and libraries) supporting the C99 standard. Quagga requires a reasonable make. It is considered a bug if quagga does not compile with the system make on recent FreeBSD, NetBSD or OpenBSD, and a very serious bug if it does not compile with GNU make. Quagga expects a POSIX.2 compliant system, more or less. Clean workarounds for POSIX non-compliance are welcome. It is considered a bug if Quagga fails to build and run on any of the following systems (where .x indicates the most recent release), or such systems "-current" versions. Or, it might be that this list is out of date and will be updated. (Note that considering it a bug is not a guarantee of support, merely "we agree that it is broken".) Dragonfly ? FreeBSD (stable branches currently supported, plus perhaps one) FreeBSD-current Linux [kernel/distribution information needed] NetBSD 4.x NetBSD 5.x NetBSD 6.x NetBSD-current OpenBSD ? [info needed on what should work] Solaris (modern/supported versions, including OpenSolaris forks) On BSD systems, installing libexecinfo is strongly recommended in order to get backtrace support. For further Quagga specific information on 'configure' and build-time configuration of the software, please read the Quagga info documentation, (doc/quagga.info). To read the info page included with the Quagga sources without first installing Quagga: cd doc # one of the following, depending on your info viewer preferences info quagga.info pinfo -r quagga.info emacs -eval '(info "quagga.info")' The Quagga website (http://www.quagga.net) currently has the info files available in various formats. -------------------------------------------------------------------------- Building Quagga from git checkouts: In order to build from git, you will need recent versions of several GNU tools, particularly autoconf, automake, libtool, GNU awk and texinfo. Note that the CVS snapshots on the Quagga website should not require these tools; everything is already setup ready to run 'configure'. If you have trouble building from CVS checkout it is recommended that you try a CVS snapshot instead. We declare that the following versions should work for building from CVS checkouts. Earlier versions may work, but failure to do so is not a bug. Required versions can be moved earlier if no problems, or later after a judgement that a system without a higher version is deficient is made. [TODO: this list is out of date as of 2013-07] automake: 1.9.6 (released 2005-07-10) autoconf: 2.59 (2.60 on 2006-06-26 is too recent to require) libtool: 1.5.22 (released 2005-12-18) texinfo: 4.7 (released 2004-04-10; 4.8 is not yet common) GNU AWK: 3.1.5 (released 2005-08-12) For running tests, one also needs: DejaGnu: [TODO: texinfo 4.6 is now ancient and this should be revisited/fixed] Because some systems provide texinfo 4.6 (4.7 is new), quagga.info is checked in so that texinfo will generally not be invoked. When texinfo 4.7 is widespread, quagga.info will be removed from CVS and texinfo will become required again. (4.7 has figure support, needed for the route server docs, which is why 4.6 doesn't work.) In order to create PostScript or PDF versions of the Texinfo documentation, you will need the convert utility, from the ImageMagick toolset installed, and epstopdf from the TeTeX suite. To create the required autotools files (Makefile.in, configure, etc.), run "./bootstrap.sh". After this you may run configure as for a snapshot or release. Please refer to "Building and Installing Quagga" above for further instructions. -------------------------------------------------------------------------- Notes on required versions: The general goal is to use a modern baseline of tools, while not imposing pain on those tracking supported (or almost supported) stable distributions. The notes below explain what versions are present in various environments. NetBSD 4 provides texinfo 4.7. NetBSD 5 and 6 provides texinfo 4.8 Fedora Core ? provides autoconf 2.59. OpenBSD 3.6 provides texinfo 4.2. OpenBSD [3.6] ports provides automake 1.4-p6 autoconf 2.5.9 libtool 1.5.8 -------------------------------------------------------------------------- quagga-1.2.4/Makefile.am000066400000000000000000000013121325323223500150140ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. SUBDIRS = lib qpb fpm @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @NHRPD@ \ @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d nhrpd \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris pimd EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ vtysh/Makefile.in vtysh/Makefile.am \ tools/zebra.el tools/multiple-bgpd.sh if HAVE_PANDOC HACKING.pdf: HACKING.md pandoc -o $@ $< clean-local: -$(LATEXMK) -C HACKING.tex endif ACLOCAL_AMFLAGS = -I m4 quagga-1.2.4/Makefile.in000066400000000000000000000657371325323223500150520ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in AUTHORS \ COPYING COPYING.LIB ChangeLog INSTALL NEWS README TODO compile \ config.guess config.sub install-sh ltmain.sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = lib qpb fpm @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @NHRPD@ \ @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d nhrpd \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris pimd EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ vtysh/Makefile.in vtysh/Makefile.am \ tools/zebra.el tools/multiple-bgpd.sh ACLOCAL_AMFLAGS = -I m4 all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 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: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt # 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. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -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 $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_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 case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 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 in build directory 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @HAVE_PANDOC_FALSE@clean-local: clean: clean-recursive clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool clean-local cscope cscopelist-am ctags ctags-am \ dist dist-all dist-bzip2 dist-gzip dist-lzip dist-shar \ dist-tarZ dist-xz dist-zip distcheck distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile @HAVE_PANDOC_TRUE@HACKING.pdf: HACKING.md @HAVE_PANDOC_TRUE@ pandoc -o $@ $< @HAVE_PANDOC_TRUE@clean-local: @HAVE_PANDOC_TRUE@ -$(LATEXMK) -C HACKING.tex # 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: quagga-1.2.4/NEWS000066400000000000000000002176041325323223500134740ustar00rootroot00000000000000Note: this file lists major user-visible changes only. * Changes in Quagga [] - [zebra] "no link-detect" is no longer the default. The previous release of Quagga always explicitly writes-out the link-detect configuration state. Therefore, to retain current behavior save your config with the prior release before updating. Otherwise, review your configuration. Note, most users will generally want to have link-detect enabled, and so can just remove 'no link-detect' from their interface configuration. This release also adds a global configuration to specify the default, which can be specified in the zebra configuration as: default link-detect (on|off) This will then apply to any interface which does not have link-detect explicitly configured. * Changes in Quagga 0.99.24 User-visible changes: - [pimd] New daemon: pimd provides IPv4 PIM-SSM multicast routing. - [bgpd] New feature: "next-hop-self all" to override nexthop on iBGP route reflector setups. - [bgpd] route-maps have a new action "set ipv6 next-hop peer-address" - [bgpd] route-maps have a new action "set as-path prepend last-as" - [bgpd] Update validity checking (particularly MP-BGP / IPv6 routes) was touched up significantly. Please report possible bugs. - [ripd] New feature: RIP for IPv4 now supports equal-cost multipath (ECMP) - [zebra] Multicast RIB support has been extended. It still is IPv4 only. - [zebra] "no link-detect" is now printed in configurations since it won't be the default anymore soon. To retain current behaviour, re-save your configuration after updating to 0.99.24. Distributor-visible changes: - --enable-pimd is added to enable pimd. It is considered experimental, though unless the distribution target is embedded systems with little flash, there is no reason to not include it in packages. - --disable-ipv6 no longer exists as an option. It's 2015, your C library really needs to have IPv6 support by now. - --disable-netlink no longer exists as an option. It didn't work anyway. - --disable-solaris no longer exists as an option. It only controlled some init scripts. - --enable-isisd is now the default. - mrlg.cgi is no longer included (it was severely outdated). It can be found independently at http://mrlg.op-sec.us/ - build on Linux with the musl C library should now work * Changes in Quagga 0.99.23 Known issues: - [bgpd] setting an extcommunity in a route map on a route that already has an extcommunity attribute will cause bgpd to crash. This issue will be fixed in a followup minor release. User-visible changes: - [lib] Performance enhancements on hashes and timers. - [bgpd] New feature: iBGP TTL security. - [bgpd] New feature: relaxed bestpath criteria for multipath and improved display of multipath routes in "show ip bgp". Scripts parsing this output may need to be updated. - [bgpd] Multiprotocol peerings over IPv6 now try to find a more appropriate IPv4 nexthop by looking at the interface. - [ospf6d] A large amount of changes has been merged for ospf6d. Careful evaluation prior to deployment is recommended. - [zebra] Recursive route support has been overhauled. Scripts parsing "show ip route" output may need adaptation. - [zebra] IPv6 address management has been improved regarding tentative addresses. This is visible in that a freshly configured address will not immediately be marked as usable. - [*] a lot of bugs have been fixed, please refer to the git log * Changes in Quagga 0.99.22 - [bgpd] The semantics of default-originate route-map have changed. The route-map is now used to advertise the default route conditionally. The old behaviour which allowed to set attributes on the originated default route is no longer supported. - [bgpd] There is now a replace-as option to neighbor ... local-as ... no-prepend. For details, refer to the user documentation. - [zebra] An FPM interface has been added. This provides an alternate interface to routing information and is geared at OpenFlow & co. - [snmp] AgentX is now supported; the old smux backend is considered deprecated. ospf6d has also had OSPFV3-MIB added. - [*] several issues with configuration save/load/apply have been fixed, in particular on ospf "max-metric router-lsa administrative" and "distribute-list", bgpd "no neighbor activate", isisd "metric-style", - [*] a lot of bugs have been fixed, please refer to the git log * Changes in Quagga 0.99.21 - [bgpd] BGP multipath support has been merged - [bgpd] SAFI (Multicast topology) support has been extended to propagate the topology to zebra. - [bgpd] AS path limit functionality has been removed - [babeld] a new routing daemon implementing the BABEL ad-hoc mesh routing protocol has been merged. - [isisd] a major overhaul has been picked up. Please note that isisd is STILL NOT SUITABLE FOR PRODUCTION USE. - [*] a lot of bugs have been fixed, please refer to the git log * Changes in Quagga 0.99.10 - [bgpd] 4-byte AS support added - [bgpd] MRT format changes to version 2. Those relying on bgpd MRT table dumps may need to update their tools. - [bgpd] Added new route-map set statement: "as-path exclude" - Zebra RIB updates queue has evolved into a multi-level structure to address RIB consistency issues. * Changes in Quagga 0.99.2 - [bgpd] Work queues added to bgpd to split up update processing, particularly beneficial when a peer session goes down. AS_PATH parsing rewritten to be clearer, more robust and ready for 4-byte. - [ripd] Simple authentication is no longer the default authentication mode for ripd. The default is now no-authentication. Any setups which used simple authentication will probably need to update their configuration manually. - [ospfd] 1s dead-interval with sub-second Hellos feature added. SPF timers now specified in milliseconds, and with adaptive hold-time support. RFC3137 Stub-router support added. Default ABR type is now 'cisco'. - Solaris least privileges support added. * Changes in Quagga 0.99.1 - Zserv is now buffered via threads and non-blocking in most cases for both clients and zebra, which should improve responsiveness of daemons when they must send many messages to zebra. - 'show thread cpu' now displays both cpu+system and wall-clock time, where getrusage() is available. - Background threads added and workqueue API added, with a 'show work-queues' command. Thread scheduling improved slightly. - Zebra now has a work-queue for RIB processing. See 'show work-queues' in the zebra daemon vty. - Support for interface renaming on Linux netlink systems. - GNU Zebra bgpd merges, including BGP Graceful-restart and "match ip route-source" command. - Automatic logging of backtraces should daemons crash to assist in diagnosis. See the documentation for more information on configuring logging correctly, and set --enable-gcc-rdynamic if compiling with gcc. * Changes in Quagga 0.98.0 - Logging facilities upgraded. One can now specify a severity level for each logging destination. And a new "show logging" command gives thorough information on the current logging system configuration. - Watchquagga daemon added. This is not well tested yet. Please try monitor mode first before enabling restart features. It is important to make sure that the various timers are configured with appropriate values for your site. - BGP route-server support added. See the texinfo documentation. - OSPF API initialisation is disabled by default even if compiled in. You can enable it with -a/--apiserver command line switch. - "write-config integrated" vtysh command replaced with "service integrated-vtysh-config" command. - Router id is now handled by zebra daemon and all daemons receive changes from it. Router id can be overriden in daemons' configurations of course. To fix common router id in zebra daemon you can either install non-127 address on loopback or use "router-id x.x.x.x" command. - "secondary" keyword is removed from ip address configuration. All supported OS'es have their own vision what's secondary address and how to handle it. - Zebra no longer enables forwarding by default. If you rely on zebra to enable forwarding make sure to add ' forwarding' statements to your zebra configuration file. - All libraries are built and used shared, on platforms where libtool supports shared libraries. - Router advertisement syntax is changed. In usual cases (if you didn't do any fancy stuff) it's enough to change lines in configuration from: "ipv6 nd prefix-advertisement X:X:X:X::/X 2592000 604800 autoconfig on-link" to: "ipv6 nd prefix X:X:X:X::/X" All router advertisement options are documented in texi documentation. - --enable-nssa configure switch is removed. NSSA support is stable enough. - Daemons don't look at current directory for config file any more. * Changes in Quagga 0.96.5 - include files are installed in $(prefix)/include/quagga. Programs building against these includes should -I$(prefix)/include and e.g. #include - New option --enable-exampledir puts example files in a separate directory from $(sysconfdir), easing NetBSD pkgsrc hierarchy rules compliance. - New configure options --enable-configfile-mask and --enable-logfile-mask to set umask values for config and log values. Masks default to 0600, matching previous behavior. - Import current CVS isisd from SourceForge, then merge it with the Quagga's Framework. * Changes in Quagga 0.96.4 - Further fixes to ospfd, some relating to the PtP revert. Interface lookups should be a lot more robust now. - Fix for a remote triggerable crash in vty layer. - Improvements to ripd, and addition of split horizon support. - Improved bgpd table support, now dumps at time of day intervals rather than time from startup intervals. Much improved support for IPv6 table dumps. show commands for views improved. * Changes in Quagga 0.96.3 - revert the 'generic PtP' patch. Means Quagga will no longer work with FreeSWAN, however, on the plus side this gets rid of a lot of niggly bugs which the PtP patch introduced. * Changes in Quagga 0.96.2 - Fix crash in ospfd * Changes in Quagga 0.96.1 - Iron out problem with the privileges definitions * Changes in Quagga 0.96 - Privilege support, daemons now run with the minimal privileges needed, see the documentation for details. - NSSA ABR support in ospfd. - OSPF-API support merged in. - 6WIND patch merged in. * 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: quagga-1.2.4/README000066400000000000000000000007201325323223500136420ustar00rootroot00000000000000Quagga is free software that manages various IPv4 and IPv6 routing protocols. Currently Quagga supports the following protocols Unicast Routing:BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng as well as very early support for IS-IS. Multicast Routing: PIM-SSM See the file INSTALL.quagga.txt for building and installation instructions. See the file REPORTING-BUGS to report bugs. Quagga is free software. See the file COPYING for copying conditions. quagga-1.2.4/REPORTING-BUGS000066400000000000000000000033651325323223500150240ustar00rootroot00000000000000This file describes the procedure for reporting Quagga bugs. You are not obliged to follow this format, but it would be great help for Quagga developers if you report a bug as described below. Bugs submitted with woefully incomplete information may be summarily closed. Submitters of bugs against old versions may be asked to retest against the latest release. Submitters may be asked for additional information. Bugs may be closed after 30 days of non-response to requests to reconfirm or supply additional information. Report bugs http://bugzilla.quagga.net Please supply the following information: 1. Your Quagga version or if it is from git then the commit reference. Please try to report bugs against git master or the latest release. 2. Quagga daemons you run e.g. bgpd or ripd and full name of your OS. Any specific options you compiled Quagga with. 3. Problem description. Copy and paste relative 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 (BSD) or ip (Linux)). 4. All Quagga 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 Quagga daemon core dumped, please, supply stack trace using the following commands: host> gdb exec_file core_file , (gdb) bt . 6. Run all Quagga 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. quagga-1.2.4/SERVICES000066400000000000000000000007061325323223500141340ustar00rootroot00000000000000# 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 ospfapi 2607/tcp isisd 2608/tcp pimd 2611/tcp nhrpd 2612/tcp quagga-1.2.4/TODO000066400000000000000000000142471325323223500134630ustar00rootroot00000000000000 Quagga TODO list 2013-03-29 This is the Quagga primary TODO list. It is on git because that way changes pass through the usual process just like code does, therefore they will have the same visibility. If you are working on something beyond a simple fix, to avoid double work it is a good idea to submit a patch to this TODO list when you are starting, listing what you're doing. Also, as others may have done just that, check the list before starting. Google Summer of Code 2013 note: this list double-serves as idea list for the Summer of Code. Ideas considered suitable for students are marked with a star after the number, like this: "[Q999*] achieve world peace". They will also have extended descriptions. Nevertheless, if you'd like to do something else, just write a mail to the mailing list: quagga-dev@lists.quagga.net "GSoC-Mentors:" listings are preliminary at this point. Overall ======= [Q000] improve unit test architecture [Q001] kick invalid runtime tests from configure.ac, use list of supported OSes and their APIs instead. Priority: low State: patch half-done 2013-03-29 David Lamparter [Q002*] clean up zebra IPC, remove code duplication, align to common API Priority: high GSoC-Mentors: David Lamparter, Christian Franke Quagga posesses an IPC mechanism to exchange route information among the different daemons and Zebra, the kernel-interface. This mechanism is implemented in libzebra, but is currently used in all sorts of different ways in the individual protocol daemons. Also, in the future the entire protocol needs to be redone in an extensible way, so we're able to support MPLS, BFD, Multi-Topology/Instance, VRFs, ... This TODO entry only refers to the first-step API cleanup. All the daemons need to use a single, well-defined libzebra API. Only after this has been addressed can we look upon changing the protocol itself, since by then it will be encapsulated inside libzebra. [Q003] add multi-instance / multi-topology support to the individual protocols [Q004] MPLS support State: work in progress 2013-03-29 Renato Westphal, Timo Teräs [Q005] BFD support State: two old implementations exist, contact Hasso Tepper library ======= [L000] improve route_table speed, eg strided lookups for common prefix depths. [L001] ipv6 addresses need concept of valid/preferred [L002] implement a generic daemon access/control protocol (eg D-Bus like? simplified SNMP-a-like? NETCONF?) [L003] extend vty command definitions to allow them to be self-documenting i18n command help strings [L004] create a common libspf (for ospfd, ospf6d and possibly isisd and more). cf. TODO item [O000] for the ospfd/ospf6d specific variant [L005] stabilise the API (possibly including symbol/library versioning voodoo) [L006] Document the exported API (DocBook/Doxygen?) [LE00] incorporate library changes from Euro-IX branch, except threading [LE01] incorporate threading library support from Euro-IX branch zebra ===== [Z000] Pointopoint address configuration. Priority: low State: patch done & tested 2013-03-29 David Lamparter [Z001] Add support for valid and preferred lifetimes to IPv6 addresses [Z002] proper support for (at least) 1-level recursive routes Priority: high [Z003] Ability to set src on routes, where systems support it. [Z004] Ability to apply route-maps to daemon route updates. bgpd ==== [B000] HUP signal support (reload configuration file). [B001*] BGP multi-path extension, relaxed mode Priority: medium Implemented, patch will be sent shortly Pradosh Mohapatra, Cumulus Networks [B002] move FSM state to be per-connection, not per-peer. [B003] Add support for internal and minimum-metric MED setting ripd ==== [R000] Multipath support. ospfd/ospf6d ============ [O000] move SPF to common code [O001] extend code sharing between ospfd and ospf6d beyond SPF [O002*] OSPF testing replay tool Priority: medium GSoC-Mentors: Martin Winter, Christian Franke, David Lamparter In order to extensively test OSPF implementations, a tool to fake an OSPF neighbor is immensely useful. This tool needs to be capable of forming an adjacency and pushing LSAs to the device to be tested. To maintain the adjacency, some minimal state tracking is useful. In total, the tool needs to form an adjacency, read and push LSAs, and output received LSAs. Additional tools to generate LSAs from specifications as well as verify received LSA correctness can then be built on top of that. The tool needs to support IPv4 and IPv6, possibly split into 2 tools with some code sharing. ospfd: [O400] Demand circuits. Priority: very low [O401] Multiple instances. Priority: medium [O402] HUP signal treatment. Priority: medium State: patch on ML needs review 2012-06-04 Mattias Walström ospf6d: [O600*] fix ospf6d in general Priority: high State: patches tickling in from Cumulus Networks 2013-03-29 Dinesh Dutt Implemented: p2p link support, ABR, Stub area/Totally Stubby area, SPF throttling, Improving state machine to get performance/scale, max-metric support, Improving ECMP to be > 4, Various other bug fixes [O601*] OSPFv3 autoconfiguration, prefix assignment and sourcedest routing Priority: medium State: work in progress 2013-03-29 Edward Seabrook GSoC-Mentors: David Lamparter OSPFv3 application in the homenet is being designed to use several extensions to the base protocol. In order of dependency, autoconfiguration, prefix assignment and sourcedest routing should be implemented. This task requires a good level of OSPF understanding plus proper ability to follow IETF discussion about these points. Also, since work has already started on this, improvements must obviously build on top of that. isisd ===== [I000] reassess isisd TODO [I001*] IS-IS testing replay tool Priority: medium GSoC-Mentors: Martin Winter, Christian Franke, David Lamparter see [O002*]. [I002] Mesh groups (RFC2973) [I003] Crypto authentication (RFC3567) vtysh ===== [V000] untangle readline specific bits [V001] add a vtyd with a vty (ie telnet) frontend (as opposed to readline) [V002] (=> [L002]) use daemon control protocol [V003] better AAA support than just PAM, eg krb5, SASL, LDAP... quagga-1.2.4/aclocal.m4000066400000000000000000001533261325323223500146350ustar00rootroot00000000000000# generated automatically by aclocal 1.15 -*- Autoconf -*- # Copyright (C) 1996-2014 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. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 11 (pkg-config-0.29.1) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.1]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES # Copyright (C) 2002-2014 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. # 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. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.15], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.15])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2014 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. # 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. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2014 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. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl 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])]) # Copyright (C) 1999-2014 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. # 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", "OBJC", "OBJCXX", "UPC", or "GJC". # 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 m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$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". rm -rf conftest.dir 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 # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub 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 am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # 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. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # 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. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; 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 ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi 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_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2014 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. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf 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. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. 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 " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/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"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2014 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 macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # 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_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])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]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # 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. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2014 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2014 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. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2014 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. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit 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 # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2014 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. # 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 is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2014 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. # _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], [m4_foreach_w([_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])]) # Copyright (C) 1999-2014 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. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2014 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. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2014 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. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # 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 ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file 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 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 if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done 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]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2014 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. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2014 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. # AM_PROG_INSTALL_STRIP # --------------------- # 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="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2014 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. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2014 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. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/ax_sys_weak_alias.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) quagga-1.2.4/bgpd/000077500000000000000000000000001325323223500136775ustar00rootroot00000000000000quagga-1.2.4/bgpd/BGP4-MIB.txt000066400000000000000000001073401325323223500155460ustar00rootroot00000000000000 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 quagga-1.2.4/bgpd/Makefile.am000066400000000000000000000026071325323223500157400ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libbgp.a sbin_PROGRAMS = bgpd bin_PROGRAMS = bgp_btoa 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_lcommunity.c \ bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_encap.c bgp_encap_tlv.c bgp_nht.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_lcommunity.h \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \ bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h bgp_nht.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ bgp_btoa_SOURCES = bgp_btoa.c bgp_btoa_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ examplesdir = $(exampledir) dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 EXTRA_DIST = BGP4-MIB.txt quagga-1.2.4/bgpd/Makefile.in000066400000000000000000000733171325323223500157570ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = bgpd$(EXEEXT) bin_PROGRAMS = bgp_btoa$(EXEEXT) subdir = bgpd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libbgp_a_AR = $(AR) $(ARFLAGS) 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_lcommunity.$(OBJEXT) bgp_mplsvpn.$(OBJEXT) \ bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) bgp_table.$(OBJEXT) \ bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT) bgp_mpath.$(OBJEXT) \ bgp_encap.$(OBJEXT) bgp_encap_tlv.$(OBJEXT) bgp_nht.$(OBJEXT) libbgp_a_OBJECTS = $(am_libbgp_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(examplesdir)" PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) am_bgp_btoa_OBJECTS = bgp_btoa.$(OBJEXT) bgp_btoa_OBJECTS = $(am_bgp_btoa_OBJECTS) bgp_btoa_DEPENDENCIES = libbgp.a ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_bgpd_OBJECTS = bgp_main.$(OBJEXT) bgpd_OBJECTS = $(am_bgpd_OBJECTS) bgpd_DEPENDENCIES = libbgp.a ../lib/libzebra.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libbgp_a_SOURCES) $(bgp_btoa_SOURCES) $(bgpd_SOURCES) DIST_SOURCES = $(libbgp_a_SOURCES) $(bgp_btoa_SOURCES) $(bgpd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libbgp.a 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_lcommunity.c \ bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_encap.c bgp_encap_tlv.c bgp_nht.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_lcommunity.h \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \ bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h bgp_nht.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ bgp_btoa_SOURCES = bgp_btoa.c bgp_btoa_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ examplesdir = $(exampledir) dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 EXTRA_DIST = BGP4-MIB.txt all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bgpd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu bgpd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libbgp.a: $(libbgp_a_OBJECTS) $(libbgp_a_DEPENDENCIES) $(EXTRA_libbgp_a_DEPENDENCIES) $(AM_V_at)-rm -f libbgp.a $(AM_V_AR)$(libbgp_a_AR) libbgp.a $(libbgp_a_OBJECTS) $(libbgp_a_LIBADD) $(AM_V_at)$(RANLIB) libbgp.a install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list bgp_btoa$(EXEEXT): $(bgp_btoa_OBJECTS) $(bgp_btoa_DEPENDENCIES) $(EXTRA_bgp_btoa_DEPENDENCIES) @rm -f bgp_btoa$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bgp_btoa_OBJECTS) $(bgp_btoa_LDADD) $(LIBS) bgpd$(EXEEXT): $(bgpd_OBJECTS) $(bgpd_DEPENDENCIES) $(EXTRA_bgpd_DEPENDENCIES) @rm -f bgpd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bgpd_OBJECTS) $(bgpd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) 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_btoa.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_encap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_encap_tlv.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_lcommunity.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mpath.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_nht.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_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@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/bgpd/bgp_advertise.c000066400000000000000000000232031325323223500166610ustar00rootroot00000000000000/* 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 "filter.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 (void) { 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 (void *p) { struct bgp_advertise_attr * ref = (struct bgp_advertise_attr *) p; struct bgp_advertise_attr *baa; baa = baa_new (); baa->attr = ref->attr; return baa; } static unsigned int baa_hash_key (void *p) { struct bgp_advertise_attr * baa = (struct bgp_advertise_attr *) p; return attrhash_key_make (baa->attr); } static int baa_hash_cmp (const void *p1, const void *p2) { const struct bgp_advertise_attr * baa1 = p1; const struct bgp_advertise_attr * baa2 = p2; 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 (void) { return (struct bgp_advertise *) XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise)); } static void bgp_advertise_free (struct bgp_advertise *adv) { if (adv->binfo) bgp_info_unlock (adv->binfo); /* bgp_advertise bgp_info reference */ XFREE (MTYPE_BGP_ADVERTISE, adv); } static 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; } static 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; } static 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. */ static void bgp_adj_out_free (struct bgp_adj_out *adj) { peer_unlock (adj->peer); /* adj_out peer reference */ 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; struct bgp_advertise_fifo *fhead; adv = adj->adv; baa = adv->baa; next = NULL; fhead = (struct bgp_advertise_fifo *)&peer->sync[afi][safi]->withdraw; 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); fhead = (struct bgp_advertise_fifo *)&peer->sync[afi][safi]->update; } /* Unlink myself from advertisement FIFO. */ BGP_ADV_FIFO_DEL (fhead, 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; if (DISABLE_BGP_ANNOUNCE) return; /* 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)); adj->peer = peer_lock (peer); /* adj_out peer reference */ if (rn) { BGP_ADJ_OUT_ADD (rn, adj); bgp_lock_node (rn); } } if (adj->adv) bgp_advertise_clean (peer, adj, afi, safi); adj->adv = bgp_advertise_new (); adv = adj->adv; adv->rn = rn; assert (adv->binfo == NULL); adv->binfo = bgp_info_lock (binfo); /* bgp_info adj_out reference */ 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); BGP_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; if (DISABLE_BGP_ANNOUNCE) return; /* 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. */ BGP_ADV_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_lock (peer); /* adj_in peer reference */ 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); peer_unlock (bai->peer); /* adj_in peer reference */ XFREE (MTYPE_BGP_ADJ_IN, bai); } int 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 0; bgp_adj_in_remove (rn, adj); bgp_unlock_node (rn); return 1; } 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_BGP_SYNCHRONISE, sizeof (struct bgp_synchronize)); BGP_ADV_FIFO_INIT (&sync->update); BGP_ADV_FIFO_INIT (&sync->withdraw); BGP_ADV_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_BGP_SYNCHRONISE, peer->sync[afi][safi]); peer->sync[afi][safi] = NULL; if (peer->hash[afi][safi]) hash_free (peer->hash[afi][safi]); peer->hash[afi][safi] = NULL; } } quagga-1.2.4/bgpd/bgp_advertise.h000066400000000000000000000113561325323223500166740ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_ADVERTISE_H #define _QUAGGA_BGP_ADVERTISE_H #include /* BGP advertise FIFO. */ struct bgp_advertise_fifo { struct bgp_advertise *next; struct bgp_advertise *prev; u_int32_t count; }; /* 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 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 fifo update; struct fifo withdraw; struct fifo withdraw_low; }; #define BGP_ADV_FIFO_HEAD(F) ((struct bgp_advertise *)FIFO_HEAD(F)) /* 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) #define BGP_ADV_FIFO_ADD(F, N) \ do { \ FIFO_ADD((F), (N)); \ (F)->count++; \ } while (0) #define BGP_ADV_FIFO_DEL(F, N) \ do { \ FIFO_DEL((N)); \ (F)->count--; \ } while (0) #define BGP_ADV_FIFO_INIT(F) \ do { \ FIFO_INIT((F)); \ (F)->count = 0; \ } while (0) /* Prototypes. */ extern void bgp_adj_out_set (struct bgp_node *, struct peer *, struct prefix *, struct attr *, afi_t, safi_t, struct bgp_info *); extern void bgp_adj_out_unset (struct bgp_node *, struct peer *, struct prefix *, afi_t, safi_t); extern void bgp_adj_out_remove (struct bgp_node *, struct bgp_adj_out *, struct peer *, afi_t, safi_t); extern int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t, struct bgp_node *); extern void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *); extern int bgp_adj_in_unset (struct bgp_node *, struct peer *); extern void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *); extern struct bgp_advertise * bgp_advertise_clean (struct peer *, struct bgp_adj_out *, afi_t, safi_t); extern void bgp_sync_init (struct peer *); extern void bgp_sync_delete (struct peer *); #endif /* _QUAGGA_BGP_ADVERTISE_H */ quagga-1.2.4/bgpd/bgp_aspath.c000066400000000000000000001434621325323223500161650ustar00rootroot00000000000000/* AS path management routines. Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro Copyright (C) 2005 Sun Microsystems, 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 "hash.h" #include "memory.h" #include "vector.h" #include "vty.h" #include "str.h" #include "log.h" #include "stream.h" #include "jhash.h" #include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_attr.h" /* Attr. Flags and Attr. Type Code. */ #define AS_HEADER_SIZE 2 /* Now FOUR octets are used for AS value. */ #define AS_VALUE_SIZE sizeof (as_t) /* This is the old one */ #define AS16_VALUE_SIZE sizeof (as16_t) /* Maximum protocol segment length value */ #define AS_SEGMENT_MAX 255 /* The following length and size macros relate specifically to Quagga's * internal representation of AS-Segments, not per se to the on-wire * sizes and lengths. At present (200508) they sort of match, however * the ONLY functions which should now about the on-wire syntax are * aspath_put, assegment_put and assegment_parse. * * aspath_put returns bytes written, the only definitive record of * size of wire-format attribute.. */ /* Calculated size in bytes of ASN segment data to hold N ASN's */ #define ASSEGMENT_DATA_SIZE(N,S) \ ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) ) /* Calculated size of segment struct to hold N ASN's */ #define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S)) /* AS segment octet length. */ #define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S) /* AS_SEQUENCE segments can be packed together */ /* Can the types of X and Y be considered for packing? */ #define ASSEGMENT_TYPES_PACKABLE(X,Y) \ ( ((X)->type == (Y)->type) \ && ((X)->type == AS_SEQUENCE)) /* Types and length of X,Y suitable for packing? */ #define ASSEGMENTS_PACKABLE(X,Y) \ ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \ && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) ) /* As segment header - the on-wire representation * NOT the internal representation! */ struct assegment_header { u_char type; u_char length; }; /* Hash for aspath. This is the top level structure of AS path. */ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; /* Callers are required to initialize the memory */ static as_t * assegment_data_new (int num) { return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); } static void assegment_data_free (as_t *asdata) { XFREE (MTYPE_AS_SEG_DATA, asdata); } /* Get a new segment. Note that 0 is an allowed length, * and will result in a segment with no allocated data segment. * the caller should immediately assign data to the segment, as the segment * otherwise is not generally valid */ static struct assegment * assegment_new (u_char type, u_short length) { struct assegment *new; new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment)); if (length) new->as = assegment_data_new (length); new->length = length; new->type = type; return new; } static void assegment_free (struct assegment *seg) { if (!seg) return; if (seg->as) assegment_data_free (seg->as); memset (seg, 0xfe, sizeof(struct assegment)); XFREE (MTYPE_AS_SEG, seg); return; } /* free entire chain of segments */ static void assegment_free_all (struct assegment *seg) { struct assegment *prev; while (seg) { prev = seg; seg = seg->next; assegment_free (prev); } } /* Duplicate just the given assegment and its data */ static struct assegment * assegment_dup (struct assegment *seg) { struct assegment *new; new = assegment_new (seg->type, seg->length); memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) ); return new; } /* Duplicate entire chain of assegments, return the head */ static struct assegment * assegment_dup_all (struct assegment *seg) { struct assegment *new = NULL; struct assegment *head = NULL; while (seg) { if (head) { new->next = assegment_dup (seg); new = new->next; } else head = new = assegment_dup (seg); seg = seg->next; } return head; } /* prepend the as number to given segment, given num of times */ static struct assegment * assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) { as_t *newas; int i; if (!num) return seg; if (num >= AS_SEGMENT_MAX) return seg; /* we don't do huge prepends */ if ((newas = assegment_data_new (seg->length + num)) == NULL) return seg; for (i = 0; i < num; i++) newas[i] = asnum; memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); assegment_data_free (seg->as); seg->as = newas; seg->length += num; return seg; } /* append given array of as numbers to the segment */ static struct assegment * assegment_append_asns (struct assegment *seg, as_t *asnos, int num) { as_t *newas; newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as, ASSEGMENT_DATA_SIZE (seg->length + num, 1)); if (newas) { seg->as = newas; memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1)); seg->length += num; return seg; } assegment_free_all (seg); return NULL; } static int int_cmp (const void *p1, const void *p2) { const as_t *as1 = p1; const as_t *as2 = p2; return (*as1 == *as2) ? 0 : ( (*as1 > *as2) ? 1 : -1); } /* normalise the segment. * In particular, merge runs of AS_SEQUENCEs into one segment * Internally, we do not care about the wire segment length limit, and * we want each distinct AS_PATHs to have the exact same internal * representation - eg, so that our hashing actually works.. */ static struct assegment * assegment_normalise (struct assegment *head) { struct assegment *seg = head, *pin; struct assegment *tmp; if (!head) return head; while (seg) { pin = seg; /* Sort values SET segments, for determinism in paths to aid * creation of hash values / path comparisons * and because it helps other lesser implementations ;) */ if (seg->type == AS_SET || seg->type == AS_CONFED_SET) { int tail = 0; int i; qsort (seg->as, seg->length, sizeof(as_t), int_cmp); /* weed out dupes */ for (i=1; i < seg->length; i++) { if (seg->as[tail] == seg->as[i]) continue; tail++; if (tail < i) seg->as[tail] = seg->as[i]; } /* seg->length can be 0.. */ if (seg->length) seg->length = tail + 1; } /* read ahead from the current, pinned segment while the segments * are packable/mergeable. Append all following packable segments * to the segment we have pinned and remove these appended * segments. */ while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next)) { tmp = pin->next; seg = pin->next; /* append the next sequence to the pinned sequence */ pin = assegment_append_asns (pin, seg->as, seg->length); /* bypass the next sequence */ pin->next = seg->next; /* get rid of the now referenceless segment */ assegment_free (tmp); } seg = pin->next; } return head; } static struct aspath * aspath_new (void) { return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); } /* Free AS path structure. */ void aspath_free (struct aspath *aspath) { if (!aspath) return; if (aspath->segments) assegment_free_all (aspath->segments); 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; struct aspath *asp = *aspath; if (asp->refcnt) asp->refcnt--; if (asp->refcnt == 0) { /* This aspath must exist in aspath hash table. */ ret = hash_release (ashash, asp); assert (ret != NULL); aspath_free (asp); *aspath = NULL; } } /* 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_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 ' '; } /* countup asns from this segment and index onward */ static int assegment_count_asns (struct assegment *seg, int from) { int count = 0; while (seg) { if (!from) count += seg->length; else { count += (seg->length - from); from = 0; } seg = seg->next; } return count; } unsigned int aspath_count_confeds (struct aspath *aspath) { int count = 0; struct assegment *seg = aspath->segments; while (seg) { if (seg->type == AS_CONFED_SEQUENCE) count += seg->length; else if (seg->type == AS_CONFED_SET) count++; seg = seg->next; } return count; } unsigned int aspath_count_hops (const struct aspath *aspath) { int count = 0; struct assegment *seg = aspath->segments; while (seg) { if (seg->type == AS_SEQUENCE) count += seg->length; else if (seg->type == AS_SET) count++; seg = seg->next; } return count; } /* Estimate size aspath /might/ take if encoded into an * ASPATH attribute. * * This is a quick estimate, not definitive! aspath_put() * may return a different number!! */ unsigned int aspath_size (struct aspath *aspath) { int size = 0; struct assegment *seg = aspath->segments; while (seg) { size += ASSEGMENT_SIZE(seg->length, 1); seg = seg->next; } return size; } /* Return highest public ASN in path */ as_t aspath_highest (struct aspath *aspath) { struct assegment *seg = aspath->segments; as_t highest = 0; unsigned int i; while (seg) { for (i = 0; i < seg->length; i++) if (seg->as[i] > highest && !BGP_AS_IS_PRIVATE(seg->as[i])) highest = seg->as[i]; seg = seg->next; } return highest; } /* Return the left-most ASN in path */ as_t aspath_leftmost (struct aspath *aspath) { struct assegment *seg = aspath->segments; as_t leftmost = 0; if (seg && seg->length && seg->type == AS_SEQUENCE) leftmost = seg->as[0]; return leftmost; } /* Return 1 if there are any 4-byte ASes in the path */ unsigned int aspath_has_as4 (struct aspath *aspath) { struct assegment *seg = aspath->segments; unsigned int i; while (seg) { for (i = 0; i < seg->length; i++) if (seg->as[i] > BGP_AS_MAX) return 1; seg = seg->next; } return 0; } /* Convert aspath structure to string expression. */ static void aspath_make_str_count (struct aspath *as) { struct assegment *seg; int str_size; int len = 0; char *str_buf; /* Empty aspath. */ if (!as->segments) { as->str = XMALLOC (MTYPE_AS_STR, 1); as->str[0] = '\0'; as->str_len = 0; return; } seg = as->segments; /* ASN takes 5 to 10 chars plus seperator, see below. * If there is one differing segment type, we need an additional * 2 chars for segment delimiters, and the final '\0'. * Hopefully this is large enough to avoid hitting the realloc * code below for most common sequences. * * This was changed to 10 after the well-known BGP assertion, which * had hit some parts of the Internet in May of 2009. */ #define ASN_STR_LEN (10 + 1) str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1, ASPATH_STR_DEFAULT_LEN); str_buf = XMALLOC (MTYPE_AS_STR, str_size); while (seg) { int i; char seperator; /* Check AS type validity. Set seperator for segment */ switch (seg->type) { case AS_SET: case AS_CONFED_SET: seperator = ','; break; case AS_SEQUENCE: case AS_CONFED_SEQUENCE: seperator = ' '; break; default: XFREE (MTYPE_AS_STR, str_buf); as->str = NULL; as->str_len = 0; return; } /* We might need to increase str_buf, particularly if path has * differing segments types, our initial guesstimate above will * have been wrong. Need 10 chars for ASN, a seperator each and * potentially two segment delimiters, plus a space between each * segment and trailing zero. * * This definitely didn't work with the value of 5 bytes and * 32-bit ASNs. */ #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1) if ( (len + SEGMENT_STR_LEN(seg)) > str_size) { str_size = len + SEGMENT_STR_LEN(seg); str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size); } #undef ASN_STR_LEN #undef SEGMENT_STR_LEN if (seg->type != AS_SEQUENCE) len += snprintf (str_buf + len, str_size - len, "%c", aspath_delimiter_char (seg->type, AS_SEG_START)); /* write out the ASNs, with their seperators, bar the last one*/ for (i = 0; i < seg->length; i++) { len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]); if (i < (seg->length - 1)) len += snprintf (str_buf + len, str_size - len, "%c", seperator); } if (seg->type != AS_SEQUENCE) len += snprintf (str_buf + len, str_size - len, "%c", aspath_delimiter_char (seg->type, AS_SEG_END)); if (seg->next) len += snprintf (str_buf + len, str_size - len, " "); seg = seg->next; } assert (len < str_size); str_buf[len] = '\0'; as->str = str_buf; as->str_len = len; return; } static void aspath_str_update (struct aspath *as) { if (as->str) XFREE (MTYPE_AS_STR, as->str); aspath_make_str_count (as); } /* Intern allocated AS path. */ struct aspath * aspath_intern (struct aspath *aspath) { struct aspath *find; /* Assert this AS path structure is not interned and has the string representation built. */ assert (aspath->refcnt == 0); assert (aspath->str); /* Check AS path hash. */ find = hash_get (ashash, aspath, hash_alloc_intern); if (find != aspath) aspath_free (aspath); find->refcnt++; 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) { unsigned short buflen = aspath->str_len + 1; struct aspath *new; new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); if (aspath->segments) new->segments = assegment_dup_all (aspath->segments); if (!aspath->str) return new; new->str = XMALLOC (MTYPE_AS_STR, buflen); new->str_len = aspath->str_len; /* copy the string data */ if (aspath->str_len > 0) memcpy (new->str, aspath->str, buflen); else new->str[0] = '\0'; return new; } static void * aspath_hash_alloc (void *arg) { const struct aspath *aspath = arg; struct aspath *new; /* Malformed AS path value. */ assert (aspath->str); if (! aspath->str) return NULL; /* New aspath structure is needed. */ new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); /* Reuse segments and string representation */ new->refcnt = 0; new->segments = aspath->segments; new->str = aspath->str; new->str_len = aspath->str_len; return new; } /* parse as-segment byte stream in struct assegment */ static int assegments_parse (struct stream *s, size_t length, struct assegment **result, int use32bit) { struct assegment_header segh; struct assegment *seg, *prev = NULL, *head = NULL; size_t bytes = 0; /* empty aspath (ie iBGP or somesuch) */ if (length == 0) return 0; if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu", (unsigned long) length); /* basic checks */ if ((STREAM_READABLE(s) < length) || (STREAM_READABLE(s) < AS_HEADER_SIZE) || (length % AS16_VALUE_SIZE )) return -1; while (bytes < length) { int i; size_t seg_size; if ((length - bytes) <= AS_HEADER_SIZE) { if (head) assegment_free_all (head); return -1; } /* softly softly, get the header first on its own */ segh.type = stream_getc (s); segh.length = stream_getc (s); seg_size = ASSEGMENT_SIZE(segh.length, use32bit); if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d", segh.type, segh.length); /* check it.. */ if ( ((bytes + seg_size) > length) /* 1771bis 4.3b: seg length contains one or more */ || (segh.length == 0) /* Paranoia in case someone changes type of segment length. * Shift both values by 0x10 to make the comparison operate * on more, than 8 bits (otherwise it's a warning, bug #564). */ || ((sizeof segh.length > 1) && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX))) { if (head) assegment_free_all (head); return -1; } switch (segh.type) { case AS_SEQUENCE: case AS_SET: case AS_CONFED_SEQUENCE: case AS_CONFED_SET: break; default: if (head) assegment_free_all (head); return -1; } /* now its safe to trust lengths */ seg = assegment_new (segh.type, segh.length); if (head) prev->next = seg; else /* it's the first segment */ head = prev = seg; for (i = 0; i < segh.length; i++) seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s); bytes += seg_size; if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu", (unsigned long) bytes); prev = seg; } *result = assegment_normalise (head); return 0; } /* 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. On error NULL is returned. */ struct aspath * aspath_parse (struct stream *s, size_t length, int use32bit) { struct aspath as; struct aspath *find; /* If length is odd it's malformed AS path. */ /* Nit-picking: if (use32bit == 0) it is malformed if odd, * otherwise its malformed when length is larger than 2 and (length-2) * is not dividable by 4. * But... this time we're lazy */ if (length % AS16_VALUE_SIZE ) return NULL; memset (&as, 0, sizeof (struct aspath)); if (assegments_parse (s, length, &as.segments, use32bit) < 0) return NULL; /* If already same aspath exist then return it. */ find = hash_get (ashash, &as, aspath_hash_alloc); /* bug! should not happen, let the daemon crash below */ assert (find); /* if the aspath was already hashed free temporary memory. */ if (find->refcnt) { assegment_free_all (as.segments); /* aspath_key_make() always updates the string */ XFREE (MTYPE_AS_STR, as.str); } find->refcnt++; return find; } static void assegment_data_put (struct stream *s, as_t *as, int num, int use32bit) { int i; assert (num <= AS_SEGMENT_MAX); for (i = 0; i < num; i++) if ( use32bit ) stream_putl (s, as[i]); else { if ( as[i] <= BGP_AS_MAX ) stream_putw(s, as[i]); else stream_putw(s, BGP_AS_TRANS); } } static size_t assegment_header_put (struct stream *s, u_char type, int length) { size_t lenp; assert (length <= AS_SEGMENT_MAX); stream_putc (s, type); lenp = stream_get_endp (s); stream_putc (s, length); return lenp; } /* write aspath data to stream */ size_t aspath_put (struct stream *s, struct aspath *as, int use32bit ) { struct assegment *seg = as->segments; size_t bytes = 0; if (!seg || seg->length == 0) return 0; if (seg) { /* * Hey, what do we do when we have > STREAM_WRITABLE(s) here? * At the moment, we would write out a partial aspath, and our peer * will complain and drop the session :-/ * * The general assumption here is that many things tested will * never happen. And, in real live, up to now, they have not. */ while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s))) { struct assegment *next = seg->next; int written = 0; int asns_packed = 0; size_t lenp; /* Overlength segments have to be split up */ while ( (seg->length - written) > AS_SEGMENT_MAX) { assegment_header_put (s, seg->type, AS_SEGMENT_MAX); assegment_data_put (s, (seg->as+written), AS_SEGMENT_MAX, use32bit); written += AS_SEGMENT_MAX; bytes += ASSEGMENT_SIZE (AS_SEGMENT_MAX, use32bit); } /* write the final segment, probably is also the first */ lenp = assegment_header_put (s, seg->type, seg->length - written); assegment_data_put (s, (seg->as + written), seg->length - written, use32bit); /* Sequence-type segments can be 'packed' together * Case of a segment which was overlength and split up * will be missed here, but that doesn't matter. */ while (next && ASSEGMENTS_PACKABLE (seg, next)) { /* NB: We should never normally get here given we * normalise aspath data when parse them. However, better * safe than sorry. We potentially could call * assegment_normalise here instead, but it's cheaper and * easier to do it on the fly here rather than go through * the segment list twice every time we write out * aspath's. */ /* Next segment's data can fit in this one */ assegment_data_put (s, next->as, next->length, use32bit); /* update the length of the segment header */ stream_putc_at (s, lenp, seg->length - written + next->length); asns_packed += next->length; next = next->next; } bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed, use32bit); seg = next; } } return bytes; } /* This is for SNMP BGP4PATHATTRASPATHSEGMENT * We have no way to manage the storage, so we use a static stream * wrapper around aspath_put. */ u_char * aspath_snmp_pathseg (struct aspath *as, size_t *varlen) { #define SNMP_PATHSEG_MAX 1024 if (!snmp_stream) snmp_stream = stream_new (SNMP_PATHSEG_MAX); else stream_reset (snmp_stream); if (!as) { *varlen = 0; return NULL; } aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */ *varlen = stream_get_endp (snmp_stream); return stream_pnt(snmp_stream); } #define min(A,B) ((A) < (B) ? (A) : (B)) static 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) { asset = assegment_new (AS_SET, 1); if (! aspath->segments) aspath->segments = asset; else { struct assegment *seg = aspath->segments; while (seg->next) seg = seg->next; seg->next = asset; } asset->type = AS_SET; asset->length = 1; asset->as[0] = as; } else { /* Check this AS value already exists or not. */ for (i = 0; i < asset->length; i++) if (asset->as[i] == as) return asset; asset->length++; asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as, asset->length * AS_VALUE_SIZE); asset->as[asset->length - 1] = as; } 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 from; struct assegment *seg1 = as1->segments; struct assegment *seg2 = as2->segments; struct aspath *aspath = NULL; struct assegment *asset; struct assegment *prevseg = NULL; match = 0; minlen = 0; aspath = NULL; asset = NULL; /* First of all check common leading sequence. */ while (seg1 && seg2) { /* 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->as[match] != seg2->as[match]) break; if (match) { struct assegment *seg = assegment_new (seg1->type, 0); seg = assegment_append_asns (seg, seg1->as, match); if (! aspath) { aspath = aspath_new (); aspath->segments = seg; } else prevseg->next = seg; prevseg = seg; } if (match != minlen || match != seg1->length || seg1->length != seg2->length) break; /* We are moving on to the next segment to reset match */ else match = 0; seg1 = seg1->next; seg2 = seg2->next; } if (! aspath) aspath = aspath_new(); /* Make as-set using rest of all information. */ from = match; while (seg1) { for (i = from; i < seg1->length; i++) asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]); from = 0; seg1 = seg1->next; } from = match; while (seg2) { for (i = from; i < seg2->length; i++) asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]); from = 0; seg2 = seg2->next; } assegment_normalise (aspath->segments); aspath_str_update (aspath); return aspath; } /* Modify as1 using as2 for aggregation for multipath, keeping the * AS-Path length the same, and so minimising change to the preference * of the mpath aggregrate route. */ struct aspath * aspath_aggregate_mpath (struct aspath *as1, struct aspath *as2) { int i; int minlen; int match; int from1,from2; struct assegment *seg1 = as1->segments; struct assegment *seg2 = as2->segments; struct aspath *aspath = NULL; struct assegment *asset; struct assegment *prevseg = NULL; match = 0; minlen = 0; aspath = NULL; asset = NULL; /* First of all check common leading sequence. */ while (seg1 && seg2) { /* 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->as[match] != seg2->as[match]) break; if (match) { struct assegment *seg = assegment_new (seg1->type, 0); seg = assegment_append_asns (seg, seg1->as, match); if (! aspath) { aspath = aspath_new (); aspath->segments = seg; } else prevseg->next = seg; prevseg = seg; } if (match != minlen || match != seg1->length || seg1->length != seg2->length) break; seg1 = seg1->next; seg2 = seg2->next; } if (! aspath) aspath = aspath_new(); /* Make as-set using rest of all information. */ from1 = from2 = match; while (seg1 || seg2) { if (seg1) { if (seg1->type == AS_SEQUENCE) { asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[from1]); from1++; if (from1 >= seg1->length) { from1 = 0; seg1 = seg1->next; } } else { for (i = from1; i < seg1->length; i++) asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]); from1 = 0; seg1 = seg1->next; } } if (seg2) { if (seg2->type == AS_SEQUENCE) { asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[from2]); from2++; if (from2 >= seg2->length) { from2 = 0; seg2 = seg2->next; } } else { for (i = from2; i < seg2->length; i++) asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]); from2 = 0; seg2 = seg2->next; } } if (asset->length == 1) asset->type = AS_SEQUENCE; asset = NULL; } assegment_normalise (aspath->segments); aspath_str_update (aspath); 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) { if ( (aspath == NULL) || (aspath->segments == NULL) ) return 0; if (aspath->segments && (aspath->segments->type == AS_SEQUENCE) && (aspath->segments->as[0] == 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) { struct assegment *seg; int count = 0; if ( (aspath == NULL) || (aspath->segments == NULL) ) return 0; seg = aspath->segments; while (seg) { int i; for (i = 0; i < seg->length; i++) if (seg->as[i] == asno) count++; seg = seg->next; } return count; } /* When all of AS path is private AS return 1. */ int aspath_private_as_check (struct aspath *aspath) { struct assegment *seg; if ( !(aspath && aspath->segments) ) return 0; seg = aspath->segments; while (seg) { int i; for (i = 0; i < seg->length; i++) { if (!BGP_AS_IS_PRIVATE(seg->as[i])) return 0; } seg = seg->next; } return 1; } /* AS path confed check. If aspath contains confed set or sequence then return 1. */ int aspath_confed_check (struct aspath *aspath) { struct assegment *seg; if ( !(aspath && aspath->segments) ) return 0; seg = aspath->segments; while (seg) { if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE) return 1; seg = seg->next; } return 0; } /* Leftmost AS path segment confed check. If leftmost AS segment is of type AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */ int aspath_left_confed_check (struct aspath *aspath) { if ( !(aspath && aspath->segments) ) return 0; if ( (aspath->segments->type == AS_CONFED_SEQUENCE) || (aspath->segments->type == AS_CONFED_SET) ) return 1; return 0; } /* Merge as1 to as2. as2 should be uninterned aspath. */ static struct aspath * aspath_merge (struct aspath *as1, struct aspath *as2) { struct assegment *last, *new; if (! as1 || ! as2) return NULL; last = new = assegment_dup_all (as1->segments); /* find the last valid segment */ while (last && last->next) last = last->next; last->next = as2->segments; as2->segments = new; aspath_str_update (as2); return as2; } /* Prepend as1 to as2. as2 should be uninterned aspath. */ struct aspath * aspath_prepend (struct aspath *as1, struct aspath *as2) { struct assegment *seg1; struct assegment *seg2; if (! as1 || ! as2) return NULL; seg1 = as1->segments; seg2 = as2->segments; /* If as2 is empty, only need to dupe as1's chain onto as2 */ if (seg2 == NULL) { as2->segments = assegment_dup_all (as1->segments); aspath_str_update (as2); return as2; } /* If as1 is empty AS, no prepending to do. */ if (seg1 == NULL) return as2; /* find the tail as1's segment chain. */ while (seg1 && seg1->next) seg1 = seg1->next; /* Delete any AS_CONFED_SEQUENCE segment from as2. */ if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) as2 = aspath_delete_confed_seq (as2); /* as2 may have been updated */ seg2 = as2->segments; /* as2 may be empty now due to aspath_delete_confed_seq, recheck */ if (seg2 == NULL) { as2->segments = assegment_dup_all (as1->segments); aspath_str_update (as2); 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) { /* We have two chains of segments, as1->segments and seg2, * and we have to attach them together, merging the attaching * segments together into one. * * 1. dupe as1->segments onto head of as2 * 2. merge seg2's asns onto last segment of this new chain * 3. attach chain after seg2 */ /* dupe as1 onto as2's head */ seg1 = as2->segments = assegment_dup_all (as1->segments); /* refind the tail of as2, reusing seg1 */ while (seg1 && seg1->next) seg1 = seg1->next; /* merge the old head, seg2, into tail, seg1 */ seg1 = assegment_append_asns (seg1, seg2->as, seg2->length); /* bypass the merged seg2, and attach any chain after it to * chain descending from as2's head */ seg1->next = seg2->next; /* seg2 is now referenceless and useless*/ assegment_free (seg2); /* we've now prepended as1's segment chain to as2, merging * the inbetween AS_SEQUENCE of seg2 in the process */ aspath_str_update (as2); return as2; } else { /* AS_SET merge code is needed at here. */ return aspath_merge (as1, as2); } /* XXX: Ermmm, what if as1 has multiple segments?? */ /* Not reached */ } /* Iterate over AS_PATH segments and wipe all occurences of the * listed AS numbers. Hence some segments may lose some or even * all data on the way, the operation is implemented as a smarter * version of aspath_dup(), which allocates memory to hold the new * data, not the original. The new AS path is returned. */ struct aspath * aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list) { struct assegment * srcseg, * exclseg, * lastseg; struct aspath * newpath; newpath = aspath_new(); lastseg = NULL; for (srcseg = source->segments; srcseg; srcseg = srcseg->next) { unsigned i, y, newlen = 0, done = 0, skip_as; struct assegment * newseg; /* Find out, how much ASns are we going to pick from this segment. * We can't perform filtering right inline, because the size of * the new segment isn't known at the moment yet. */ for (i = 0; i < srcseg->length; i++) { skip_as = 0; for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next) for (y = 0; y < exclseg->length; y++) if (srcseg->as[i] == exclseg->as[y]) { skip_as = 1; // There's no sense in testing the rest of exclusion list, bail out. break; } if (!skip_as) newlen++; } /* newlen is now the number of ASns to copy */ if (!newlen) continue; /* Actual copying. Allocate memory and iterate once more, performing filtering. */ newseg = assegment_new (srcseg->type, newlen); for (i = 0; i < srcseg->length; i++) { skip_as = 0; for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next) for (y = 0; y < exclseg->length; y++) if (srcseg->as[i] == exclseg->as[y]) { skip_as = 1; break; } if (skip_as) continue; newseg->as[done++] = srcseg->as[i]; } /* At his point newlen must be equal to done, and both must be positive. Append * the filtered segment to the gross result. */ if (!lastseg) newpath->segments = newseg; else lastseg->next = newseg; lastseg = newseg; } aspath_str_update (newpath); /* We are happy returning even an empty AS_PATH, because the administrator * might expect this very behaviour. There's a mean to avoid this, if necessary, * by having a match rule against certain AS_PATH regexps in the route-map index. */ aspath_free (source); return newpath; } /* Add specified AS to the leftmost of aspath. */ static struct aspath * aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num) { struct assegment *assegment = aspath->segments; unsigned i; if (assegment && assegment->type == type) { /* extend existing segment */ aspath->segments = assegment_prepend_asns (aspath->segments, asno, num); } else { /* prepend with new segment */ struct assegment *newsegment = assegment_new (type, num); for (i = 0; i < num; i++) newsegment->as[i] = asno; /* insert potentially replacing empty segment */ if (assegment && assegment->length == 0) { newsegment->next = assegment->next; assegment_free (assegment); } else newsegment->next = assegment; aspath->segments = newsegment; } aspath_str_update (aspath); return aspath; } /* Add specified AS to the leftmost of aspath num times. */ struct aspath * aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num) { return aspath_add_asns (aspath, asno, AS_SEQUENCE, num); } /* Add specified AS to the leftmost of aspath. */ struct aspath * aspath_add_seq (struct aspath *aspath, as_t asno) { return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1); } /* 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 (const struct aspath *aspath1, const struct aspath *aspath2) { const struct assegment *seg1; const struct assegment *seg2; if (!(aspath1 && aspath2)) return 0; seg1 = aspath1->segments; seg2 = aspath2->segments; /* If both paths are originated in this AS then we do want to compare MED */ if (!seg1 && !seg2) return 1; /* find first non-confed segments for each */ while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE) || (seg1->type == AS_CONFED_SET))) seg1 = seg1->next; while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE) || (seg2->type == AS_CONFED_SET))) seg2 = seg2->next; /* Check as1's */ if (!(seg1 && seg2 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE))) return 0; if (seg1->as[0] == seg2->as[0]) return 1; return 0; } /* Truncate an aspath after a number of hops, and put the hops remaining * at the front of another aspath. Needed for AS4 compat. * * Returned aspath is a /new/ aspath, which should either by free'd or * interned by the caller, as desired. */ struct aspath * aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) { struct assegment *seg, *newseg, *prevseg = NULL; struct aspath *newpath = NULL, *mergedpath; int hops, cpasns = 0; if (!aspath) return NULL; seg = aspath->segments; /* CONFEDs should get reconciled too.. */ hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath)) - aspath_count_hops (as4path); if (hops < 0) { if (BGP_DEBUG (as4, AS4)) zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH"); /* Something's gone wrong. The RFC says we should now ignore AS4_PATH, * which is daft behaviour - it contains vital loop-detection * information which must have been removed from AS_PATH. */ hops = aspath_count_hops (aspath); } if (!hops) return aspath_dup (as4path); if ( BGP_DEBUG(as4, AS4)) zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now", aspath->str, as4path->str); while (seg && hops > 0) { switch (seg->type) { case AS_SET: case AS_CONFED_SET: hops--; cpasns = seg->length; break; case AS_CONFED_SEQUENCE: /* Should never split a confed-sequence, if hop-count * suggests we must then something's gone wrong somewhere. * * Most important goal is to preserve AS_PATHs prime function * as loop-detector, so we fudge the numbers so that the entire * confed-sequence is merged in. */ if (hops < seg->length) { if (BGP_DEBUG (as4, AS4)) zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls" " across 2/4 ASN boundary somewhere, broken.."); hops = seg->length; } case AS_SEQUENCE: cpasns = MIN(seg->length, hops); hops -= seg->length; } assert (cpasns <= seg->length); newseg = assegment_new (seg->type, 0); newseg = assegment_append_asns (newseg, seg->as, cpasns); if (!newpath) { newpath = aspath_new (); newpath->segments = newseg; } else prevseg->next = newseg; prevseg = newseg; seg = seg->next; } /* We may be able to join some segments here, and we must * do this because... we want normalised aspaths in out hash * and we do not want to stumble in aspath_put. */ mergedpath = aspath_merge (newpath, aspath_dup(as4path)); aspath_free (newpath); mergedpath->segments = assegment_normalise (mergedpath->segments); aspath_str_update (mergedpath); if ( BGP_DEBUG(as4, AS4)) zlog_debug ("[AS4] result of synthesizing is %s", mergedpath->str); return mergedpath; } /* 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 (const struct aspath *aspath1, const struct aspath *aspath2) { if (! (aspath1 && aspath2) ) return 0; if ( !(aspath1->segments && aspath2->segments) ) return 0; if ( (aspath1->segments->type != AS_CONFED_SEQUENCE) || (aspath2->segments->type != AS_CONFED_SEQUENCE) ) return 0; if (aspath1->segments->as[0] == aspath2->segments->as[0]) return 1; return 0; } /* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath. * See RFC3065, 6.1 c1 */ struct aspath * aspath_delete_confed_seq (struct aspath *aspath) { struct assegment *seg; if (!(aspath && aspath->segments)) return aspath; seg = aspath->segments; /* "if the first path segment of the AS_PATH is * of type AS_CONFED_SEQUENCE," */ if (aspath->segments->type != AS_CONFED_SEQUENCE) return aspath; /* "... that segment and any immediately following segments * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed * from the AS_PATH attribute," */ while (seg && (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET)) { aspath->segments = seg->next; assegment_free (seg); seg = aspath->segments; } aspath_str_update (aspath); 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_asns (aspath, asno, AS_CONFED_SEQUENCE, 1); } /* Add new as value to as path structure. */ static void aspath_as_add (struct aspath *as, as_t asno) { struct assegment *seg = as->segments; if (!seg) return; /* Last segment search procedure. */ while (seg->next) seg = seg->next; assegment_append_asns (seg, &asno, 1); } /* Add new as segment to the as path. */ static void aspath_segment_add (struct aspath *as, int type) { struct assegment *seg = as->segments; struct assegment *new = assegment_new (type, 0); if (seg) { while (seg->next) seg = seg->next; seg->next = new; } else as->segments = new; } struct aspath * aspath_empty (void) { return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */ } struct aspath * aspath_empty_get (void) { struct aspath *aspath; aspath = aspath_new (); aspath_make_str_count (aspath); return aspath; } unsigned long aspath_count (void) { 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_seq_start, as_token_confed_seq_end, as_token_confed_set_start, as_token_confed_set_end, as_token_unknown }; /* Return next token and point for string parse. */ static const char * aspath_gettoken (const char *buf, enum as_token *token, u_long *asno) { const char *p = buf; /* Skip seperators (space for sequences, ',' for sets). */ while (isspace ((int) *p) || *p == ',') p++; /* Check the end of the string and type specify characters (e.g. {}()). */ switch (*p) { case '\0': return NULL; case '{': *token = as_token_set_start; p++; return p; case '}': *token = as_token_set_end; p++; return p; case '(': *token = as_token_confed_seq_start; p++; return p; case ')': *token = as_token_confed_seq_end; p++; return p; case '[': *token = as_token_confed_set_start; p++; return p; case ']': *token = as_token_confed_set_end; p++; return p; } /* Check actual AS value. */ if (isdigit ((int) *p)) { as_t 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 (const char *str) { enum as_token token = as_token_unknown; u_short as_type; u_long asno = 0; 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_seq_start: as_type = AS_CONFED_SEQUENCE; aspath_segment_add (aspath, as_type); needtype = 0; break; case as_token_confed_seq_end: as_type = AS_SEQUENCE; needtype = 1; break; case as_token_confed_set_start: as_type = AS_CONFED_SET; aspath_segment_add (aspath, as_type); needtype = 0; break; case as_token_confed_set_end: as_type = AS_SEQUENCE; needtype = 1; break; case as_token_unknown: default: aspath_free (aspath); return NULL; } } aspath_make_str_count (aspath); return aspath; } /* Make hash value by raw aspath data. */ unsigned int aspath_key_make (void *p) { struct aspath *aspath = (struct aspath *) p; unsigned int key = 0; if (!aspath->str) aspath_str_update (aspath); key = jhash (aspath->str, aspath->str_len, 2334325); return key; } /* If two aspath have same value then return 1 else return 0 */ int aspath_cmp (const void *arg1, const void *arg2) { const struct assegment *seg1 = ((const struct aspath *)arg1)->segments; const struct assegment *seg2 = ((const struct aspath *)arg2)->segments; while (seg1 || seg2) { int i; if ((!seg1 && seg2) || (seg1 && !seg2)) return 0; if (seg1->type != seg2->type) return 0; if (seg1->length != seg2->length) return 0; for (i = 0; i < seg1->length; i++) if (seg1->as[i] != seg2->as[i]) return 0; seg1 = seg1->next; seg2 = seg2->next; } return 1; } /* AS path hash initialize. */ void aspath_init (void) { ashash = hash_create_size (32768, aspath_key_make, aspath_cmp); } void aspath_finish (void) { hash_clean (ashash, (void (*)(void *))aspath_free); hash_free (ashash); ashash = NULL; if (snmp_stream) stream_free (snmp_stream); } /* return and as path value */ const char * aspath_print (struct aspath *as) { return (as ? as->str : NULL); } /* Printing functions */ /* Feed the AS_PATH to the vty; the suffix string follows it only in case * AS_PATH wasn't empty. */ void aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix) { assert (format); vty_out (vty, format, as->str); if (as->str_len && strlen (suffix)) vty_out (vty, "%s", suffix); } static void aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty) { struct aspath *as; as = (struct aspath *) backet->data; vty_out (vty, "[%p:%u] (%ld) ", (void *)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); } quagga-1.2.4/bgpd/bgp_aspath.h000066400000000000000000000111231325323223500161560ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_ASPATH_H #define _QUAGGA_BGP_ASPATH_H /* 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 64512U #define BGP_PRIVATE_AS_MAX 65535U /* Private 4 byte AS range defined in RFC6996. */ #define BGP_PRIVATE_AS4_MIN 4200000000U #define BGP_PRIVATE_AS4_MAX 4294967294U /* we leave BGP_AS_MAX as the 16bit AS MAX number. */ #define BGP_AS_MAX 65535U #define BGP_AS4_MAX 4294967295U /* Transition 16Bit AS as defined by IANA */ #define BGP_AS_TRANS 23456U #define BGP_AS_IS_PRIVATE(ASN) \ (((ASN) >= BGP_PRIVATE_AS_MIN && (ASN) <= BGP_PRIVATE_AS_MAX) || \ ((ASN) >= BGP_PRIVATE_AS4_MIN && (ASN) <= BGP_PRIVATE_AS4_MAX)) /* AS_PATH segment data in abstracted form, no limit is placed on length */ struct assegment { struct assegment *next; as_t *as; u_short length; u_char type; }; /* AS path may be include some AsSegments. */ struct aspath { /* Reference count to this aspath. */ unsigned long refcnt; /* segment data */ struct assegment *segments; /* String expression of AS path. This string is used by vty output and AS path regular expression match. */ char *str; unsigned short str_len; }; #define ASPATH_STR_DEFAULT_LEN 32 /* Prototypes. */ extern void aspath_init (void); extern void aspath_finish (void); extern struct aspath *aspath_parse (struct stream *, size_t, int); extern struct aspath *aspath_dup (struct aspath *); extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *); extern struct aspath *aspath_aggregate_mpath (struct aspath *, struct aspath *); extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); extern struct aspath *aspath_filter_exclude (struct aspath *, struct aspath *); extern struct aspath *aspath_add_seq_n (struct aspath *, as_t, unsigned); extern struct aspath *aspath_add_seq (struct aspath *, as_t); extern struct aspath *aspath_add_confed_seq (struct aspath *, as_t); extern int aspath_cmp (const void *, const void *); extern int aspath_cmp_left (const struct aspath *, const struct aspath *); extern int aspath_cmp_left_confed (const struct aspath *, const struct aspath *); extern struct aspath *aspath_delete_confed_seq (struct aspath *); extern struct aspath *aspath_empty (void); extern struct aspath *aspath_empty_get (void); extern struct aspath *aspath_str2aspath (const char *); extern void aspath_free (struct aspath *); extern struct aspath *aspath_intern (struct aspath *); extern void aspath_unintern (struct aspath **); extern const char *aspath_print (struct aspath *); extern void aspath_print_vty (struct vty *, const char *, struct aspath *, const char *); extern void aspath_print_all_vty (struct vty *); extern unsigned int aspath_key_make (void *); extern int aspath_loop_check (struct aspath *, as_t); extern int aspath_private_as_check (struct aspath *); extern int aspath_firstas_check (struct aspath *, as_t); extern int aspath_confed_check (struct aspath *); extern int aspath_left_confed_check (struct aspath *); extern unsigned long aspath_count (void); extern unsigned int aspath_count_hops (const struct aspath *); extern unsigned int aspath_count_confeds (struct aspath *); extern unsigned int aspath_size (struct aspath *); extern as_t aspath_highest (struct aspath *); extern as_t aspath_leftmost (struct aspath *); extern size_t aspath_put (struct stream *, struct aspath *, int); extern struct aspath *aspath_reconcile_as4 (struct aspath *, struct aspath *); extern unsigned int aspath_has_as4 (struct aspath *); /* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */ extern u_char *aspath_snmp_pathseg (struct aspath *, size_t *); #endif /* _QUAGGA_BGP_ASPATH_H */ quagga-1.2.4/bgpd/bgp_attr.c000066400000000000000000002707171325323223500156630ustar00rootroot00000000000000/* 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 "jhash.h" #include "filter.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" #include "bgpd/bgp_lcommunity.h" #include "table.h" #include "bgp_encap_types.h" /* Attribute strings for logging. */ static const 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, "CLUSTER_LIST" }, { 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" }, { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" }, { BGP_ATTR_AS4_PATH, "AS4_PATH" }, { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, { BGP_ATTR_ENCAP, "ENCAP" }, { 21, ""}, { 22, ""}, { 23, ""}, { 24, ""}, { 25, ""}, { 26, ""}, { 27, ""}, { 28, ""}, { 29, ""}, { 30, ""}, { 31, ""}, { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" } }; static const int attr_str_max = array_size(attr_str); static const struct message attr_flag_str[] = { { BGP_ATTR_FLAG_OPTIONAL, "Optional" }, { BGP_ATTR_FLAG_TRANS, "Transitive" }, { BGP_ATTR_FLAG_PARTIAL, "Partial" }, /* bgp_attr_flags_diagnose() relies on this bit being last in this list */ { BGP_ATTR_FLAG_EXTLEN, "Extended Length" }, }; static struct hash *cluster_hash; static void * cluster_hash_alloc (void *p) { struct cluster_list * val = (struct cluster_list *) p; 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. */ static struct cluster_list * cluster_parse (struct in_addr * pnt, int length) { struct cluster_list tmp; struct cluster_list *cluster; tmp.length = length; tmp.list = 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; } static unsigned int cluster_hash_key_make (void *p) { const struct cluster_list *cluster = p; return jhash(cluster->list, cluster->length, 0); } static int cluster_hash_cmp (const void *p1, const void *p2) { const struct cluster_list * cluster1 = p1; const struct cluster_list * cluster2 = p2; return (cluster1->length == cluster2->length && memcmp (cluster1->list, cluster2->list, cluster1->length) == 0); } static void cluster_free (struct cluster_list *cluster) { if (cluster->list) XFREE (MTYPE_CLUSTER_VAL, cluster->list); XFREE (MTYPE_CLUSTER, cluster); } #if 0 static struct cluster_list * cluster_dup (struct cluster_list *cluster) { struct cluster_list *new; new = XCALLOC (MTYPE_CLUSTER, 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; } #endif static 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 *c = *cluster; if (c->refcnt) c->refcnt--; if (c->refcnt == 0) { hash_release (cluster_hash, c); cluster_free (c); *cluster = NULL; } } static void cluster_init (void) { cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp); } static void cluster_finish (void) { hash_clean (cluster_hash, (void (*)(void *))cluster_free); hash_free (cluster_hash); cluster_hash = NULL; } struct bgp_attr_encap_subtlv * encap_tlv_dup(struct bgp_attr_encap_subtlv *orig) { struct bgp_attr_encap_subtlv *new; struct bgp_attr_encap_subtlv *tail; struct bgp_attr_encap_subtlv *p; for (p = orig, tail = new = NULL; p; p = p->next) { int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length; if (tail) { tail->next = XCALLOC(MTYPE_ENCAP_TLV, size); tail = tail->next; } else { tail = new = XCALLOC(MTYPE_ENCAP_TLV, size); } assert(tail); memcpy(tail, p, size); tail->next = NULL; } return new; } static void encap_free(struct bgp_attr_encap_subtlv *p) { struct bgp_attr_encap_subtlv *next; while (p) { next = p->next; p->next = NULL; XFREE(MTYPE_ENCAP_TLV, p); p = next; } } void bgp_attr_flush_encap(struct attr *attr) { if (!attr || !attr->extra) return; if (attr->extra->encap_subtlvs) { encap_free(attr->extra->encap_subtlvs); attr->extra->encap_subtlvs = NULL; } } /* * Compare encap sub-tlv chains * * 1 = equivalent * 0 = not equivalent * * This algorithm could be made faster if needed */ static int encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2) { struct bgp_attr_encap_subtlv *p; struct bgp_attr_encap_subtlv *q; if (!h1 && !h2) return 1; if (h1 && !h2) return 0; if (!h1 && h2) return 0; if (h1 == h2) return 1; for (p = h1; p; p = p->next) { for (q = h2; q; q = q->next) { if ((p->type == q->type) && (p->length == q->length) && !memcmp(p->value, q->value, p->length)) { break; } } if (!q) return 0; } for (p = h2; p; p = p->next) { for (q = h1; q; q = q->next) { if ((p->type == q->type) && (p->length == q->length) && !memcmp(p->value, q->value, p->length)) { break; } } if (!q) return 0; } return 1; } /* Unknown transit attribute. */ static struct hash *transit_hash; static void transit_free (struct transit *transit) { if (transit->val) XFREE (MTYPE_TRANSIT_VAL, transit->val); XFREE (MTYPE_TRANSIT, transit); } static void * transit_hash_alloc (void *p) { /* Transit structure is already allocated. */ return p; } static 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 *t = *transit; if (t->refcnt) t->refcnt--; if (t->refcnt == 0) { hash_release (transit_hash, t); transit_free (t); *transit = NULL; } } static unsigned int transit_hash_key_make (void *p) { const struct transit * transit = p; return jhash(transit->val, transit->length, 0); } static int transit_hash_cmp (const void *p1, const void *p2) { const struct transit * transit1 = p1; const struct transit * transit2 = p2; return (transit1->length == transit2->length && memcmp (transit1->val, transit2->val, transit1->length) == 0); } static void transit_init (void) { transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp); } static void transit_finish (void) { hash_clean (transit_hash, (void (*)(void *))transit_free); hash_free (transit_hash); transit_hash = NULL; } /* Attribute hash routines. */ static struct hash *attrhash; static struct attr_extra * bgp_attr_extra_new (void) { return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra)); } void bgp_attr_extra_free (struct attr *attr) { if (attr->extra) { if (attr->extra->encap_subtlvs) { encap_free(attr->extra->encap_subtlvs); attr->extra->encap_subtlvs = NULL; } XFREE (MTYPE_ATTR_EXTRA, attr->extra); attr->extra = NULL; } } struct attr_extra * bgp_attr_extra_get (struct attr *attr) { if (!attr->extra) attr->extra = bgp_attr_extra_new(); return attr->extra; } /* Shallow copy of an attribute * Though, not so shallow that it doesn't copy the contents * of the attr_extra pointed to by 'extra' */ void bgp_attr_dup (struct attr *new, struct attr *orig) { struct attr_extra *extra = new->extra; *new = *orig; /* if caller provided attr_extra space, use it in any case. * * This is neccesary even if orig->extra equals NULL, because otherwise * memory may be later allocated on the heap by bgp_attr_extra_get. * * That memory would eventually be leaked, because the caller must not * call bgp_attr_extra_free if he provided attr_extra on the stack. */ if (extra) { new->extra = extra; memset(new->extra, 0, sizeof(struct attr_extra)); if (orig->extra) { *new->extra = *orig->extra; if (orig->extra->encap_subtlvs) { new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); } } } else if (orig->extra) { new->extra = bgp_attr_extra_new(); *new->extra = *orig->extra; if (orig->extra->encap_subtlvs) { new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); } } } unsigned long int attr_count (void) { return attrhash->count; } unsigned long int attr_unknown_count (void) { return transit_hash->count; } unsigned int attrhash_key_make (void *p) { const struct attr *attr = (struct attr *) p; const struct attr_extra *extra = attr->extra; uint32_t key = 0; #define MIX(val) key = jhash_1word(val, key) MIX(attr->origin); MIX(attr->nexthop.s_addr); MIX(attr->med); MIX(attr->local_pref); key += attr->origin; key += attr->nexthop.s_addr; key += attr->med; key += attr->local_pref; if (extra) { MIX(extra->aggregator_as); MIX(extra->aggregator_addr.s_addr); MIX(extra->weight); MIX(extra->mp_nexthop_global_in.s_addr); MIX(extra->originator_id.s_addr); MIX(extra->tag); } if (attr->aspath) MIX(aspath_key_make (attr->aspath)); if (attr->community) MIX(community_hash_make (attr->community)); if (extra) { if (extra->lcommunity) MIX(lcommunity_hash_make (extra->lcommunity)); if (extra->ecommunity) MIX(ecommunity_hash_make (extra->ecommunity)); if (extra->cluster) MIX(cluster_hash_key_make (extra->cluster)); if (extra->transit) MIX(transit_hash_key_make (extra->transit)); MIX(extra->mp_nexthop_len); key = jhash(extra->mp_nexthop_global.s6_addr, 16, key); key = jhash(extra->mp_nexthop_local.s6_addr, 16, key); } return key; } int attrhash_cmp (const void *p1, const void *p2) { const struct attr * attr1 = p1; const struct attr * attr2 = p2; if (attr1->flag == attr2->flag && attr1->origin == attr2->origin && attr1->nexthop.s_addr == attr2->nexthop.s_addr && attr1->aspath == attr2->aspath && attr1->community == attr2->community && attr1->med == attr2->med && attr1->local_pref == attr2->local_pref) { const struct attr_extra *ae1 = attr1->extra; const struct attr_extra *ae2 = attr2->extra; if (ae1 && ae2 && ae1->aggregator_as == ae2->aggregator_as && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr && ae1->weight == ae2->weight && ae1->tag == ae2->tag && ae1->mp_nexthop_len == ae2->mp_nexthop_len && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) && ae1->ecommunity == ae2->ecommunity && ae1->lcommunity == ae2->lcommunity && ae1->cluster == ae2->cluster && ae1->transit == ae2->transit && (ae1->encap_tunneltype == ae2->encap_tunneltype) && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs) && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)) return 1; else if (ae1 || ae2) return 0; /* neither attribute has extra attributes, so they're same */ return 1; } else return 0; } static void attrhash_init (void) { attrhash = hash_create (attrhash_key_make, attrhash_cmp); } /* * special for hash_clean below */ static void attr_vfree (void *attr) { bgp_attr_extra_free ((struct attr *)attr); XFREE (MTYPE_ATTR, attr); } static void attrhash_finish (void) { hash_clean(attrhash, attr_vfree); hash_free (attrhash); attrhash = NULL; } static 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); } static void * bgp_attr_hash_alloc (void *p) { struct attr * val = (struct attr *) p; struct attr *attr; attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr)); *attr = *val; if (val->extra) { attr->extra = bgp_attr_extra_new (); *attr->extra = *val->extra; if (attr->extra->encap_subtlvs) { attr->extra->encap_subtlvs = encap_tlv_dup(attr->extra->encap_subtlvs); } } 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->extra) { struct attr_extra *attre = attr->extra; if (attre->ecommunity) { if (! attre->ecommunity->refcnt) attre->ecommunity = ecommunity_intern (attre->ecommunity); else attre->ecommunity->refcnt++; } if (attre->lcommunity) { if (! attre->lcommunity->refcnt) attre->lcommunity = lcommunity_intern (attre->lcommunity); else attre->lcommunity->refcnt++; } if (attre->cluster) { if (! attre->cluster->refcnt) attre->cluster = cluster_intern (attre->cluster); else attre->cluster->refcnt++; } if (attre->transit) { if (! attre->transit->refcnt) attre->transit = transit_intern (attre->transit); else attre->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)); bgp_attr_extra_get (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->extra->weight = BGP_ATTR_DEFAULT_WEIGHT; attr->extra->tag = 0; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN; 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)); bgp_attr_extra_get (&attr); bgp_attr_default_set(&attr, origin); new = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); aspath_unintern (&new->aspath); return new; } /* Create the attributes for an aggregate */ struct attr * bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, struct aspath *aspath, struct community *community, int as_set, u_char atomic_aggregate) { struct attr attr; struct attr *new; struct attr_extra attre; memset (&attr, 0, sizeof (struct attr)); memset (&attre, 0, sizeof (struct attr_extra)); attr.extra = &attre; /* 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); } attre.weight = BGP_ATTR_DEFAULT_WEIGHT; attre.mp_nexthop_len = IPV6_MAX_BYTELEN; if (! as_set || atomic_aggregate) 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)) attre.aggregator_as = bgp->confed_id; else attre.aggregator_as = bgp->as; attre.aggregator_addr = bgp->router_id; new = bgp_attr_intern (&attr); aspath_unintern (&new->aspath); return new; } /* Unintern just the sub-components of the attr, but not the attr */ void bgp_attr_unintern_sub (struct attr *attr) { /* aspath refcount shoud be decrement. */ if (attr->aspath) aspath_unintern (&attr->aspath); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)); if (attr->community) community_unintern (&attr->community); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); if (attr->extra) { if (attr->extra->ecommunity) ecommunity_unintern (&attr->extra->ecommunity); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); if (attr->extra->lcommunity) lcommunity_unintern (&attr->extra->lcommunity); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); if (attr->extra->cluster) cluster_unintern (&attr->extra->cluster); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)); if (attr->extra->transit) transit_unintern (&attr->extra->transit); } } /* Free bgp attribute and aspath. */ void bgp_attr_unintern (struct attr **pattr) { struct attr *attr = *pattr; struct attr *ret; struct attr tmp; struct attr_extra tmp_extra; /* Decrement attribute reference. */ attr->refcnt--; tmp = *attr; if (attr->extra) { tmp.extra = &tmp_extra; memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra)); } /* If reference becomes zero then free attribute object. */ if (attr->refcnt == 0) { ret = hash_release (attrhash, attr); assert (ret != NULL); bgp_attr_extra_free (attr); XFREE (MTYPE_ATTR, attr); *pattr = NULL; } bgp_attr_unintern_sub (&tmp); } void bgp_attr_flush (struct attr *attr) { if (attr->aspath && ! attr->aspath->refcnt) { aspath_free (attr->aspath); attr->aspath = NULL; } if (attr->community && ! attr->community->refcnt) { community_free (attr->community); attr->community = NULL; } if (attr->extra) { struct attr_extra *attre = attr->extra; if (attre->ecommunity && ! attre->ecommunity->refcnt) ecommunity_free (&attre->ecommunity); if (attre->lcommunity && ! attre->lcommunity->refcnt) lcommunity_free (&attre->lcommunity); if (attre->cluster && ! attre->cluster->refcnt) { cluster_free (attre->cluster); attre->cluster = NULL; } if (attre->transit && ! attre->transit->refcnt) { transit_free (attre->transit); attre->transit = NULL; } encap_free(attre->encap_subtlvs); attre->encap_subtlvs = NULL; } } /* Implement some draft-ietf-idr-error-handling behaviour and * avoid resetting sessions for malformed attributes which are * are partial/optional and hence where the error likely was not * introduced by the sending neighbour. */ static bgp_attr_parse_ret_t bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, bgp_size_t length) { struct peer *const peer = args->peer; const u_int8_t flags = args->flags; /* startp and length must be special-cased, as whether or not to * send the attribute data with the NOTIFY depends on the error, * the caller therefore signals this with the seperate length argument */ u_char *notify_datap = (length > 0 ? args->startp : NULL); /* The malformed attribute shouldn't be passed on, should * we decide to proceed with parsing the UPDATE */ UNSET_FLAG (args->attr->flag, ATTR_FLAG_BIT (args->type)); /* Only relax error handling for eBGP peers */ if (peer->sort != BGP_PEER_EBGP) { bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; } /* Adjust the stream getp to the end of the attribute, in case we can * still proceed but the caller hasn't read all the attribute. */ stream_set_getp (BGP_INPUT (peer), (args->startp - STREAM_DATA (BGP_INPUT (peer))) + args->total); switch (args->type) { /* where an attribute is relatively inconsequential, e.g. it does not * affect route selection, and can be safely ignored, then any such * attributes which are malformed should just be ignored and the route * processed as normal. */ case BGP_ATTR_AS4_AGGREGATOR: case BGP_ATTR_AGGREGATOR: case BGP_ATTR_ATOMIC_AGGREGATE: return BGP_ATTR_PARSE_PROCEED; /* Core attributes, particularly ones which may influence route * selection, should always cause session resets */ case BGP_ATTR_ORIGIN: case BGP_ATTR_AS_PATH: case BGP_ATTR_NEXT_HOP: case BGP_ATTR_MULTI_EXIT_DISC: case BGP_ATTR_LOCAL_PREF: case BGP_ATTR_COMMUNITIES: case BGP_ATTR_ORIGINATOR_ID: case BGP_ATTR_CLUSTER_LIST: case BGP_ATTR_MP_REACH_NLRI: case BGP_ATTR_MP_UNREACH_NLRI: case BGP_ATTR_EXT_COMMUNITIES: bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; } /* Partial optional attributes that are malformed should not cause * the whole session to be reset. Instead treat it as a withdrawal * of the routes, if possible. */ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS) && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL)) return BGP_ATTR_PARSE_WITHDRAW; /* default to reset */ bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; } /* Find out what is wrong with the path attribute flag bits and log the error. "Flag bits" here stand for Optional, Transitive and Partial, but not for Extended Length. Checking O/T/P bits at once implies, that the attribute being diagnosed is defined by RFC as either a "well-known" or an "optional, non-transitive" attribute. */ static void bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args, u_int8_t desired_flags /* how RFC says it must be */ ) { u_char seen = 0, i; u_char real_flags = args->flags; const u_int8_t attr_code = args->type; desired_flags &= ~BGP_ATTR_FLAG_EXTLEN; real_flags &= ~BGP_ATTR_FLAG_EXTLEN; for (i = 0; i <= 2; i++) /* O,T,P, but not E */ if ( CHECK_FLAG (desired_flags, attr_flag_str[i].key) != CHECK_FLAG (real_flags, attr_flag_str[i].key) ) { zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"", LOOKUP (attr_str, attr_code), CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not", attr_flag_str[i].str); seen = 1; } if (!seen) { zlog (args->peer->log, LOG_DEBUG, "Strange, %s called for attr %s, but no problem found with flags" " (real flags 0x%x, desired 0x%x)", __func__, LOOKUP (attr_str, attr_code), real_flags, desired_flags); } } /* Required flags for attributes. EXTLEN will be masked off when testing, * as will PARTIAL for optional+transitive attributes. */ const u_int8_t attr_flags_values [] = { [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_LARGE_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL }; static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1; static int bgp_attr_flag_invalid (struct bgp_attr_parser_args *args) { u_int8_t mask = BGP_ATTR_FLAG_EXTLEN; const u_int8_t flags = args->flags; const u_int8_t attr_code = args->type; struct peer *const peer = args->peer; /* there may be attributes we don't know about */ if (attr_code > attr_flags_values_max) return 0; if (attr_flags_values[attr_code] == 0) return 0; /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to * 1." */ if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags) && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags)) { zlog (peer->log, LOG_ERR, "%s well-known attributes must have transitive flag set (%x)", LOOKUP (attr_str, attr_code), flags); return 1; } /* "For well-known attributes and for optional non-transitive attributes, * the Partial bit MUST be set to 0." */ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL)) { if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)) { zlog (peer->log, LOG_ERR, "%s well-known attribute " "must NOT have the partial flag set (%x)", LOOKUP (attr_str, attr_code), flags); return 1; } if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)) { zlog (peer->log, LOG_ERR, "%s optional + transitive attribute " "must NOT have the partial flag set (%x)", LOOKUP (attr_str, attr_code), flags); return 1; } } /* Optional transitive attributes may go through speakers that don't * reocgnise them and set the Partial bit. */ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)) SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL); if ((flags & ~mask) == attr_flags_values[attr_code]) return 0; bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]); return 1; } /* Get origin attribute of the update message. */ static bgp_attr_parse_ret_t bgp_attr_origin (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* 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); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } /* 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); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_INVAL_ORIGIN, args->total); } /* 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. */ static int bgp_attr_aspath (struct bgp_attr_parser_args *args) { struct attr *const attr = args->attr; struct peer *const peer = args->peer; const bgp_size_t length = args->length; /* * peer with AS4 => will get 4Byte ASnums * otherwise, will get 16 Bit */ attr->aspath = aspath_parse (peer->ibuf, length, CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)); /* In case of IBGP, length will be zero. */ if (! attr->aspath) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s, length is %d", peer->host, length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0); } /* Set aspath attribute flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); return BGP_ATTR_PARSE_PROCEED; } static bgp_attr_parse_ret_t bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr) { /* These checks were part of bgp_attr_aspath, but with * as4 we should to check aspath things when * aspath synthesizing with as4_path has already taken place. * Otherwise we check ASPATH and use the synthesized thing, and that is * not right. * So do the checks later, i.e. here */ struct bgp *bgp = peer->bgp; struct aspath *aspath; /* Confederation sanity check. */ if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) || (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_AS_PATH); return BGP_ATTR_PARSE_ERROR; } /* First AS check for EBGP. */ if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) { if (peer->sort == BGP_PEER_EBGP && ! aspath_firstas_check (attr->aspath, peer->as)) { zlog (peer->log, LOG_ERR, "%s incorrect first AS (must be %u)", peer->host, peer->as); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_AS_PATH); return BGP_ATTR_PARSE_ERROR; } } /* 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); } return BGP_ATTR_PARSE_PROCEED; } /* Parse AS4 path information. This function is another wrapper of aspath_parse. */ static int bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; *as4_path = aspath_parse (peer->ibuf, length, 1); /* In case of IBGP, length will be zero. */ if (!*as4_path) { zlog (peer->log, LOG_ERR, "Malformed AS4 path from %s, length is %d", peer->host, length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0); } /* Set aspath attribute flag. */ if (as4_path) attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); return BGP_ATTR_PARSE_PROCEED; } /* Nexthop attribute. */ static bgp_attr_parse_ret_t bgp_attr_nexthop (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; in_addr_t nexthop_h, nexthop_n; /* Check nexthop attribute length. */ if (length != 4) { zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP attribute must result in a NOTIFICATION message (this is implemented below). At the same time, semantically incorrect NEXT_HOP is more likely to be just logged locally (this is implemented somewhere else). The UPDATE message gets ignored in any of these cases. */ nexthop_n = stream_get_ipv4 (peer->ibuf); nexthop_h = ntohl (nexthop_n); if ((IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) && !BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) /* loopbacks may be used in testing */ { char buf[INET_ADDRSTRLEN]; inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, args->total); } attr->nexthop.s_addr = nexthop_n; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); return BGP_ATTR_PARSE_PROCEED; } /* MED atrribute. */ static bgp_attr_parse_ret_t bgp_attr_med (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Length check. */ if (length != 4) { zlog (peer->log, LOG_ERR, "MED attribute length isn't four [%d]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } attr->med = stream_getl (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); return BGP_ATTR_PARSE_PROCEED; } /* Local preference attribute. */ static bgp_attr_parse_ret_t bgp_attr_local_pref (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Length check. */ if (length != 4) { zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } /* 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 == BGP_PEER_EBGP) { stream_forward_getp (peer->ibuf, length); return BGP_ATTR_PARSE_PROCEED; } attr->local_pref = stream_getl (peer->ibuf); /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); return BGP_ATTR_PARSE_PROCEED; } /* Atomic aggregate. */ static int bgp_attr_atomic (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Length check. */ if (length != 0) { zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); return BGP_ATTR_PARSE_PROCEED; } /* Aggregator attribute */ static int bgp_attr_aggregator (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; int wantedlen = 6; struct attr_extra *attre = bgp_attr_extra_get (attr); /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) wantedlen = 8; if (length != wantedlen) { zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) attre->aggregator_as = stream_getl (peer->ibuf); else attre->aggregator_as = stream_getw (peer->ibuf); attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); return BGP_ATTR_PARSE_PROCEED; } /* New Aggregator attribute */ static bgp_attr_parse_ret_t bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args, as_t *as4_aggregator_as, struct in_addr *as4_aggregator_addr) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; if (length != 8) { zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, 0); } *as4_aggregator_as = stream_getl (peer->ibuf); as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR); return BGP_ATTR_PARSE_PROCEED; } /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. */ static bgp_attr_parse_ret_t bgp_attr_munge_as4_attrs (struct peer *const peer, struct attr *const attr, struct aspath *as4_path, as_t as4_aggregator, struct in_addr *as4_aggregator_addr) { int ignore_as4_path = 0; struct aspath *newpath; struct attr_extra *attre = attr->extra; if (!attr->aspath) { /* NULL aspath shouldn't be possible as bgp_attr_parse should have * checked that all well-known, mandatory attributes were present. * * Can only be a problem with peer itself - hard error */ return BGP_ATTR_PARSE_ERROR; } if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) { /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR * if given. * It is worth a warning though, because the peer really * should not send them */ if (BGP_DEBUG(as4, AS4)) { if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))) zlog_debug ("[AS4] %s %s AS4_PATH", peer->host, "AS4 capable peer, yet it sent"); if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) zlog_debug ("[AS4] %s %s AS4_AGGREGATOR", peer->host, "AS4 capable peer, yet it sent"); } return BGP_ATTR_PARSE_PROCEED; } /* We have a asn16 peer. First, look for AS4_AGGREGATOR * because that may override AS4_PATH */ if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) ) { if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) { assert (attre); /* received both. * if the as_number in aggregator is not AS_TRANS, * then AS4_AGGREGATOR and AS4_PATH shall be ignored * and the Aggregator shall be taken as * info on the aggregating node, and the AS_PATH * shall be taken as the AS_PATH * otherwise * the Aggregator shall be ignored and the * AS4_AGGREGATOR shall be taken as the * Aggregating node and the AS_PATH is to be * constructed "as in all other cases" */ if (attre->aggregator_as != BGP_AS_TRANS) { /* ignore */ if ( BGP_DEBUG(as4, AS4)) zlog_debug ("[AS4] %s BGP not AS4 capable peer" " send AGGREGATOR != AS_TRANS and" " AS4_AGGREGATOR, so ignore" " AS4_AGGREGATOR and AS4_PATH", peer->host); ignore_as4_path = 1; } else { /* "New_aggregator shall be taken as aggregator" */ attre->aggregator_as = as4_aggregator; attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr; } } else { /* We received a AS4_AGGREGATOR but no AGGREGATOR. * That is bogus - but reading the conditions * we have to handle AS4_AGGREGATOR as if it were * AGGREGATOR in that case */ if ( BGP_DEBUG(as4, AS4)) zlog_debug ("[AS4] %s BGP not AS4 capable peer send" " AS4_AGGREGATOR but no AGGREGATOR, will take" " it as if AGGREGATOR with AS_TRANS had been there", peer->host); (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator; /* sweep it under the carpet and simulate a "good" AGGREGATOR */ attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); } } /* need to reconcile NEW_AS_PATH and AS_PATH */ if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)))) { newpath = aspath_reconcile_as4 (attr->aspath, as4_path); aspath_unintern (&attr->aspath); attr->aspath = aspath_intern (newpath); } return BGP_ATTR_PARSE_PROCEED; } /* Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_community (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; if (length == 0) { attr->community = NULL; return BGP_ATTR_PARSE_PROCEED; } attr->community = community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length); /* XXX: fix community_parse to use stream API and remove this */ stream_forward_getp (peer->ibuf, length); if (!attr->community) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); return BGP_ATTR_PARSE_PROCEED; } /* Originator ID attribute. */ static bgp_attr_parse_ret_t bgp_attr_originator_id (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Length check. */ if (length != 4) { zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } (bgp_attr_extra_get (attr))->originator_id.s_addr = stream_get_ipv4 (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); return BGP_ATTR_PARSE_PROCEED; } /* Cluster list attribute. */ static bgp_attr_parse_ret_t bgp_attr_cluster_list (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Check length. */ if (length % 4) { zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } (bgp_attr_extra_get (attr))->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length); /* XXX: Fix cluster_parse to use stream API and then remove this */ stream_forward_getp (peer->ibuf, length); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST); return BGP_ATTR_PARSE_PROCEED; } /* Multiprotocol reachability information parse. */ int bgp_mp_reach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update) { afi_t afi; safi_t safi; bgp_size_t nlri_len; size_t start; struct stream *s; struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; struct attr_extra *attre = bgp_attr_extra_get(attr); /* Set end of packet. */ s = BGP_INPUT(peer); start = stream_get_getp(s); /* safe to read statically sized header? */ #define BGP_MP_REACH_MIN_SIZE 5 #define LEN_LEFT (length - (stream_get_getp(s) - start)) if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) { zlog_info ("%s: %s sent invalid length, %lu", __func__, peer->host, (unsigned long)length); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Load AFI, SAFI. */ afi = stream_getw (s); safi = stream_getc (s); /* Get nexthop length. */ attre->mp_nexthop_len = stream_getc (s); if (LEN_LEFT < attre->mp_nexthop_len) { zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", __func__, peer->host, attre->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Nexthop length check. */ switch (attre->mp_nexthop_len) { case 4: stream_get (&attre->mp_nexthop_global_in, s, 4); /* Probably needed for RFC 2283 */ if (attr->nexthop.s_addr == 0) memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4); break; case 12: stream_getl (s); /* RD high */ stream_getl (s); /* RD low */ stream_get (&attre->mp_nexthop_global_in, s, 4); break; case 24: { u_int32_t rd_high __attribute__((unused)); u_int32_t rd_low __attribute__((unused)); rd_high = stream_getl (s); rd_low = stream_getl (s); } /* fall through */ case 16: stream_get (&attre->mp_nexthop_global, s, 16); break; case 32: case 48: if (attre->mp_nexthop_len == 48) { u_int32_t rd_high __attribute__((unused)); u_int32_t rd_low __attribute__((unused)); rd_high = stream_getl (s); rd_low = stream_getl (s); } stream_get (&attre->mp_nexthop_global, s, 16); if (attre->mp_nexthop_len == 48) { u_int32_t rd_high __attribute__((unused)); u_int32_t rd_low __attribute__((unused)); rd_high = stream_getl (s); rd_low = stream_getl (s); } stream_get (&attre->mp_nexthop_local, s, 16); if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local)) { char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; if (BGP_DEBUG (update, UPDATE_IN)) zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host, inet_ntop (AF_INET6, &attre->mp_nexthop_global, buf1, INET6_ADDRSTRLEN), inet_ntop (AF_INET6, &attre->mp_nexthop_local, buf2, INET6_ADDRSTRLEN)); attre->mp_nexthop_len = 16; } break; default: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", __func__, peer->host, attre->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (!LEN_LEFT) { zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)", __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } { u_char val; if ((val = stream_getc (s))) zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field", peer->host, val); } /* must have nrli_len, what is left of the attribute */ nlri_len = LEN_LEFT; if ((!nlri_len) || (nlri_len > STREAM_READABLE(s))) { zlog_info ("%s: (%s) Failed to read NLRI", __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } mp_update->afi = afi; mp_update->safi = safi; mp_update->nlri = stream_pnt (s); mp_update->length = nlri_len; stream_forward_getp (s, nlri_len); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI); return BGP_ATTR_PARSE_PROCEED; #undef LEN_LEFT } /* Multiprotocol unreachable parse */ int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_withdraw) { struct stream *s; afi_t afi; safi_t safi; u_int16_t withdraw_len; struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; s = peer->ibuf; #define BGP_MP_UNREACH_MIN_SIZE 3 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE)) return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; afi = stream_getw (s); safi = stream_getc (s); withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; mp_withdraw->afi = afi; mp_withdraw->safi = safi; mp_withdraw->nlri = stream_pnt (s); mp_withdraw->length = withdraw_len; stream_forward_getp (s, withdraw_len); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI); return BGP_ATTR_PARSE_PROCEED; } /* Large Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_large_community (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; if (length == 0) { if (attr->extra) attr->extra->lcommunity = NULL; /* Empty extcomm doesn't seem to be invalid per se */ return BGP_ATTR_PARSE_PROCEED; } (bgp_attr_extra_get (attr))->lcommunity = lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); if (attr->extra && !attr->extra->lcommunity) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); return BGP_ATTR_PARSE_PROCEED; } /* Extended Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_ext_communities (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; if (length == 0) { if (attr->extra) attr->extra->ecommunity = NULL; /* Empty extcomm doesn't seem to be invalid per se */ return BGP_ATTR_PARSE_PROCEED; } (bgp_attr_extra_get (attr))->ecommunity = ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); if (attr->extra && !attr->extra->ecommunity) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); return BGP_ATTR_PARSE_PROCEED; } /* Parse Tunnel Encap attribute in an UPDATE */ static int bgp_attr_encap( uint8_t type, struct peer *peer, /* IN */ bgp_size_t length, /* IN: attr's length field */ struct attr *attr, /* IN: caller already allocated */ u_char flag, /* IN: attr's flags field */ u_char *startp) { bgp_size_t total; struct attr_extra *attre = NULL; struct bgp_attr_encap_subtlv *stlv_last = NULL; uint16_t tunneltype; total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS) || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) { zlog (peer->log, LOG_ERR, "Tunnel Encap attribute flag isn't optional and transitive %d", flag); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); return -1; } if (BGP_ATTR_ENCAP == type) { /* read outer TLV type and length */ uint16_t tlv_length; if (length < 4) { zlog (peer->log, LOG_ERR, "Tunnel Encap attribute not long enough to contain outer T,L"); bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total); return -1; } tunneltype = stream_getw (BGP_INPUT (peer)); tlv_length = stream_getw (BGP_INPUT (peer)); length -= 4; if (tlv_length != length) { zlog (peer->log, LOG_ERR, "%s: tlv_length(%d) != length(%d)", __func__, tlv_length, length); } } while (length >= 4) { uint16_t subtype = 0; uint16_t sublength = 0; struct bgp_attr_encap_subtlv *tlv; if (BGP_ATTR_ENCAP == type) { subtype = stream_getc (BGP_INPUT (peer)); sublength = stream_getc (BGP_INPUT (peer)); length -= 2; } if (sublength > length) { zlog (peer->log, LOG_ERR, "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", sublength, length); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total); return -1; } /* alloc and copy sub-tlv */ /* TBD make sure these are freed when attributes are released */ tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength); tlv->type = subtype; tlv->length = sublength; stream_get(tlv->value, peer->ibuf, sublength); length -= sublength; /* attach tlv to encap chain */ if (!attre) { attre = bgp_attr_extra_get(attr); if (BGP_ATTR_ENCAP == type) { for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next; stlv_last = stlv_last->next); if (stlv_last) { stlv_last->next = tlv; } else { attre->encap_subtlvs = tlv; } } } else { stlv_last->next = tlv; } stlv_last = tlv; } if (attre && (BGP_ATTR_ENCAP == type)) { attre->encap_tunneltype = tunneltype; } if (length) { /* spurious leftover data */ zlog (peer->log, LOG_ERR, "Tunnel Encap attribute length is bad: %d leftover octets", length); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total); return -1; } return 0; } /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t bgp_attr_unknown (struct bgp_attr_parser_args *args) { bgp_size_t total = args->total; struct transit *transit; struct attr_extra *attre; struct peer *const peer = args->peer; struct attr *const attr = args->attr; u_char *const startp = args->startp; const u_char type = args->type; const u_char flag = args->flags; const bgp_size_t length = args->length; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Unknown attribute is received (type %d, length %d)", peer->host, type, length); if (BGP_DEBUG (events, EVENTS)) zlog (peer->log, LOG_DEBUG, "Unknown attribute type %d length %d is received", type, length); /* Forward read pointer of input stream. */ stream_forward_getp (peer->ibuf, length); /* 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)) { return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_UNREC_ATTR, args->total); } /* 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 BGP_ATTR_PARSE_PROCEED; /* 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 (! ((attre = bgp_attr_extra_get(attr))->transit) ) attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit)); transit = attre->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 BGP_ATTR_PARSE_PROCEED; } /* Well-known attribute check. */ static int bgp_attr_check (struct peer *peer, struct attr *attr) { u_char type = 0; /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an * empty UPDATE. */ if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag) return BGP_ATTR_PARSE_PROCEED; /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required to carry any other path attributes.", though if MP_REACH_NLRI or NLRI are present, it should. Check for any other attribute being present instead. */ if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI)) return BGP_ATTR_PARSE_PROCEED; 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; /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and * NLRI is empty. We can't easily check NLRI empty here though. */ if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)) && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI))) type = BGP_ATTR_NEXT_HOP; if (peer->sort == 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 / %s", peer->host, type, LOOKUP (attr_str, type)); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MISS_ATTR, &type, 1); return BGP_ATTR_PARSE_ERROR; } return BGP_ATTR_PARSE_PROCEED; } /* Read attribute of update packet. This function is called from bgp_update_receive() in bgp_packet.c. */ bgp_attr_parse_ret_t 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 = 0; u_char type = 0; bgp_size_t length; u_char *startp, *endp; u_char *attr_endp; u_char seen[BGP_ATTR_BITMAP_SIZE]; /* we need the as4_path only until we have synthesized the as_path with it */ /* same goes for as4_aggregator */ struct aspath *as4_path = NULL; as_t as4_aggregator = 0; struct in_addr as4_aggregator_addr = { .s_addr = 0 }; /* Initialize bitmap. */ memset (seen, 0, BGP_ATTR_BITMAP_SIZE); /* End pointer of BGP attribute. */ assert (size <= stream_get_size (BGP_INPUT (peer))); assert (size <= stream_get_endp (BGP_INPUT (peer))); 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) { /* XXX warning: long int format, int arg (arg 5) */ zlog (peer->log, LOG_WARNING, "%s: error BGP attribute length %lu is smaller than min len", peer->host, (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return BGP_ATTR_PARSE_ERROR; } /* Fetch attribute flag and type. */ startp = BGP_INPUT_PNT (peer); /* "The lower-order four bits of the Attribute Flags octet are unused. They MUST be zero when sent and MUST be ignored when received." */ flag = 0xF0 & stream_getc (BGP_INPUT (peer)); type = stream_getc (BGP_INPUT (peer)); /* Check whether Extended-Length applies and is in bounds */ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) { zlog (peer->log, LOG_WARNING, "%s: Extended length set, but just %lu bytes of attr header", peer->host, (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return BGP_ATTR_PARSE_ERROR; } /* 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 BGP_ATTR_PARSE_ERROR; } /* 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); zlog_warn ("%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_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, startp, endp - startp); return BGP_ATTR_PARSE_ERROR; } struct bgp_attr_parser_args attr_args = { .peer = peer, .length = length, .attr = attr, .type = type, .flags = flag, .startp = startp, .total = attr_endp - startp, }; /* 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 (bgp_attr_flag_invalid (&attr_args)) { bgp_attr_parse_ret_t ret; ret = bgp_attr_malformed (&attr_args, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, attr_args.total); if (ret == BGP_ATTR_PARSE_PROCEED) continue; return ret; } /* OK check attribute and store it's value. */ switch (type) { case BGP_ATTR_ORIGIN: ret = bgp_attr_origin (&attr_args); break; case BGP_ATTR_AS_PATH: ret = bgp_attr_aspath (&attr_args); break; case BGP_ATTR_AS4_PATH: ret = bgp_attr_as4_path (&attr_args, &as4_path); break; case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (&attr_args); break; case BGP_ATTR_MULTI_EXIT_DISC: ret = bgp_attr_med (&attr_args); break; case BGP_ATTR_LOCAL_PREF: ret = bgp_attr_local_pref (&attr_args); break; case BGP_ATTR_ATOMIC_AGGREGATE: ret = bgp_attr_atomic (&attr_args); break; case BGP_ATTR_AGGREGATOR: ret = bgp_attr_aggregator (&attr_args); break; case BGP_ATTR_AS4_AGGREGATOR: ret = bgp_attr_as4_aggregator (&attr_args, &as4_aggregator, &as4_aggregator_addr); break; case BGP_ATTR_COMMUNITIES: ret = bgp_attr_community (&attr_args); break; case BGP_ATTR_LARGE_COMMUNITIES: ret = bgp_attr_large_community (&attr_args); break; case BGP_ATTR_ORIGINATOR_ID: ret = bgp_attr_originator_id (&attr_args); break; case BGP_ATTR_CLUSTER_LIST: ret = bgp_attr_cluster_list (&attr_args); break; case BGP_ATTR_MP_REACH_NLRI: ret = bgp_mp_reach_parse (&attr_args, mp_update); break; case BGP_ATTR_MP_UNREACH_NLRI: ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw); break; case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (&attr_args); break; case BGP_ATTR_ENCAP: ret = bgp_attr_encap (type, peer, length, attr, flag, startp); break; default: ret = bgp_attr_unknown (&attr_args); break; } if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) { bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); ret = BGP_ATTR_PARSE_ERROR; } /* If hard error occurred immediately return to the caller. */ if (ret == BGP_ATTR_PARSE_ERROR) { zlog (peer->log, LOG_WARNING, "%s: Attribute %s, parse error", peer->host, LOOKUP (attr_str, type)); if (as4_path) aspath_unintern (&as4_path); return ret; } if (ret == BGP_ATTR_PARSE_WITHDRAW) { zlog (peer->log, LOG_WARNING, "%s: Attribute %s, parse error - treating as withdrawal", peer->host, LOOKUP (attr_str, type)); if (as4_path) aspath_unintern (&as4_path); return ret; } /* Check the fetched length. */ if (BGP_INPUT_PNT (peer) != attr_endp) { zlog (peer->log, LOG_WARNING, "%s: BGP attribute %s, fetch error", peer->host, LOOKUP (attr_str, type)); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); if (as4_path) aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } } /* Check final read pointer is same as end pointer. */ if (BGP_INPUT_PNT (peer) != endp) { zlog (peer->log, LOG_WARNING, "%s: BGP attribute %s, length mismatch", peer->host, LOOKUP (attr_str, type)); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); if (as4_path) aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } /* Check all mandatory well-known attributes are present */ { bgp_attr_parse_ret_t ret; if ((ret = bgp_attr_check (peer, attr)) < 0) { if (as4_path) aspath_unintern (&as4_path); return ret; } } /* * At this place we can see whether we got AS4_PATH and/or * AS4_AGGREGATOR from a 16Bit peer and act accordingly. * We can not do this before we've read all attributes because * the as4 handling does not say whether AS4_PATH has to be sent * after AS_PATH or not - and when AS4_AGGREGATOR will be send * in relationship to AGGREGATOR. * So, to be defensive, we are not relying on any order and read * all attributes first, including these 32bit ones, and now, * afterwards, we look what and if something is to be done for as4. * * It is possible to not have AS_PATH, e.g. GR EoR and sole * MP_UNREACH_NLRI. */ /* actually... this doesn't ever return failure currently, but * better safe than sorry */ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)) && bgp_attr_munge_as4_attrs (peer, attr, as4_path, as4_aggregator, &as4_aggregator_addr)) { bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); if (as4_path) aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } /* At this stage, we have done all fiddling with as4, and the * resulting info is in attr->aggregator resp. attr->aspath * so we can chuck as4_aggregator and as4_path alltogether in * order to save memory */ if (as4_path) { aspath_unintern (&as4_path); /* unintern - it is in the hash */ /* The flag that we got this is still there, but that does not * do any trouble */ } /* * The "rest" of the code does nothing with as4_aggregator. * there is no memory attached specifically which is not part * of the attr. * so ignoring just means do nothing. */ /* * Finally do the checks on the aspath we did not do yet * because we waited for a potentially synthesized aspath. */ if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) { ret = bgp_attr_aspath_check (peer, attr); if (ret != BGP_ATTR_PARSE_PROCEED) return ret; } /* Finally intern unknown attribute. */ if (attr->extra && attr->extra->transit) attr->extra->transit = transit_intern (attr->extra->transit); return BGP_ATTR_PARSE_PROCEED; } int stream_put_prefix (struct stream *, struct prefix *); size_t bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, struct attr *attr) { size_t sizep; /* Set extended bit always to encode the attribute length as 2 bytes */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); stream_putw (s, 0); /* Marker: Attribute length. */ stream_putw (s, afi); stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi); /* Nexthop */ switch (afi) { case AFI_IP: switch (safi) { case SAFI_MULTICAST: stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); break; case SAFI_MPLS_VPN: stream_putc (s, 12); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); stream_put (s, &attr->extra->mp_nexthop_global_in, 4); break; case SAFI_ENCAP: stream_putc (s, 4); stream_put (s, &attr->extra->mp_nexthop_global_in, 4); break; case SAFI_UNICAST: /* invalid for IPv4 */ default: break; } break; case AFI_IP6: switch (safi) { case SAFI_UNICAST: case SAFI_MULTICAST: { struct attr_extra *attre = attr->extra; assert (attr->extra); stream_putc (s, attre->mp_nexthop_len); stream_put (s, &attre->mp_nexthop_global, 16); if (attre->mp_nexthop_len == 32) stream_put (s, &attre->mp_nexthop_local, 16); } break; case SAFI_MPLS_VPN: { struct attr_extra *attre = attr->extra; assert (attr->extra); if (attre->mp_nexthop_len == 16) { stream_putc (s, 24); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); stream_put (s, &attre->mp_nexthop_global, 16); } else if (attre->mp_nexthop_len == 32) { stream_putc (s, 48); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); stream_put (s, &attre->mp_nexthop_global, 16); stream_putl (s, 0); /* RD = 0, per RFC */ stream_putl (s, 0); stream_put (s, &attre->mp_nexthop_local, 16); } } break; case SAFI_ENCAP: assert (attr->extra); stream_putc (s, 16); stream_put (s, &attr->extra->mp_nexthop_global, 16); break; default: break; } break; default: break; } /* SNPA */ stream_putc (s, 0); return sizep; } void bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, u_char *tag) { if (safi == SAFI_MPLS_VPN) { /* 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)); } else stream_put_prefix (s, p); } size_t bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p) { int size = PSIZE (p->prefixlen); if (safi == SAFI_MPLS_VPN) size += 88; return size; } /* * Encodes the tunnel encapsulation attribute */ static void bgp_packet_mpattr_tea( struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, uint8_t attrtype) { unsigned int attrlenfield = 0; unsigned int attrhdrlen = 0; struct bgp_attr_encap_subtlv *subtlvs; struct bgp_attr_encap_subtlv *st; const char *attrname; if (!attr || !attr->extra) return; switch (attrtype) { case BGP_ATTR_ENCAP: attrname = "Tunnel Encap"; subtlvs = attr->extra->encap_subtlvs; /* * The tunnel encap attr has an "outer" tlv. * T = tunneltype, * L = total length of subtlvs, * V = concatenated subtlvs. */ attrlenfield = 2 + 2; /* T + L */ attrhdrlen = 1 + 1; /* subTLV T + L */ break; default: assert(0); } /* if no tlvs, don't make attr */ if (subtlvs == NULL) return; /* compute attr length */ for (st = subtlvs; st; st = st->next) { attrlenfield += (attrhdrlen + st->length); } if (attrlenfield > 0xffff) { zlog (peer->log, LOG_ERR, "%s attribute is too long (length=%d), can't send it", attrname, attrlenfield); return; } if (attrlenfield > 0xff) { /* 2-octet length field */ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, attrtype); stream_putw (s, attrlenfield & 0xffff); } else { /* 1-octet length field */ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, attrtype); stream_putc (s, attrlenfield & 0xff); } if (attrtype == BGP_ATTR_ENCAP) { /* write outer T+L */ stream_putw(s, attr->extra->encap_tunneltype); stream_putw(s, attrlenfield - 4); } /* write each sub-tlv */ for (st = subtlvs; st; st = st->next) { if (attrtype == BGP_ATTR_ENCAP) { stream_putc (s, st->type); stream_putc (s, st->length); } stream_put (s, st->value, st->length); } } void bgp_packet_mpattr_end (struct stream *s, size_t sizep) { /* Set MP attribute length. Don't count the (2) bytes used to encode the attr length */ stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2); } /* 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) { size_t cp; size_t aspath_sizep; struct aspath *aspath; int send_as4_path = 0; int send_as4_aggregator = 0; int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0; if (! bgp) bgp = bgp_get_default (); /* Remember current pointer. */ cp = stream_get_endp (s); if (p && !(afi == AFI_IP && safi == SAFI_UNICAST)) { size_t mpattrlen_pos = 0; mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr); bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag); bgp_packet_mpattr_end(s, mpattrlen_pos); } /* 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 == BGP_PEER_EBGP && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) || attr->aspath->segments == NULL) && (! 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 { if (peer->change_local_as) { /* If replace-as is specified, we only use the change_local_as when advertising routes. */ if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) { aspath = aspath_add_seq (aspath, peer->local_as); } aspath = aspath_add_seq (aspath, peer->change_local_as); } else { aspath = aspath_add_seq (aspath, peer->local_as); } } } else if (peer->sort == 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; /* If peer is not AS4 capable, then: * - send the created AS_PATH out as AS4_PATH (optional, transitive), * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment * types are in it (i.e. exclude them if they are there) * AND do this only if there is at least one asnum > 65535 in the path! * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change * all ASnums > 65535 to BGP_AS_TRANS */ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS_PATH); aspath_sizep = stream_get_endp (s); stream_putw (s, 0); stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit)); /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs * in the path */ if (!use32bit && aspath_has_as4 (aspath)) send_as4_path = 1; /* we'll do this later, at the correct place */ /* Nexthop attribute. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP && safi == SAFI_UNICAST) /* only write NH attr for unicast safi */ { 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 == BGP_PEER_IBGP || peer->sort == 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)) { assert (attr->extra); /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); if (use32bit) { /* AS4 capable peer */ stream_putc (s, 8); stream_putl (s, attr->extra->aggregator_as); } else { /* 2-byte AS peer */ stream_putc (s, 6); /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */ if ( attr->extra->aggregator_as > 65535 ) { stream_putw (s, BGP_AS_TRANS); /* we have to send AS4_AGGREGATOR, too. * we'll do that later in order to send attributes in ascending * order. */ send_as4_aggregator = 1; } else stream_putw (s, (u_int16_t) attr->extra->aggregator_as); } stream_put_ipv4 (s, attr->extra->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); } /* * Large Community attribute. */ if (attr->extra && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))) { if (attr->extra->lcommunity->size * 12 > 255) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); stream_putw (s, attr->extra->lcommunity->size * 12); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); stream_putc (s, attr->extra->lcommunity->size * 12); } stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); } /* Route Reflector. */ if (peer->sort == BGP_PEER_IBGP && from && from->sort == 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->extra->originator_id); else stream_put_in_addr (s, &from->remote_id); /* Cluster list. */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_CLUSTER_LIST); if (attr->extra && attr->extra->cluster) { stream_putc (s, attr->extra->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->extra->cluster->list, attr->extra->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); } } /* 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))) { struct attr_extra *attre = attr->extra; assert (attre); if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { if (attre->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, attre->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, attre->ecommunity->size * 8); } stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8); } else { u_int8_t *pnt; int tbit; int ecom_tr_size = 0; int i; for (i = 0; i < attre->ecommunity->size; i++) { pnt = attre->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 < attre->ecommunity->size; i++) { pnt = attre->ecommunity->val + (i * 8); tbit = *pnt; if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) continue; stream_put (s, pnt, 8); } } } } if ( send_as4_path ) { /* If the peer is NOT As4 capable, AND */ /* there are ASnums > 65535 in path THEN * give out AS4_PATH */ /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET * path segments! * Hm, I wonder... confederation things *should* only be at * the beginning of an aspath, right? Then we should use * aspath_delete_confed_seq for this, because it is already * there! (JK) * Folks, talk to me: what is reasonable here!? */ aspath = aspath_delete_confed_seq (aspath); stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS4_PATH); aspath_sizep = stream_get_endp (s); stream_putw (s, 0); stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1)); } if (aspath != attr->aspath) aspath_free (aspath); if ( send_as4_aggregator ) { assert (attr->extra); /* send AS4_AGGREGATOR, at this place */ /* this section of code moved here in order to ensure the correct * *ascending* order of attributes */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AS4_AGGREGATOR); stream_putc (s, 8); stream_putl (s, attr->extra->aggregator_as); stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN)) { /* Tunnel Encap attribute */ bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP); } /* Unknown transit attribute. */ if (attr->extra && attr->extra->transit) stream_put (s, attr->extra->transit->val, attr->extra->transit->length); /* Return total size of attribute. */ return stream_get_endp (s) - cp; } size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi) { unsigned long attrlen_pnt; /* Set extended bit always to encode the attribute length as 2 bytes */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); attrlen_pnt = stream_get_endp (s); stream_putw (s, 0); /* Length of this attribute. */ stream_putw (s, afi); stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi); return attrlen_pnt; } void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag) { bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag); } void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt) { bgp_packet_mpattr_end (s, attrlen_pnt); } /* Initialization of attribute. */ void bgp_attr_init (void) { aspath_init (); attrhash_init (); community_init (); ecommunity_init (); lcommunity_init (); cluster_init (); transit_init (); } void bgp_attr_finish (void) { aspath_finish (); attrhash_finish (); community_finish (); ecommunity_finish (); lcommunity_finish (); cluster_finish (); transit_finish (); } /* Make attribute packet. */ void bgp_dump_routes_attr (struct stream *s, struct attr *attr, struct prefix *prefix) { unsigned long cp; unsigned long len; size_t aspath_lenp; struct aspath *aspath; /* Remember current pointer. */ cp = stream_get_endp (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; stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS_PATH); aspath_lenp = stream_get_endp (s); stream_putw (s, 0); stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1)); /* Nexthop attribute. */ /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */ if(prefix != NULL && prefix->family != AF_INET6 ) { 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)) { assert (attr->extra); stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); stream_putc (s, 8); stream_putl (s, attr->extra->aggregator_as); stream_put_ipv4 (s, attr->extra->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); } /* Large Community attribute. */ if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)) { if (attr->extra->lcommunity->size * 12 > 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->extra->lcommunity->size * 12); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_COMMUNITIES); stream_putc (s, attr->extra->lcommunity->size * 12); } stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); } /* Add a MP_NLRI attribute to dump the IPv6 next hop */ if (prefix != NULL && prefix->family == AF_INET6 && attr->extra && (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) ) { int sizep; struct attr_extra *attre = attr->extra; stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); /* MP header */ stream_putc (s, 0); /* Marker: Attribute length. */ stream_putw(s, AFI_IP6); /* AFI */ stream_putc(s, SAFI_UNICAST); /* SAFI */ /* Next hop */ stream_putc(s, attre->mp_nexthop_len); stream_put(s, &attre->mp_nexthop_global, 16); if (attre->mp_nexthop_len == 32) stream_put(s, &attre->mp_nexthop_local, 16); /* SNPA */ stream_putc(s, 0); /* Prefix */ stream_put_prefix(s, prefix); /* Set MP attribute length. */ stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); } /* Return total size of attribute. */ len = stream_get_endp (s) - cp - 2; stream_putw_at (s, cp, len); } quagga-1.2.4/bgpd/bgp_attr.h000066400000000000000000000165631325323223500156650ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_ATTR_H #define _QUAGGA_BGP_ATTR_H /* 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)) #define BGP_MED_MAX UINT32_MAX /* 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 3 /* Attribute flag, type length. */ #define BGP_ATTR_DEFAULT_WEIGHT 32768 struct bgp_attr_encap_subtlv { struct bgp_attr_encap_subtlv *next; /* for chaining */ uint16_t type; uint16_t length; uint8_t value[1]; /* will be extended */ }; /* Additional/uncommon BGP attributes. * lazily allocated as and when a struct attr * requires it. */ struct attr_extra { /* Multi-Protocol Nexthop, AFI IPv6 */ struct in6_addr mp_nexthop_global; struct in6_addr mp_nexthop_local; /* Extended Communities attribute. */ struct ecommunity *ecommunity; /* Large Communities attribute. */ struct lcommunity *lcommunity; /* Route-Reflector Cluster attribute */ struct cluster_list *cluster; /* Unknown transitive attribute. */ struct transit *transit; struct in_addr mp_nexthop_global_in; /* Aggregator Router ID attribute */ struct in_addr aggregator_addr; /* Route Reflector Originator attribute */ struct in_addr originator_id; /* Local weight, not actually an attribute */ u_int32_t weight; /* Aggregator ASN */ as_t aggregator_as; /* MP Nexthop length */ u_char mp_nexthop_len; uint16_t encap_tunneltype; /* grr */ struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ /* route tag */ route_tag_t tag; }; /* BGP core attribute structure. */ struct attr { /* AS Path structure */ struct aspath *aspath; /* Community structure */ struct community *community; /* Lazily allocated pointer to extra attributes */ struct attr_extra *extra; /* Reference count of this attribute. */ unsigned long refcnt; /* Flag of attribute is set or not. */ u_int32_t flag; /* Apart from in6_addr, the remaining static attributes */ struct in_addr nexthop; u_int32_t med; u_int32_t local_pref; /* Path origin attribute */ u_char origin; }; /* 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)) typedef enum { BGP_ATTR_PARSE_PROCEED = 0, BGP_ATTR_PARSE_ERROR = -1, BGP_ATTR_PARSE_WITHDRAW = -2, /* only used internally, send notify + convert to BGP_ATTR_PARSE_ERROR */ BGP_ATTR_PARSE_ERROR_NOTIFYPLS = -3, } bgp_attr_parse_ret_t; /* Prototypes. */ extern void bgp_attr_init (void); extern void bgp_attr_finish (void); extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, struct bgp_nlri *, struct bgp_nlri *); extern struct attr_extra *bgp_attr_extra_get (struct attr *); extern void bgp_attr_extra_free (struct attr *); extern void bgp_attr_dup (struct attr *, struct attr *); extern struct attr *bgp_attr_intern (struct attr *attr); extern void bgp_attr_unintern_sub (struct attr *); extern void bgp_attr_unintern (struct attr **); extern void bgp_attr_flush (struct attr *); extern struct attr *bgp_attr_default_set (struct attr *attr, u_char); extern struct attr *bgp_attr_default_intern (u_char); extern struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char, struct aspath *, struct community *, int as_set, u_char); extern 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 *); extern void bgp_dump_routes_attr (struct stream *, struct attr *, struct prefix *); extern int attrhash_cmp (const void *, const void *); extern unsigned int attrhash_key_make (void *); extern void attr_show_all (struct vty *); extern unsigned long int attr_count (void); extern unsigned long int attr_unknown_count (void); /* Cluster list prototypes. */ extern int cluster_loop_check (struct cluster_list *, struct in_addr); extern void cluster_unintern (struct cluster_list **); /* Transit attribute prototypes. */ void transit_unintern (struct transit **); /* Below exported for unit-test purposes only */ struct bgp_attr_parser_args { struct peer *peer; bgp_size_t length; /* attribute data length; */ bgp_size_t total; /* total length, inc header */ struct attr *attr; u_int8_t type; u_int8_t flags; u_char *startp; }; extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *); extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *); extern struct bgp_attr_encap_subtlv * encap_tlv_dup(struct bgp_attr_encap_subtlv *orig); extern void bgp_attr_flush_encap(struct attr *attr); /** * Set of functions to encode MP_REACH_NLRI and MP_UNREACH_NLRI attributes. * Typical call sequence is to call _start(), followed by multiple _prefix(), * one for each NLRI that needs to be encoded into the UPDATE message, and * finally the _end() function. */ extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi, struct attr *attr); extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, u_char *tag); extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, struct prefix *p); extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep); extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag); extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt); #endif /* _QUAGGA_BGP_ATTR_H */ quagga-1.2.4/bgpd/bgp_btoa.c000066400000000000000000000153761325323223500156340ustar00rootroot00000000000000/* BGP dump to ascii converter 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 "zebra.h" #include "stream.h" #include "log.h" #include "prefix.h" #include "command.h" #include "memory.h" #include "privs.h" #include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" /* privileges */ static zebra_capabilities_t _caps_p [] = { ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, }; struct zebra_privs_t bgpd_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), .cap_num_i = 0, }; 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 */ }; static int attr_parse (struct stream *s, u_int16_t len) { u_int flag; u_int type; u_int16_t length; u_int16_t lim; lim = s->getp + len; printf ("attr_parse s->getp %zd, len %d, lim %d\n", s->getp, len, lim); while (s->getp < lim) { flag = stream_getc (s); type = stream_getc (s); if (flag & BGP_ATTR_FLAG_EXTLEN) length = stream_getw (s); else length = stream_getc (s); printf ("FLAG: %d\n", flag); printf ("TYPE: %d\n", type); printf ("Len: %d\n", length); switch (type) { case BGP_ATTR_ORIGIN: { u_char origin; origin = stream_getc (s); printf ("ORIGIN: %d\n", origin); } break; case BGP_ATTR_AS_PATH: { struct aspath *aspath; aspath = aspath_parse (s, length, 1); printf ("ASPATH: %s\n", aspath->str); aspath_free(aspath); } break; case BGP_ATTR_NEXT_HOP: { struct in_addr nexthop; nexthop.s_addr = stream_get_ipv4 (s); printf ("NEXTHOP: %s\n", inet_ntoa (nexthop)); } break; default: stream_getw_from (s, length); break; } } return 0; } int main (int argc, char **argv) { int ret; FILE *fp; struct stream *s; time_t now; int type; int subtype; size_t len; int source_as; int dest_as; ifindex_t ifindex; int family; struct in_addr sip; struct in_addr dip; u_int16_t viewno, seq_num; struct prefix_ipv4 p; s = stream_new (10000); if (argc != 2) { fprintf (stderr, "Usage: %s FILENAME\n", argv[0]); exit (1); } fp = fopen (argv[1], "r"); if (!fp) { perror ("fopen"); exit (1); } while (1) { stream_reset (s); ret = fread (s->data, 12, 1, fp); if (!ret || feof (fp)) { printf ("END OF FILE\n"); break; } if (ferror (fp)) { printf ("ERROR OF FREAD\n"); break; } /* Extract header. */ now = stream_getl (s); type = stream_getw (s); subtype = stream_getw (s); len = stream_getl (s); printf ("TIME: %s", ctime (&now)); /* printf ("TYPE: %d/%d\n", type, subtype); */ if (type == MSG_PROTOCOL_BGP4MP) printf ("TYPE: BGP4MP"); else if (type == MSG_PROTOCOL_BGP4MP_ET) printf ("TYPE: BGP4MP_ET"); else if (type == MSG_TABLE_DUMP) printf ("TYPE: MSG_TABLE_DUMP"); else printf ("TYPE: Unknown %d", type); if (type == MSG_TABLE_DUMP) switch (subtype) { case AFI_IP: printf ("/AFI_IP\n"); break; case AFI_IP6: printf ("/AFI_IP6\n"); break; default: printf ("/UNKNOWN %d", subtype); break; } else { switch (subtype) { case BGP4MP_STATE_CHANGE: printf ("/CHANGE\n"); break; case BGP4MP_MESSAGE: printf ("/MESSAGE\n"); break; case BGP4MP_ENTRY: printf ("/ENTRY\n"); break; case BGP4MP_SNAPSHOT: printf ("/SNAPSHOT\n"); break; default: printf ("/UNKNOWN %d", subtype); break; } } printf ("len: %zd\n", len); ret = fread (s->data + 12, len, 1, fp); if (feof (fp)) { printf ("ENDOF FILE 2\n"); break; } if (ferror (fp)) { printf ("ERROR OF FREAD 2\n"); break; } /* printf ("now read %d\n", len); */ if (type == MSG_TABLE_DUMP) { u_char status; time_t originated; struct in_addr peer; u_int16_t attrlen; viewno = stream_getw (s); seq_num = stream_getw (s); printf ("VIEW: %d\n", viewno); printf ("SEQUENCE: %d\n", seq_num); /* start */ while (s->getp < len - 16) { p.prefix.s_addr = stream_get_ipv4 (s); p.prefixlen = stream_getc (s); printf ("PREFIX: %s/%d\n", inet_ntoa (p.prefix), p.prefixlen); status = stream_getc (s); originated = stream_getl (s); peer.s_addr = stream_get_ipv4 (s); source_as = stream_getw(s); printf ("FROM: %s AS%d\n", inet_ntoa (peer), source_as); printf ("ORIGINATED: %s", ctime (&originated)); attrlen = stream_getw (s); printf ("ATTRLEN: %d\n", attrlen); attr_parse (s, attrlen); printf ("STATUS: 0x%x\n", status); } } else { source_as = stream_getw (s); dest_as = stream_getw (s); printf ("source_as: %d\n", source_as); printf ("dest_as: %d\n", dest_as); ifindex = stream_getw (s); family = stream_getw (s); printf ("ifindex: %d\n", ifindex); printf ("family: %d\n", family); sip.s_addr = stream_get_ipv4 (s); dip.s_addr = stream_get_ipv4 (s); printf ("saddr: %s\n", inet_ntoa (sip)); printf ("daddr: %s\n", inet_ntoa (dip)); printf ("\n"); } } fclose (fp); return 0; } quagga-1.2.4/bgpd/bgp_clist.c000066400000000000000000000755251325323223500160270ustar00rootroot00000000000000/* 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 "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_lcommunity.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; case EXTCOMMUNITY_LIST_MASTER: return &ch->extcommunity_list; case LARGE_COMMUNITY_LIST_MASTER: return &ch->lcommunity_list; } return NULL; } /* Allocate a new community list entry. */ static struct community_entry * community_entry_new (void) { return XCALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry)); } /* Free community list entry. */ static 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 LARGE_COMMUNITY_LIST_STANDARD: if (entry->u.lcom) lcommunity_free (&entry->u.lcom); 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: case LARGE_COMMUNITY_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. */ static struct community_list * community_list_new (void) { return XCALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list)); } /* Free community-list. */ static void community_list_free (struct community_list *list) { if (list->name) XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name); XFREE (MTYPE_COMMUNITY_LIST, list); } static struct community_list * community_list_insert (struct community_list_handler *ch, const char *name, int master) { size_t 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, const 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; } static struct community_list * community_list_get (struct community_list_handler *ch, const 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; } static 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); } static 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, const 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 LARGE_COMMUNITY_LIST_STANDARD: if (lcommunity_cmp (entry->u.lcom, 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: case LARGE_COMMUNITY_LIST_EXPANDED: if (strcmp (entry->config, arg) == 0) return entry; break; default: break; } } return NULL; } static char * community_str_get (struct community *com, int i) { int len; u_int32_t comval; u_int16_t as; u_int16_t val; char *str; char *pnt; 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); 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, "%u:%d", as, val); pnt += strlen (pnt); break; } *pnt = '\0'; return str; } /* Internal function to perform regular expression match for * * a single community. */ static int community_regexp_include (regex_t * reg, struct community *com, int i) { char *str; int rv; /* When there is no communities attribute it is treated as empty * string. */ if (com == NULL || com->size == 0) str = XSTRDUP(MTYPE_COMMUNITY_STR, ""); else str = community_str_get (com, i); /* Regular expression match. */ rv = regexec (reg, str, 0, NULL, 0); XFREE(MTYPE_COMMUNITY_STR, str); if (rv == 0) return 1; /* No match. */ return 0; } /* Internal function to perform regular expression match for community attribute. */ static int community_regexp_match (struct community *com, regex_t * reg) { const 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 char * lcommunity_str_get (struct lcommunity *lcom, int i) { struct lcommunity_val lcomval; u_int32_t globaladmin; u_int32_t localdata1; u_int32_t localdata2; char *str; u_char *ptr; char *pnt; ptr = lcom->val; ptr += (i * LCOMMUNITY_SIZE); memcpy (&lcomval, ptr, LCOMMUNITY_SIZE); /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */ str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48); ptr = (u_char *)lcomval.val; globaladmin = (*ptr++ << 24); globaladmin |= (*ptr++ << 16); globaladmin |= (*ptr++ << 8); globaladmin |= (*ptr++); localdata1 = (*ptr++ << 24); localdata1 |= (*ptr++ << 16); localdata1 |= (*ptr++ << 8); localdata1 |= (*ptr++); localdata2 = (*ptr++ << 24); localdata2 |= (*ptr++ << 16); localdata2 |= (*ptr++ << 8); localdata2 |= (*ptr++); sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2); pnt += strlen (pnt); *pnt = '\0'; return str; } /* Internal function to perform regular expression match for * * a single community. */ static int lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i) { const char *str; /* When there is no communities attribute it is treated as empty * string. */ if (lcom == NULL || lcom->size == 0) str = ""; else str = lcommunity_str_get (lcom, i); /* Regular expression match. */ if (regexec (reg, str, 0, NULL, 0) == 0) return 1; /* No match. */ return 0; } static int lcommunity_regexp_match (struct lcommunity *com, regex_t * reg) { const char *str; /* When there is no communities attribute it is treated as empty string. */ if (com == NULL || com->size == 0) str = ""; else str = lcommunity_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) { const 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 lcommunity_list_match (struct lcommunity *lcom, 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 == LARGE_COMMUNITY_LIST_STANDARD) { if (lcommunity_match (lcom, entry->u.lcom)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) { if (lcommunity_regexp_match (lcom, 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; } /* Delete all permitted communities in the list from com. */ struct community * community_list_match_delete (struct community *com, struct community_list *list) { struct community_entry *entry; u_int32_t val; u_int32_t com_index_to_delete[com->size]; int delete_index = 0; int i; /* Loop over each community value and evaluate each against the * community-list. If we need to delete a community value add its index to * com_index_to_delete. */ for (i = 0; i < com->size; i++) { val = community_val_get (com, i); for (entry = list->head; entry; entry = entry->next) { if (entry->any) { if (entry->direct == COMMUNITY_PERMIT) { com_index_to_delete[delete_index] = i; delete_index++; } break; } else if ((entry->style == COMMUNITY_LIST_STANDARD) && (community_include (entry->u.com, COMMUNITY_INTERNET) || community_include (entry->u.com, val) )) { if (entry->direct == COMMUNITY_PERMIT) { com_index_to_delete[delete_index] = i; delete_index++; } break; } else if ((entry->style == COMMUNITY_LIST_EXPANDED) && community_regexp_include (entry->reg, com, i)) { if (entry->direct == COMMUNITY_PERMIT) { com_index_to_delete[delete_index] = i; delete_index++; } break; } } } /* Delete all of the communities we flagged for deletion */ for (i = delete_index-1; i >= 0; i--) { val = community_val_get (com, com_index_to_delete[i]); community_del_val (com, &val); } return com; } /* To avoid duplicated entry in the community-list, this function compares specified entry to existing entry. */ static 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 LARGE_COMMUNITY_LIST_STANDARD: if (lcommunity_cmp (entry->u.lcom, new->u.lcom)) return 1; break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: case LARGE_COMMUNITY_LIST_EXPANDED: if (entry->config && new->config && strcmp (entry->config, new->config) == 0) return 1; if (!entry->config && !new->config) return 1; break; default: break; } } return 0; } /* Set community-list. */ int community_list_set (struct community_list_handler *ch, const char *name, const 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, const char *name, const 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; } /* Delete all permitted large communities in the list from com. */ struct lcommunity * lcommunity_list_match_delete (struct lcommunity *lcom, struct community_list *list) { struct community_entry *entry; u_int32_t com_index_to_delete[lcom->size]; u_char *ptr; int delete_index = 0; int i; /* Loop over each lcommunity value and evaluate each against the * community-list. If we need to delete a community value add its index to * com_index_to_delete. */ for (i = 0; i < lcom->size; i++) { ptr = lcom->val + (i * LCOMMUNITY_SIZE); for (entry = list->head; entry; entry = entry->next) { if (entry->any) { if (entry->direct == COMMUNITY_PERMIT) { com_index_to_delete[delete_index] = i; delete_index++; } break; } else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) && lcommunity_include (entry->u.lcom, ptr) ) { if (entry->direct == COMMUNITY_PERMIT) { com_index_to_delete[delete_index] = i; delete_index++; } break; } else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) && entry->reg && lcommunity_regexp_include (entry->reg, lcom, i)) { if (entry->direct == COMMUNITY_PERMIT) { com_index_to_delete[delete_index] = i; delete_index++; } break; } } } /* Delete all of the communities we flagged for deletion */ for (i = delete_index-1; i >= 0; i--) { ptr = lcom->val + (com_index_to_delete[i] * LCOMMUNITY_SIZE); lcommunity_del_val (lcom, ptr); } return lcom; } /* Set lcommunity-list. */ int lcommunity_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, int style) { struct community_entry *entry = NULL; struct community_list *list; struct lcommunity *lcom = NULL; regex_t *regex = NULL; /* Get community list. */ list = community_list_get (ch, name, LARGE_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 == LARGE_COMMUNITY_LIST_STANDARD) lcom = lcommunity_str2com (str); else regex = bgp_regcomp (str); if (! lcom && ! regex) return COMMUNITY_LIST_ERR_MALFORMED_VAL; } entry = community_entry_new (); entry->direct = direct; entry->style = style; entry->any = (str ? 0 : 1); entry->u.lcom = lcom; entry->reg = regex; if (lcom) entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST); else if (regex) entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); else entry->config = 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 lcommunity_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style) { struct community_entry *entry = NULL; struct community_list *list; struct lcommunity *lcom = NULL; regex_t *regex = NULL; /* Lookup community list. */ list = community_list_lookup (ch, name, LARGE_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 == LARGE_COMMUNITY_LIST_STANDARD) lcom = lcommunity_str2com (str); else regex = bgp_regcomp (str); if (! lcom && ! regex) return COMMUNITY_LIST_ERR_MALFORMED_VAL; if (lcom) entry = community_list_entry_lookup (list, lcom, direct); else entry = community_list_entry_lookup (list, str, direct); if (lcom) lcommunity_free (&lcom); 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, const char *name, const 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_COMMUNITY_LIST); 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, const char *name, const 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 (void) { 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->lcommunity_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); } quagga-1.2.4/bgpd/bgp_clist.h000066400000000000000000000125371325323223500160260ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_CLIST_H #define _QUAGGA_BGP_CLIST_H /* Master Community-list. */ #define COMMUNITY_LIST_MASTER 0 #define EXTCOMMUNITY_LIST_MASTER 1 #define LARGE_COMMUNITY_LIST_MASTER 2 /* 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. */ #define LARGE_COMMUNITY_LIST_STANDARD 4 /* Standard Large community-list. */ #define LARGE_COMMUNITY_LIST_EXPANDED 5 /* Expanded Large community-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; struct lcommunity *lcom; } 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; /* Large community-list. */ struct community_list_master lcommunity_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. */ extern struct community_list_handler *community_list_init (void); extern void community_list_terminate (struct community_list_handler *); extern int community_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern int community_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern int extcommunity_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern int extcommunity_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern int lcommunity_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern int lcommunity_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern struct community_list_master * community_list_master_lookup (struct community_list_handler *, int); extern struct community_list * community_list_lookup (struct community_list_handler *, const char *, int); extern int community_list_match (struct community *, struct community_list *); extern int ecommunity_list_match (struct ecommunity *, struct community_list *); extern int lcommunity_list_match (struct lcommunity *, struct community_list *); extern int community_list_exact_match (struct community *, struct community_list *); extern struct community * community_list_match_delete (struct community *, struct community_list *); extern struct lcommunity * lcommunity_list_match_delete (struct lcommunity *lcom, struct community_list *list); #endif /* _QUAGGA_BGP_CLIST_H */ quagga-1.2.4/bgpd/bgp_community.c000066400000000000000000000321141325323223500167200ustar00rootroot00000000000000/* 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. */ static struct hash *comhash; /* Allocate a new communities value. */ static struct community * community_new (void) { 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. */ static 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) memmove (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(). */ static 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; if (!com) return NULL; /* 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, "%u:%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); *com = NULL; } } /* Create new community attribute. */ struct community * community_parse (u_int32_t *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 = 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) return NULL; 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) { unsigned char *pnt = (unsigned char *)com->val; int size = com->size * 4; unsigned int key = 0; int c; for (c = 0; c < size; c += 4) { key += pnt[c]; key += pnt[c + 1]; key += pnt[c + 2]; key += pnt[c + 3]; } return key; } int community_match (const struct community *com1, const 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 (const struct community *com1, const 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. */ static const char * community_gettoken (const char *buf, enum community_token *token, u_int32_t *val) { const 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 NULL; } /* 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 NULL; } 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 NULL; } *val = community_high + community_low; *token = community_token_val; return p; } *token = community_token_unknown; return NULL; } /* convert string to community structure */ struct community * community_str2com (const char *str) { struct community *com = NULL; struct community *com_sort = NULL; u_int32_t val = 0; enum community_token token = community_token_unknown; do { 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; } } while (str); 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 (void) { return comhash->count; } /* Return communities hash. */ struct hash * community_hash (void) { return comhash; } /* Initialize comminity related hash. */ void community_init (void) { comhash = hash_create ((unsigned int (*) (void *))community_hash_make, (int (*) (const void *, const void *))community_cmp); } void community_finish (void) { hash_free (comhash); comhash = NULL; } quagga-1.2.4/bgpd/bgp_community.h000066400000000000000000000056621325323223500167350ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_COMMUNITY_H #define _QUAGGA_BGP_COMMUNITY_H /* 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. */ extern void community_init (void); extern void community_finish (void); extern void community_free (struct community *); extern struct community *community_uniq_sort (struct community *); extern struct community *community_parse (u_int32_t *, u_short); extern struct community *community_intern (struct community *); extern void community_unintern (struct community **); extern char *community_str (struct community *); extern unsigned int community_hash_make (struct community *); extern struct community *community_str2com (const char *); extern int community_match (const struct community *, const struct community *); extern int community_cmp (const struct community *, const struct community *); extern struct community *community_merge (struct community *, struct community *); extern struct community *community_delete (struct community *, struct community *); extern struct community *community_dup (struct community *); extern int community_include (struct community *, u_int32_t); extern void community_del_val (struct community *, u_int32_t *); extern unsigned long community_count (void); extern struct hash *community_hash (void); extern u_int32_t community_val_get (struct community *com, int i); #endif /* _QUAGGA_BGP_COMMUNITY_H */ quagga-1.2.4/bgpd/bgp_damp.c000066400000000000000000000441171325323223500156230ustar00rootroot00000000000000/* 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 "filter.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; static 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) { unsigned 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) { unsigned 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. */ static int bgp_reuse_timer (struct thread *t) { struct bgp_damp_info *bdi; struct bgp_damp_info *next; time_t t_now, t_diff; damp->t_reuse = NULL; damp->t_reuse = thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE); t_now = bgp_clock (); /* 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) { struct bgp *bgp = bdi->binfo->peer->bgp; 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. */ bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_DAMPED); bdi->suppress_time = 0; if (bdi->lastrecord == BGP_RECORD_UPDATE) { bgp_info_unset_flag (bdi->rn, bdi->binfo, 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 = NULL; double last_penalty = 0; t_now = bgp_clock (); /* Processing Unreachable Messages. */ if (binfo->extra) bdi = binfo->extra->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; (bgp_info_extra_get (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++; } assert ((rn == bdi->rn) && (binfo == bdi->binfo)); bdi->lastrecord = BGP_RECORD_WITHDRAW; bdi->t_updated = t_now; /* Make this route as historical status. */ bgp_info_set_flag (rn, binfo, 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) { bgp_info_set_flag (rn, binfo, 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; if (!binfo->extra || !((bdi = binfo->extra->damp_info))) return BGP_DAMP_USED; t_now = bgp_clock (); bgp_info_unset_flag (rn, binfo, 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) ) { bgp_info_unset_flag (rn, binfo, 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; assert (binfo->extra && binfo->extra->damp_info); t_now = bgp_clock (); bdi = binfo->extra->damp_info; if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) { t_diff = t_now - bdi->suppress_time; if (t_diff >= damp->max_suppress_time) { bgp_info_unset_flag (bdi->rn, binfo, 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; if (! bdi) return; binfo = bdi->binfo; binfo->extra->damp_info = NULL; if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) bgp_reuse_list_delete (bdi); else BGP_DAMP_LIST_DEL (damp, bdi); bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_HISTORY|BGP_INFO_DAMPED); if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) bgp_info_delete (bdi->rn, binfo); XFREE (MTYPE_BGP_DAMP_INFO, bdi); } static void bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup) { double reuse_max_ratio; unsigned 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 *)); /* Reuse-array computations */ damp->reuse_index = XCALLOC (MTYPE_BGP_DAMP_ARRAY, sizeof(int) * damp->reuse_index_size); 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, time_t half, unsigned int reuse, unsigned int suppress, time_t 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 (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE); return 0; } static 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 (void) { unsigned 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) { /* If it wasn't enabled, there's nothing to do. */ if (! CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) return 0; /* 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; } void bgp_config_write_damp (struct vty *vty) { 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 %lld%s", bgp_damp_cfg.half_life/60LL, VTY_NEWLINE); else vty_out (vty, " bgp dampening %lld %d %d %lld%s", bgp_damp_cfg.half_life/60LL, bgp_damp_cfg.reuse_limit, bgp_damp_cfg.suppress_value, bgp_damp_cfg.max_suppress_time/60LL, VTY_NEWLINE); } static const char * bgp_get_reuse_time (unsigned 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; if (!binfo->extra) return; /* BGP dampening information. */ bdi = binfo->extra->damp_info; /* If dampening is not enabled or there is no dampening information, return immediately. */ if (! damp || ! bdi) return; /* Calculate new penalty. */ t_now = bgp_clock (); 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); } const char * bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo, char *timebuf, size_t len) { struct bgp_damp_info *bdi; time_t t_now, t_diff; int penalty; if (!binfo->extra) return NULL; /* BGP dampening information. */ bdi = binfo->extra->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 = bgp_clock (); t_diff = t_now - bdi->t_updated; penalty = bgp_damp_decay (t_diff, bdi->penalty); return bgp_get_reuse_time (penalty, timebuf, len); } int bgp_show_dampening_parameters (struct vty *vty, afi_t afi, safi_t safi) { struct bgp *bgp; bgp = bgp_get_default(); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { vty_out (vty, "Half-life time: %ld min%s", damp->half_life / 60, VTY_NEWLINE); vty_out (vty, "Reuse penalty: %d%s", damp->reuse_limit, VTY_NEWLINE); vty_out (vty, "Suppress penalty: %d%s", damp->suppress_value, VTY_NEWLINE); vty_out (vty, "Max suppress time: %ld min%s", damp->max_suppress_time / 60, VTY_NEWLINE); vty_out (vty, "Max suppress penalty: %u%s", damp->ceiling, VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); } else vty_out (vty, "dampening not enabled for %s%s", afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); return CMD_SUCCESS; } quagga-1.2.4/bgpd/bgp_damp.h000066400000000000000000000107321325323223500156240ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_DAMP_H #define _QUAGGA_BGP_DAMP_H /* 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. */ unsigned int penalty; /* Number of flapping. */ unsigned 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 1U #define BGP_RECORD_WITHDRAW 2U afi_t afi; safi_t safi; }; /* Specified parameter set configuration. */ struct bgp_damp_config { /* Value over which routes suppressed. */ unsigned int suppress_value; /* Value below which suppressed routes reused. */ unsigned int reuse_limit; /* Max time a route can be suppressed. */ time_t max_suppress_time; /* Time during which accumulated penalty reduces by half. */ time_t half_life; /* Non-configurable parameters but fixed at implementation time. * To change this values, init_bgp_damp() should be modified. */ time_t tmax; /* Max time previous instability retained */ unsigned int reuse_list_size; /* Number of reuse lists */ unsigned 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 */ unsigned int decay_rate_per_tick; /* Calculated from half-life */ unsigned int decay_array_size; /* Calculated using config parameters */ double scale_factor; unsigned 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 extern int bgp_damp_enable (struct bgp *, afi_t, safi_t, time_t, unsigned int, unsigned int, time_t); extern int bgp_damp_disable (struct bgp *, afi_t, safi_t); extern int bgp_damp_withdraw (struct bgp_info *, struct bgp_node *, afi_t, safi_t, int); extern int bgp_damp_update (struct bgp_info *, struct bgp_node *, afi_t, safi_t); extern int bgp_damp_scan (struct bgp_info *, afi_t, safi_t); extern void bgp_damp_info_free (struct bgp_damp_info *, int); extern void bgp_damp_info_clean (void); extern int bgp_damp_decay (time_t, int); extern void bgp_config_write_damp (struct vty *); extern void bgp_damp_info_vty (struct vty *, struct bgp_info *); extern const char * bgp_damp_reuse_time_vty (struct vty *, struct bgp_info *, char *, size_t); extern int bgp_show_dampening_parameters (struct vty *vty, afi_t, safi_t); #endif /* _QUAGGA_BGP_DAMP_H */ quagga-1.2.4/bgpd/bgp_debug.c000066400000000000000000000722561325323223500157750ustar00rootroot00000000000000/* 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 #include "prefix.h" #include "linklist.h" #include "stream.h" #include "command.h" #include "str.h" #include "log.h" #include "sockunion.h" #include "filter.h" #include "memory.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" unsigned long conf_bgp_debug_as4; 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 conf_bgp_debug_zebra; unsigned long conf_bgp_debug_allow_martians; unsigned long conf_bgp_debug_nht; unsigned long term_bgp_debug_as4; 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; unsigned long term_bgp_debug_zebra; unsigned long term_bgp_debug_allow_martians; unsigned long term_bgp_debug_nht; /* messages for BGP-4 status */ const struct message bgp_status_msg[] = { { Idle, "Idle" }, { Connect, "Connect" }, { Active, "Active" }, { OpenSent, "OpenSent" }, { OpenConfirm, "OpenConfirm" }, { Established, "Established" }, { Clearing, "Clearing" }, { Deleted, "Deleted" }, }; #define BGP_DEBUG_MSG_MAX(msg) const int msg ## _max = array_size (msg) BGP_DEBUG_MSG_MAX (bgp_status_msg); /* BGP message type string. */ const char *bgp_type_str[] = { NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE", "ROUTE-REFRESH", "CAPABILITY", NULL, }; /* message for BGP-4 Notify */ static const struct message bgp_notify_msg[] = { { 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"}, }; BGP_DEBUG_MSG_MAX (bgp_notify_msg); static const struct message bgp_notify_head_msg[] = { { BGP_NOTIFY_HEADER_NOT_SYNC, "/Connection Not Synchronized"}, { BGP_NOTIFY_HEADER_BAD_MESLEN, "/Bad Message Length"}, { BGP_NOTIFY_HEADER_BAD_MESTYPE, "/Bad Message Type"}, }; BGP_DEBUG_MSG_MAX (bgp_notify_head_msg); static const struct message bgp_notify_open_msg[] = { { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { 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"}, }; BGP_DEBUG_MSG_MAX (bgp_notify_open_msg); static const struct message bgp_notify_update_msg[] = { { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { 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"}, }; BGP_DEBUG_MSG_MAX (bgp_notify_update_msg); static const struct message bgp_notify_cease_msg[] = { { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { 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_COLLISION_RESOLUTION, "/Connection collision resolution"}, { BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resource"}, }; BGP_DEBUG_MSG_MAX (bgp_notify_cease_msg); static const struct message bgp_notify_capability_msg[] = { { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value" }, { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"}, { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"}, }; BGP_DEBUG_MSG_MAX (bgp_notify_capability_msg); /* Origin strings. */ const char *bgp_origin_str[] = {"i","e","?"}; const 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]); if (attr->extra) { char addrbuf[BUFSIZ]; /* Add MP case. */ if (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, addrbuf, BUFSIZ)); if (attr->extra->mp_nexthop_len == 32) snprintf (buf + strlen (buf), size - strlen (buf), "(%s)", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, addrbuf, BUFSIZ)); } 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_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 %u %s", attr->extra->aggregator_as, inet_ntoa (attr->extra->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->extra->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->extra->cluster->length / 4; i++) snprintf (buf + strlen (buf), size - strlen (buf), " %s", inet_ntoa (attr->extra->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, const char *direct) { const char *subcode_str; const char *code_str; subcode_str = ""; code_str = LOOKUP_DEF (bgp_notify_msg, bgp_notify->code, "Unrecognized Error Code"); switch (bgp_notify->code) { case BGP_NOTIFY_HEADER_ERR: subcode_str = LOOKUP_DEF (bgp_notify_head_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; case BGP_NOTIFY_OPEN_ERR: subcode_str = LOOKUP_DEF (bgp_notify_open_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; case BGP_NOTIFY_UPDATE_ERR: subcode_str = LOOKUP_DEF (bgp_notify_update_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; case BGP_NOTIFY_HOLD_ERR: break; case BGP_NOTIFY_FSM_ERR: break; case BGP_NOTIFY_CEASE: subcode_str = LOOKUP_DEF (bgp_notify_cease_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; case BGP_NOTIFY_CAPABILITY_ERR: subcode_str = LOOKUP_DEF (bgp_notify_capability_msg, bgp_notify->subcode, "Unrecognized Error 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, code_str, subcode_str, bgp_notify->length, bgp_notify->data ? bgp_notify->data : ""); else if (BGP_DEBUG (normal, NORMAL)) plog_debug (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s", peer ? peer->host : "", direct, bgp_notify->code, bgp_notify->subcode, code_str, 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_as4, debug_bgp_as4_cmd, "debug bgp as4", DEBUG_STR BGP_STR "BGP AS4 actions\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (as4, AS4); else { TERM_DEBUG_ON (as4, AS4); vty_out (vty, "BGP as4 debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_as4, no_debug_bgp_as4_cmd, "no debug bgp as4", NO_STR DEBUG_STR BGP_STR "BGP AS4 actions\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (as4, AS4); else { TERM_DEBUG_OFF (as4, AS4); vty_out (vty, "BGP as4 debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_as4, undebug_bgp_as4_cmd, "undebug bgp as4", UNDEBUG_STR BGP_STR "BGP AS4 actions\n") DEFUN (debug_bgp_as4_segment, debug_bgp_as4_segment_cmd, "debug bgp as4 segment", DEBUG_STR BGP_STR "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (as4, AS4_SEGMENT); else { TERM_DEBUG_ON (as4, AS4_SEGMENT); vty_out (vty, "BGP as4 segment debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_as4_segment, no_debug_bgp_as4_segment_cmd, "no debug bgp as4 segment", NO_STR DEBUG_STR BGP_STR "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (as4, AS4_SEGMENT); else { TERM_DEBUG_OFF (as4, AS4_SEGMENT); vty_out (vty, "BGP as4 segment debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_as4_segment, undebug_bgp_as4_segment_cmd, "undebug bgp as4 segment", UNDEBUG_STR BGP_STR "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") 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 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_nht, debug_bgp_nht_cmd, "debug bgp nht", DEBUG_STR BGP_STR "BGP nexthop tracking events\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (nht, NHT); else { TERM_DEBUG_ON (nht, NHT); vty_out (vty, "BGP nexthop tracking debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_nht, no_debug_bgp_nht_cmd, "no debug bgp nht", NO_STR DEBUG_STR BGP_STR "BGP nexthop tracking events\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (nht, NHT); else { TERM_DEBUG_OFF (nht, NHT); vty_out (vty, "BGP nexthop tracking debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_nht, undebug_bgp_nht_cmd, "undebug bgp nht", UNDEBUG_STR BGP_STR "BGP next-hop tracking updates\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 (debug_bgp_zebra, debug_bgp_zebra_cmd, "debug bgp zebra", DEBUG_STR BGP_STR "BGP Zebra messages\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (zebra, ZEBRA); else { TERM_DEBUG_ON (zebra, ZEBRA); vty_out (vty, "BGP zebra debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_zebra, no_debug_bgp_zebra_cmd, "no debug bgp zebra", NO_STR DEBUG_STR BGP_STR "BGP Zebra messages\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (zebra, ZEBRA); else { TERM_DEBUG_OFF (zebra, ZEBRA); vty_out (vty, "BGP zebra debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_zebra, undebug_bgp_zebra_cmd, "undebug bgp zebra", UNDEBUG_STR BGP_STR "BGP Zebra messages\n") DEFUN (debug_bgp_allow_martians, debug_bgp_allow_martians_cmd, "debug bgp allow-martians", DEBUG_STR BGP_STR "BGP allow martian next hops\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (allow_martians, ALLOW_MARTIANS); else { TERM_DEBUG_ON (allow_martians, ALLOW_MARTIANS); vty_out (vty, "BGP allow_martian next hop debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_allow_martians, no_debug_bgp_allow_martians_cmd, "no debug bgp allow-martians", NO_STR DEBUG_STR BGP_STR "BGP allow martian next hops\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (allow_martians, ALLOW_MARTIANS); else { TERM_DEBUG_OFF (allow_martians, ALLOW_MARTIANS); vty_out (vty, "BGP allow martian next hop debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_allow_martians, undebug_bgp_allow_martians_cmd, "undebug bgp allow-martians", UNDEBUG_STR BGP_STR "BGP allow martian next hops\n") 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 (as4, AS4); TERM_DEBUG_OFF (as4, AS4_SEGMENT); TERM_DEBUG_OFF (fsm, FSM); TERM_DEBUG_OFF (filter, FILTER); TERM_DEBUG_OFF (zebra, ZEBRA); TERM_DEBUG_OFF (allow_martians, ALLOW_MARTIANS); 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); if (BGP_DEBUG (zebra, ZEBRA)) vty_out (vty, " BGP zebra debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (as4, AS4)) vty_out (vty, " BGP as4 debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (as4, AS4_SEGMENT)) vty_out (vty, " BGP as4 aspath segment debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) vty_out (vty, " BGP allow martian next hop debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (nht, NHT)) vty_out (vty, " BGP next-hop tracking debugging is on%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } static 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 (as4, AS4)) { vty_out (vty, "debug bgp as4%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (as4, AS4_SEGMENT)) { vty_out (vty, "debug bgp as4 segment%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++; } if (CONF_BGP_DEBUG (zebra, ZEBRA)) { vty_out (vty, "debug bgp zebra%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) { vty_out (vty, "debug bgp allow-martians%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (nht, NHT)) { vty_out (vty, "debug bgp nht%s", VTY_NEWLINE); write++; } return write; } static struct cmd_node debug_node = { DEBUG_NODE, "", 1 }; void bgp_debug_init (void) { install_node (&debug_node, bgp_config_write_debug); install_element (ENABLE_NODE, &show_debugging_bgp_cmd); install_element (ENABLE_NODE, &debug_bgp_as4_cmd); install_element (CONFIG_NODE, &debug_bgp_as4_cmd); install_element (ENABLE_NODE, &debug_bgp_as4_segment_cmd); install_element (CONFIG_NODE, &debug_bgp_as4_segment_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_nht_cmd); install_element (CONFIG_NODE, &debug_bgp_nht_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, &debug_bgp_zebra_cmd); install_element (CONFIG_NODE, &debug_bgp_zebra_cmd); install_element (ENABLE_NODE, &debug_bgp_allow_martians_cmd); install_element (CONFIG_NODE, &debug_bgp_allow_martians_cmd); install_element (ENABLE_NODE, &no_debug_bgp_as4_cmd); install_element (ENABLE_NODE, &undebug_bgp_as4_cmd); install_element (CONFIG_NODE, &no_debug_bgp_as4_cmd); install_element (ENABLE_NODE, &no_debug_bgp_as4_segment_cmd); install_element (ENABLE_NODE, &undebug_bgp_as4_segment_cmd); install_element (CONFIG_NODE, &no_debug_bgp_as4_segment_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_nht_cmd); install_element (ENABLE_NODE, &undebug_bgp_nht_cmd); install_element (CONFIG_NODE, &no_debug_bgp_nht_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_zebra_cmd); install_element (ENABLE_NODE, &undebug_bgp_zebra_cmd); install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd); install_element (ENABLE_NODE, &no_debug_bgp_allow_martians_cmd); install_element (ENABLE_NODE, &undebug_bgp_allow_martians_cmd); install_element (CONFIG_NODE, &no_debug_bgp_allow_martians_cmd); install_element (ENABLE_NODE, &no_debug_bgp_all_cmd); install_element (ENABLE_NODE, &undebug_bgp_all_cmd); } quagga-1.2.4/bgpd/bgp_debug.h000066400000000000000000000101431325323223500157650ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_DEBUG_H #define _QUAGGA_BGP_DEBUG_H #include "bgp_attr.h" /* 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. */ extern void bgp_debug_init (void); extern void bgp_packet_dump (struct stream *); extern int debug (unsigned int option); extern unsigned long conf_bgp_debug_as4; 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 conf_bgp_debug_zebra; extern unsigned long conf_bgp_debug_allow_martians; extern unsigned long conf_bgp_debug_nht; extern unsigned long term_bgp_debug_as4; 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; extern unsigned long term_bgp_debug_zebra; extern unsigned long term_bgp_debug_allow_martians; extern unsigned long term_bgp_debug_nht; #define BGP_DEBUG_AS4 0x01 #define BGP_DEBUG_AS4_SEGMENT 0x02 #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_ZEBRA 0x01 #define BGP_DEBUG_ALLOW_MARTIANS 0x01 #define BGP_DEBUG_NHT 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 const char *bgp_type_str[]; extern int bgp_dump_attr (struct peer *, struct attr *, char *, size_t); extern void bgp_notify_print (struct peer *, struct bgp_notify *, const char *); extern const struct message bgp_status_msg[]; extern const int bgp_status_msg_max; #endif /* _QUAGGA_BGP_DEBUG_H */ quagga-1.2.4/bgpd/bgp_dump.c000066400000000000000000000535201325323223500156450ustar00rootroot00000000000000/* 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 "linklist.h" #include "filter.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_ALL_ET, BGP_DUMP_UPDATES, BGP_DUMP_UPDATES_ET, BGP_DUMP_ROUTES }; static const struct bgp_dump_type_map { enum bgp_dump_type type; const char *str; } bgp_dump_type_map[] = { {BGP_DUMP_ALL, "all"}, {BGP_DUMP_ALL_ET, "all-et"}, {BGP_DUMP_UPDATES, "updates"}, {BGP_DUMP_UPDATES_ET, "updates-et"}, {BGP_DUMP_ROUTES, "routes-mrt"}, {0, NULL}, }; 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 */ MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */ }; struct bgp_dump { enum bgp_dump_type type; char *filename; FILE *fp; unsigned int interval; char *interval_str; struct thread *t_interval; }; static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump); static int bgp_dump_interval_func (struct thread *); /* 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; static FILE * bgp_dump_open_file (struct bgp_dump *bgp_dump) { int ret; time_t clock; struct tm *tm; char fullpath[MAXPATHLEN]; char realpath[MAXPATHLEN]; mode_t oldumask; 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); oldumask = umask(0777 & ~LOGFILE_MASK); bgp_dump->fp = fopen (realpath, "w"); if (bgp_dump->fp == NULL) { zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno)); umask(oldumask); return NULL; } umask(oldumask); return bgp_dump->fp; } static int bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval) { int secs_into_day; time_t t; struct tm *tm; if (interval > 0) { /* Periodic dump every interval seconds */ if ((interval < 86400) && ((86400 % interval) == 0)) { /* Dump at predictable times: if a day has a whole number of * intervals, dump every interval seconds starting from midnight */ (void) time(&t); tm = localtime(&t); secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour; interval = interval - secs_into_day % interval; /* always > 0 */ } bgp_dump->t_interval = thread_add_timer (bm->master, bgp_dump_interval_func, bgp_dump, interval); } else { /* One-off dump: execute immediately, don't affect any scheduled dumps */ bgp_dump->t_interval = thread_add_event (bm->master, bgp_dump_interval_func, bgp_dump, 0); } return 0; } /* Dump common header. */ static void bgp_dump_header (struct stream *obuf, int type, int subtype, int dump_type) { struct timeval clock; long msecs; time_t secs; if ((dump_type == BGP_DUMP_ALL_ET || dump_type == BGP_DUMP_UPDATES_ET) && type == MSG_PROTOCOL_BGP4MP) type = MSG_PROTOCOL_BGP4MP_ET; gettimeofday(&clock, NULL); secs = clock.tv_sec; msecs = clock.tv_usec; /* Put dump packet header. */ stream_putl (obuf, secs); stream_putw (obuf, type); stream_putw (obuf, subtype); stream_putl (obuf, 0); /* len */ /* Adding microseconds for the MRT Extended Header */ if (type == MSG_PROTOCOL_BGP4MP_ET) stream_putl (obuf, msecs); } static void bgp_dump_set_size (struct stream *s, int type) { /* * The BGP_DUMP_HEADER_SIZE stay at 12 event when ET: * "The Microsecond Timestamp is included in the computation * of the Length field value." (RFC6396 2011) */ stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE); } static void bgp_dump_routes_index_table(struct bgp *bgp) { struct peer *peer; struct listnode *node; uint16_t peerno = 1; struct stream *obuf; obuf = bgp_dump_obuf; stream_reset (obuf); /* MRT header */ bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE, BGP_DUMP_ROUTES); /* Collector BGP ID */ stream_put_in_addr (obuf, &bgp->router_id); /* View name */ if(bgp->name) { stream_putw (obuf, strlen(bgp->name)); stream_put(obuf, bgp->name, strlen(bgp->name)); } else { stream_putw(obuf, 0); } /* Peer count ( plus one extra internal peer ) */ stream_putw (obuf, listcount(bgp->peer) + 1); /* Populate fake peer at index 0, for locally originated routes */ /* Peer type (IPv4) */ stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP); /* Peer BGP ID (0.0.0.0) */ stream_putl (obuf, 0); /* Peer IP address (0.0.0.0) */ stream_putl (obuf, 0); /* Peer ASN (0) */ stream_putl (obuf, 0); /* Walk down all peers */ for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { /* Peer's type */ if (sockunion_family(&peer->su) == AF_INET) { stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP); } else if (sockunion_family(&peer->su) == AF_INET6) { stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6); } /* Peer's BGP ID */ stream_put_in_addr (obuf, &peer->remote_id); /* Peer's IP address */ if (sockunion_family(&peer->su) == AF_INET) { stream_put_in_addr (obuf, &peer->su.sin.sin_addr); } else if (sockunion_family(&peer->su) == AF_INET6) { stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); } /* Peer's AS number. */ /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */ stream_putl (obuf, peer->as); /* Store the peer number for this peer */ peer->table_dump_index = peerno; peerno++; } bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); fflush (bgp_dump_routes.fp); } static struct bgp_info * bgp_dump_route_node_record (int afi, struct bgp_node *rn, struct bgp_info *info, unsigned int seq) { struct stream *obuf; size_t sizep; size_t endp; obuf = bgp_dump_obuf; stream_reset (obuf); /* MRT header */ if (afi == AFI_IP) bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST, BGP_DUMP_ROUTES); else if (afi == AFI_IP6) bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST, BGP_DUMP_ROUTES); /* Sequence number */ stream_putl (obuf, seq); /* Prefix length */ stream_putc (obuf, rn->p.prefixlen); /* Prefix */ if (afi == AFI_IP) { /* We'll dump only the useful bits (those not 0), but have to * align on 8 bits */ stream_write (obuf, (u_char *) &rn->p.u.prefix4, (rn->p.prefixlen + 7) / 8); } else if (afi == AFI_IP6) { /* We'll dump only the useful bits (those not 0), but have to * align on 8 bits */ stream_write (obuf, (u_char *) &rn->p.u.prefix6, (rn->p.prefixlen + 7) / 8); } /* Save where we are now, so we can overwride the entry count later */ sizep = stream_get_endp (obuf); /* Entry count */ uint16_t entry_count = 0; /* Entry count, note that this is overwritten later */ stream_putw (obuf, 0); endp = stream_get_endp (obuf); for (; info; info = info->next) { size_t cur_endp; /* Peer index */ stream_putw (obuf, info->peer->table_dump_index); /* Originated */ #ifdef HAVE_CLOCK_MONOTONIC stream_putl (obuf, time (NULL) - (bgp_clock () - info->uptime)); #else stream_putl (obuf, info->uptime); #endif /* HAVE_CLOCK_MONOTONIC */ /* Dump attribute. */ /* Skip prefix & AFI/SAFI for MP_NLRI */ bgp_dump_routes_attr (obuf, info->attr, &rn->p); cur_endp = stream_get_endp (obuf); if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE) { stream_set_endp (obuf, endp); break; } entry_count++; endp = cur_endp; } /* Overwrite the entry count, now that we know the right number */ stream_putw_at (obuf, sizep, entry_count); bgp_dump_set_size (obuf, MSG_TABLE_DUMP_V2); fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); return info; } /* Runs under child process. */ static unsigned int bgp_dump_routes_func (int afi, int first_run, unsigned int seq) { struct bgp_info *info; struct bgp_node *rn; struct bgp *bgp; struct bgp_table *table; bgp = bgp_get_default (); if (!bgp) return seq; if (bgp_dump_routes.fp == NULL) return seq; /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers, so this should only be done on the first call to bgp_dump_routes_func. ( this function will be called once for ipv4 and once for ipv6 ) */ if(first_run) bgp_dump_routes_index_table(bgp); /* Walk down each BGP route. */ table = bgp->rib[afi][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { info = rn->info; while (info) { info = bgp_dump_route_node_record(afi, rn, info, seq); seq++; } } fflush (bgp_dump_routes.fp); return seq; } static int bgp_dump_interval_func (struct thread *t) { struct bgp_dump *bgp_dump; bgp_dump = THREAD_ARG (t); bgp_dump->t_interval = NULL; /* Reschedule dump even if file couldn't be opened this time... */ if (bgp_dump_open_file (bgp_dump) != NULL) { /* In case of bgp_dump_routes, we need special route dump function. */ if (bgp_dump->type == BGP_DUMP_ROUTES) { unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0); bgp_dump_routes_func (AFI_IP6, 0, seq); /* Close the file now. For a RIB dump there's no point in leaving * it open until the next scheduled dump starts. */ fclose(bgp_dump->fp); bgp_dump->fp = NULL; } } /* if interval is set reschedule */ if (bgp_dump->interval > 0) bgp_dump_interval_add (bgp_dump, bgp_dump->interval); return 0; } /* Dump common information. */ static void bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4) { 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. */ if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) { stream_putl (obuf, peer->as); stream_putl (obuf, peer->local_as); } else { stream_putw (obuf, peer->as); stream_putw (obuf, peer->local_as); } if (peer->su.sa.sa_family == AF_INET) { 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); } else if (peer->su.sa.sa_family == AF_INET6) { /* 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); } } /* 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_AS4, bgp_dump_all.type); bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/ 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_endp (obuf), 1, bgp_dump_all.fp); fflush (bgp_dump_all.fp); } static 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. */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) { bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4, bgp_dump->type); } else { bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE, bgp_dump->type); } bgp_dump_common (obuf, peer, 0); /* 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_endp (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); } static unsigned int bgp_dump_parse_time (const 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; } static int bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, enum bgp_dump_type type, const char *path, const char *interval_str) { unsigned int interval; /* Don't schedule duplicate dumps if the dump command is given twice */ if (bgp_dump->filename && strcmp(path, bgp_dump->filename) == 0 && type == bgp_dump->type) { if (interval_str) { if (bgp_dump->interval_str && strcmp(bgp_dump->interval_str, interval_str) == 0) return CMD_SUCCESS; } else { if (!bgp_dump->interval_str) return CMD_SUCCESS; } } /* Removing previous config */ bgp_dump_unset(vty, bgp_dump); if (interval_str) { /* 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; } /* Setting interval string */ bgp_dump->interval_str = strdup (interval_str); } else { interval = 0; } /* Set type. */ bgp_dump->type = type; /* Set interval */ bgp_dump->interval = interval; /* Set file name. */ bgp_dump->filename = strdup (path); /* Create interval thread. */ bgp_dump_interval_add (bgp_dump, interval); /* This should be called when interval is expired. */ bgp_dump_open_file (bgp_dump); return CMD_SUCCESS; } static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump) { /* Removing file name. */ if (bgp_dump->filename) { free (bgp_dump->filename); bgp_dump->filename = NULL; } /* Closing file. */ if (bgp_dump->fp) { fclose (bgp_dump->fp); bgp_dump->fp = NULL; } /* Removing interval thread. */ if (bgp_dump->t_interval) { thread_cancel (bgp_dump->t_interval); bgp_dump->t_interval = NULL; } bgp_dump->interval = 0; /* Removing interval string. */ 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|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]", "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\nDump all BGP packets (Extended Tiemstamp Header)\n" "Dump BGP updates only\nDump BGP updates only (Extended Tiemstamp Header)\n" "Dump whole BGP routing table\n" "Output filename\n" "Interval of output\n") { int bgp_dump_type = 0; const char *interval = NULL; struct bgp_dump *bgp_dump_struct = NULL; const struct bgp_dump_type_map *map = NULL; for (map = bgp_dump_type_map; map->str; map++) if (strcmp(argv[0], map->str) == 0) bgp_dump_type = map->type; switch (bgp_dump_type) { case BGP_DUMP_ALL: case BGP_DUMP_ALL_ET: bgp_dump_struct = &bgp_dump_all; break; case BGP_DUMP_UPDATES: case BGP_DUMP_UPDATES_ET: bgp_dump_struct = &bgp_dump_updates; break; case BGP_DUMP_ROUTES: default: bgp_dump_struct = &bgp_dump_routes; break; } /* When an interval is given */ if (argc == 3) interval = argv[2]; return bgp_dump_set (vty, bgp_dump_struct, bgp_dump_type, argv[1], interval); } DEFUN (no_dump_bgp_all, no_dump_bgp_all_cmd, "no dump bgp (all|updates|routes-mrt) [PATH] [INTERVAL]", NO_STR "Stop dump packet\n" "Stop BGP packet dump\n" "Stop dump process all/all-et\n" "Stop dump process updates/updates-et\n" "Stop dump process route-mrt\n") { return bgp_dump_unset (vty, &bgp_dump_all); } /* BGP node structure. */ static struct cmd_node bgp_dump_node = { DUMP_NODE, "", 1 }; #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 static int config_write_bgp_dump (struct vty *vty) { if (bgp_dump_all.filename) { const char *type_str = "all"; if (bgp_dump_all.type == BGP_DUMP_ALL_ET) type_str = "all-et"; if (bgp_dump_all.interval_str) vty_out (vty, "dump bgp %s %s %s%s", type_str, bgp_dump_all.filename, bgp_dump_all.interval_str, VTY_NEWLINE); else vty_out (vty, "dump bgp %s %s%s", type_str, bgp_dump_all.filename, VTY_NEWLINE); } if (bgp_dump_updates.filename) { const char *type_str = "updates"; if (bgp_dump_updates.type == BGP_DUMP_UPDATES_ET) type_str = "updates-et"; if (bgp_dump_updates.interval_str) vty_out (vty, "dump bgp %s %s %s%s", type_str, 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); } return 0; } /* Initialize BGP packet dump functionality. */ void bgp_dump_init (void) { 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 << 1) + BGP_DUMP_MSG_HEADER + 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, &no_dump_bgp_all_cmd); } void bgp_dump_finish (void) { stream_free (bgp_dump_obuf); bgp_dump_obuf = NULL; } quagga-1.2.4/bgpd/bgp_dump.h000066400000000000000000000036271325323223500156550ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_DUMP_H #define _QUAGGA_BGP_DUMP_H /* MRT compatible packet dump values. */ /* type value */ #define MSG_PROTOCOL_BGP4MP 16 #define MSG_PROTOCOL_BGP4MP_ET 17 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 #define BGP4MP_ENTRY 2 #define BGP4MP_SNAPSHOT 3 #define BGP4MP_MESSAGE_AS4 4 #define BGP4MP_STATE_CHANGE_AS4 5 #define BGP_DUMP_HEADER_SIZE 12 #define BGP_DUMP_MSG_HEADER 40 #define TABLE_DUMP_V2_PEER_INDEX_TABLE 1 #define TABLE_DUMP_V2_RIB_IPV4_UNICAST 2 #define TABLE_DUMP_V2_RIB_IPV4_MULTICAST 3 #define TABLE_DUMP_V2_RIB_IPV6_UNICAST 4 #define TABLE_DUMP_V2_RIB_IPV6_MULTICAST 5 #define TABLE_DUMP_V2_RIB_GENERIC 6 #define TABLE_DUMP_V2_PEER_INDEX_TABLE_IP 0 #define TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6 1 #define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS2 0 #define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4 2 extern void bgp_dump_init (void); extern void bgp_dump_finish (void); extern void bgp_dump_state (struct peer *, int, int); extern void bgp_dump_packet (struct peer *, int, struct stream *); #endif /* _QUAGGA_BGP_DUMP_H */ quagga-1.2.4/bgpd/bgp_ecommunity.c000066400000000000000000000431561325323223500170750ustar00rootroot00000000000000/* 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 "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_aspath.h" /* Hash of community attribute. */ static struct hash *ecomhash; /* Allocate a new ecommunities. */ static struct ecommunity * ecommunity_new (void) { 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); ecom = NULL; } /* 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_int8_t *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 Extended 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 (u_int8_t *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 (void *arg) { const struct ecommunity *ecom = arg; int size = ecom->size * ECOMMUNITY_SIZE; u_int8_t *pnt = ecom->val; unsigned int key = 0; int c; for (c = 0; c < size; c += ECOMMUNITY_SIZE) { key += pnt[c]; key += pnt[c + 1]; key += pnt[c + 2]; key += pnt[c + 3]; key += pnt[c + 4]; key += pnt[c + 5]; key += pnt[c + 6]; key += pnt[c + 7]; } return key; } /* Compare two Extended Communities Attribute structure. */ int ecommunity_cmp (const void *arg1, const void *arg2) { const struct ecommunity *ecom1 = arg1; const struct ecommunity *ecom2 = arg2; return (ecom1->size == ecom2->size && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0); } /* Initialize Extended Comminities related hash. */ void ecommunity_init (void) { ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp); } void ecommunity_finish (void) { hash_free (ecomhash); ecomhash = NULL; } /* Extended Communities token enum. */ enum ecommunity_token { ecommunity_token_unknown = 0, ecommunity_token_rt, ecommunity_token_soo, ecommunity_token_val, }; /* Get next Extended Communities token from the string. */ static const char * ecommunity_gettoken (const char *str, struct ecommunity_val *eval, enum ecommunity_token *token) { int ret; int dot = 0; int digit = 0; int separator = 0; const char *p = str; char *endptr; struct in_addr ip; as_t as = 0; u_int32_t val = 0; char buf[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; } /* What a mess, there are several possibilities: * * a) A.B.C.D:MN * b) EF:OPQR * c) GHJK:MN * * A.B.C.D: Four Byte IP * EF: Two byte ASN * GHJK: Four-byte ASN * MN: Two byte value * OPQR: Four byte value * */ while (isdigit ((int) *p) || *p == ':' || *p == '.') { if (*p == ':') { if (separator) goto error; separator = 1; digit = 0; if ((p - str) > INET_ADDRSTRLEN) goto error; memset (buf, 0, INET_ADDRSTRLEN + 1); memcpy (buf, str, p - str); if (dot) { /* Parsing A.B.C.D in: * A.B.C.D:MN */ ret = inet_aton (buf, &ip); if (ret == 0) goto error; } else { /* ASN */ as = strtoul (buf, &endptr, 10); if (*endptr != '\0' || as == BGP_AS4_MAX) goto error; } } else if (*p == '.') { if (separator) goto error; dot++; if (dot > 4) goto error; } else { digit = 1; /* We're past the IP/ASN part */ if (separator) { val *= 10; val += (*p - '0'); } } p++; } /* Low digit part must be there. */ if (!digit || !separator) goto error; /* Encode result into routing distinguisher. */ if (dot) { if (val > UINT16_MAX) goto error; eval->val[0] = ECOMMUNITY_ENCODE_IP; eval->val[1] = 0; memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); eval->val[6] = (val >> 8) & 0xff; eval->val[7] = val & 0xff; } else if (as > BGP_AS_MAX) { if (val > UINT16_MAX) goto error; eval->val[0] = ECOMMUNITY_ENCODE_AS4; eval->val[1] = 0; eval->val[2] = (as >>24) & 0xff; eval->val[3] = (as >>16) & 0xff; eval->val[4] = (as >>8) & 0xff; eval->val[5] = as & 0xff; eval->val[6] = (val >> 8) & 0xff; eval->val[7] = val & 0xff; } else { eval->val[0] = ECOMMUNITY_ENCODE_AS; eval->val[1] = 0; eval->val[2] = (as >>8) & 0xff; eval->val[3] = as & 0xff; eval->val[4] = (val >>24) & 0xff; eval->val[5] = (val >>16) & 0xff; eval->val[6] = (val >>8) & 0xff; eval->val[7] = val & 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_ROUTE_TARGET or ECOMMUNITY_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_ROUTE_TARGET keyword_included = 0 "soo 100:1" -> str = "100:1" type = ECOMMUNITY_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 (const char *str, int type, int keyword_included) { struct ecommunity *ecom = NULL; enum ecommunity_token token = ecommunity_token_unknown; 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_ROUTE_TARGET; } if (token == ecommunity_token_soo) { type = ECOMMUNITY_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; } } 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_ROUTE_MAP ECOMMUNITY_FORMAT_COMMUNITY_LIST ECOMMUNITY_FORMAT_DISPLAY */ char * ecommunity_ecom2str (struct ecommunity *ecom, int format) { int i; u_int8_t *pnt; int encode = 0; int type = 0; #define ECOMMUNITY_STR_DEFAULT_LEN 27 int str_size; int str_pnt; char *str_buf; const 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++; switch (encode) { case ECOMMUNITY_ENCODE_AS: case ECOMMUNITY_ENCODE_IP: case ECOMMUNITY_ENCODE_AS4: break; case ECOMMUNITY_ENCODE_OPAQUE: if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) { uint16_t tunneltype; memcpy (&tunneltype, pnt + 5, 2); tunneltype = ntohs(tunneltype); len = sprintf (str_buf + str_pnt, "ET:%d", tunneltype); str_pnt += len; first = 0; continue; } /* fall through */ default: len = sprintf (str_buf + str_pnt, "?"); str_pnt += len; first = 0; continue; } /* Low-order octet of type. */ type = *pnt++; if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN) { len = sprintf (str_buf + str_pnt, "?"); str_pnt += len; first = 0; continue; } switch (format) { case ECOMMUNITY_FORMAT_COMMUNITY_LIST: prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo "); break; case ECOMMUNITY_FORMAT_DISPLAY: prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:"); break; case ECOMMUNITY_FORMAT_ROUTE_MAP: prefix = ""; break; default: prefix = ""; break; } /* Put string into buffer. */ if (encode == ECOMMUNITY_ENCODE_AS4) { eas.as = (*pnt++ << 24); eas.as |= (*pnt++ << 16); eas.as |= (*pnt++ << 8); eas.as |= (*pnt++); eas.val = (*pnt++ << 8); eas.val |= (*pnt++); len = sprintf( str_buf + str_pnt, "%s%u:%u", prefix, eas.as, eas.val ); str_pnt += len; first = 0; } if (encode == 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%u:%u", prefix, eas.as, eas.val); str_pnt += len; first = 0; } else if (encode == 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:%u", prefix, inet_ntoa (eip.ip), eip.val); str_pnt += len; first = 0; } } return str_buf; } int ecommunity_match (const struct ecommunity *ecom1, const 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; } quagga-1.2.4/bgpd/bgp_ecommunity.h000066400000000000000000000062321325323223500170740ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_ECOMMUNITY_H #define _QUAGGA_BGP_ECOMMUNITY_H /* High-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ENCODE_AS 0x00 #define ECOMMUNITY_ENCODE_IP 0x01 #define ECOMMUNITY_ENCODE_AS4 0x02 #define ECOMMUNITY_ENCODE_OPAQUE 0x03 /* Low-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ROUTE_TARGET 0x02 #define ECOMMUNITY_SITE_ORIGIN 0x03 /* Low-order octet of the Extended Communities type field for OPAQUE types */ #define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c /* Extended communities attribute string format. */ #define ECOMMUNITY_FORMAT_ROUTE_MAP 0 #define ECOMMUNITY_FORMAT_COMMUNITY_LIST 1 #define ECOMMUNITY_FORMAT_DISPLAY 2 /* Extended Communities value is eight octet long. */ #define ECOMMUNITY_SIZE 8 /* Extended Communities type flag. */ #define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40 /* Extended Communities attribute. */ struct ecommunity { /* Reference counter. */ unsigned long refcnt; /* Size of Extended Communities attribute. */ int size; /* Extended Communities value. */ u_int8_t *val; /* Human readable format string. */ char *str; }; /* Extended community value is eight octet. */ struct ecommunity_val { char val[ECOMMUNITY_SIZE]; }; #define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE) extern void ecommunity_init (void); extern void ecommunity_finish (void); extern void ecommunity_free (struct ecommunity **); extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short); extern struct ecommunity *ecommunity_dup (struct ecommunity *); extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *); extern struct ecommunity *ecommunity_uniq_sort (struct ecommunity *); extern struct ecommunity *ecommunity_intern (struct ecommunity *); extern int ecommunity_cmp (const void *, const void *); extern void ecommunity_unintern (struct ecommunity **); extern unsigned int ecommunity_hash_make (void *); extern struct ecommunity *ecommunity_str2com (const char *, int, int); extern char *ecommunity_ecom2str (struct ecommunity *, int); extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *); extern char *ecommunity_str (struct ecommunity *); #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ quagga-1.2.4/bgpd/bgp_encap.c000066400000000000000000000642251325323223500157720ustar00rootroot00000000000000 /* * This file created by LabN Consulting, L.L.C. * * * This file is based on bgp_mplsvpn.c which is 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 "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_encap.h" static 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; } static 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; } static void decode_rd_as4 (u_char *pnt, struct rd_as *rd_as) { rd_as->as = (u_int32_t) *pnt++ << 24; rd_as->as |= (u_int32_t) *pnt++ << 16; rd_as->as |= (u_int32_t) *pnt++ << 8; rd_as->as |= (u_int32_t) *pnt++; rd_as->val = ((u_int32_t) *pnt++ << 8); rd_as->val |= (u_int32_t) *pnt; } static 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; } static void ecom2prd(struct ecommunity *ecom, struct prefix_rd *prd) { int i; memset(prd, 0, sizeof(struct prefix_rd)); prd->family = AF_UNSPEC; prd->prefixlen = 64; if (!ecom) return; for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) { uint8_t *ep; ep = ecom->val + i; switch (ep[0]) { default: continue; case 0x80: case 0x81: case 0x82: if (ep[1] == 0x0) { prd->val[1] = ep[0] & 0x03; memcpy(prd->val + 2, ep + 2, 6); return; } } } } int bgp_nlri_parse_encap( struct peer *peer, struct attr *attr, /* Need even for withdraw */ struct bgp_nlri *packet) { u_char *pnt; u_char *lim; afi_t afi = packet->afi; struct prefix p; int psize = 0; int prefixlen; struct rd_as rd_as; struct rd_ip rd_ip; struct prefix_rd prd; struct ecommunity *pEcom = NULL; u_int16_t rdtype = 0xffff; char buf[BUFSIZ]; /* Check peer status. */ if (peer->status != Established) return 0; /* Make prefix_rd */ if (attr && attr->extra && attr->extra->ecommunity) pEcom = attr->extra->ecommunity; ecom2prd(pEcom, &prd); memset(&rd_as, 0, sizeof(rd_as)); memset(&rd_ip, 0, sizeof(rd_ip)); if (pEcom) { rdtype = (prd.val[0] << 8) | prd.val[1]; /* Decode RD value. */ if (rdtype == RD_TYPE_AS) decode_rd_as (prd.val + 2, &rd_as); else if (rdtype == RD_TYPE_IP) decode_rd_ip (prd.val + 2, &rd_ip); else if (rdtype == RD_TYPE_AS4) decode_rd_as4 (prd.val + 2, &rd_as); else { zlog_err ("Invalid RD type %d", rdtype); } } /* * NB: this code was based on the MPLS VPN code, which supported RDs. * For the moment we are retaining the underlying RIB structure that * keeps a per-RD radix tree, but since the RDs are not carried over * the wire, we set the RD internally to 0. */ prd.family = AF_UNSPEC; prd.prefixlen = 64; memset(prd.val, 0, sizeof(prd.val)); 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 = afi2family(afi); if (p.family == 0) { /* bad afi, shouldn't happen */ zlog_warn("%s: bad afi %d, dropping incoming route", __func__, afi); continue; } psize = PSIZE (prefixlen); p.prefixlen = prefixlen; memcpy (&p.u.prefix, pnt, psize); if (pnt + psize > lim) return -1; if (rdtype == RD_TYPE_AS) zlog_info ("rd-as %u:%u prefix %s/%d", rd_as.as, rd_as.val, inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); else if (rdtype == RD_TYPE_IP) zlog_info ("rd-ip %s:%u prefix %s/%d", inet_ntoa (rd_ip.ip), rd_ip.val, inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); else if (rdtype == RD_TYPE_AS4) zlog_info ("rd-as4 %u:%u prefix %s/%d", rd_as.as, rd_as.val, inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); else zlog_info ("rd unknown, default to 0:0 prefix %s/%d", inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); if (attr) { bgp_update (peer, &p, attr, afi, SAFI_ENCAP, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); } else { bgp_withdraw (peer, &p, attr, afi, SAFI_ENCAP, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL); } } /* Packet length consistency check. */ if (pnt != lim) return -1; return 0; } /* TBD: these routes should probably all be host routes */ /* For testing purpose, static route of ENCAP. */ DEFUN (encap_network, encap_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" "ENCAP Route Distinguisher\n" "BGP tag\n" "tag value\n") { return bgp_static_set_safi (SAFI_ENCAP, vty, argv[0], argv[1], argv[2], NULL); } /* For testing purpose, static route of ENCAP. */ DEFUN (no_encap_network, no_encap_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" "ENCAP Route Distinguisher\n" "BGP tag\n" "tag value\n") { return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[0], argv[1], argv[2]); } static int show_adj_route_encap (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_ENCAP]); 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; vty_out (vty, "Route Distinguisher: "); /* Decode RD type. */ type = decode_rd_type (pnt); switch (type) { case RD_TYPE_AS: decode_rd_as (pnt + 2, &rd_as); vty_out (vty, "%u:%d", rd_as.as, rd_as.val); break; case RD_TYPE_IP: decode_rd_ip (pnt + 2, &rd_ip); vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); break; default: vty_out (vty, "unknown RD type"); } vty_out (vty, "%s", VTY_NEWLINE); rd_header = 0; } route_vty_out_tmp (vty, &rm->p, attr, SAFI_ENCAP); } } } 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 }; static int bgp_show_encap ( struct vty *vty, afi_t afi, 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"; unsigned long output_count = 0; unsigned long total_count = 0; bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } if ((afi != AFI_IP) && (afi != AFI_IP6)) { vty_out (vty, "Afi %d not supported%s", afi, VTY_NEWLINE); return CMD_WARNING; } for (rn = bgp_table_top (bgp->rib[afi][SAFI_ENCAP]); 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) { total_count++; 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); vty_out (vty, "Route Distinguisher: "); switch (type) { case RD_TYPE_AS: decode_rd_as (pnt + 2, &rd_as); vty_out (vty, "%u:%d", rd_as.as, rd_as.val); break; case RD_TYPE_IP: decode_rd_ip (pnt + 2, &rd_ip); vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); break; default: vty_out (vty, "Unknown RD type"); break; } vty_out (vty, "%s", VTY_NEWLINE); rd_header = 0; } if (tags) route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_ENCAP); else route_vty_out (vty, &rm->p, ri, 0, SAFI_ENCAP); output_count++; } } } if (output_count == 0) { vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); } else vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (show_bgp_ipv4_encap, show_bgp_ipv4_encap_cmd, "show bgp ipv4 encap", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n") { return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 0); } DEFUN (show_bgp_ipv6_encap, show_bgp_ipv6_encap_cmd, "show bgp ipv6 encap", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n") { return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 0); } DEFUN (show_bgp_ipv4_encap_rd, show_bgp_ipv4_encap_rd_cmd, "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP 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_encap (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 0); } DEFUN (show_bgp_ipv6_encap_rd, show_bgp_ipv6_encap_rd_cmd, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP 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_encap (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 0); } DEFUN (show_bgp_ipv4_encap_tags, show_bgp_ipv4_encap_tags_cmd, "show bgp ipv4 encap tags", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display BGP tags for prefixes\n") { return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 1); } DEFUN (show_bgp_ipv6_encap_tags, show_bgp_ipv6_encap_tags_cmd, "show bgp ipv6 encap tags", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display BGP tags for prefixes\n") { return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 1); } DEFUN (show_bgp_ipv4_encap_rd_tags, show_bgp_ipv4_encap_rd_tags_cmd, "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn tags", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP 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_encap (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 1); } DEFUN (show_bgp_ipv6_encap_rd_tags, show_bgp_ipv6_encap_rd_tags_cmd, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn tags", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP 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_encap (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 1); } DEFUN (show_bgp_ipv4_encap_neighbor_routes, show_bgp_ipv4_encap_neighbor_routes_cmd, "show bgp ipv4 encap neighbors A.B.C.D routes", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\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; if (str2sockunion(argv[0], &su)) { 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_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv6_encap_neighbor_routes, show_bgp_ipv6_encap_neighbor_routes_cmd, "show bgp ipv6 encap neighbors A.B.C.D routes", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\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; if (str2sockunion(argv[0], &su)) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv4_encap_rd_neighbor_routes, show_bgp_ipv4_encap_rd_neighbor_routes_cmd, "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\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") { 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; } if (str2sockunion(argv[1], &su)) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv6_encap_rd_neighbor_routes, show_bgp_ipv6_encap_rd_neighbor_routes_cmd, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\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") { 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; } if (str2sockunion(argv[1], &su)) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv4_encap_neighbor_advertised_routes, show_bgp_ipv4_encap_neighbor_advertised_routes_cmd, "show bgp ipv4 encap neighbors A.B.C.D advertised-routes", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\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_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return show_adj_route_encap (vty, peer, NULL); } DEFUN (show_bgp_ipv6_encap_neighbor_advertised_routes, show_bgp_ipv6_encap_neighbor_advertised_routes_cmd, "show bgp ipv6 encap neighbors A.B.C.D advertised-routes", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\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_IP6][SAFI_ENCAP]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return show_adj_route_encap (vty, peer, NULL); } DEFUN (show_bgp_ipv4_encap_rd_neighbor_advertised_routes, show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd, "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\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") { 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[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP]) { 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_encap (vty, peer, &prd); } DEFUN (show_bgp_ipv6_encap_rd_neighbor_advertised_routes, show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\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") { 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[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP]) { 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_encap (vty, peer, &prd); } void bgp_encap_init (void) { install_element (BGP_ENCAP_NODE, &encap_network_cmd); install_element (BGP_ENCAP_NODE, &no_encap_network_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_tags_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_tags_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_tags_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_tags_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); } quagga-1.2.4/bgpd/bgp_encap.h000066400000000000000000000017761325323223500160010ustar00rootroot00000000000000/* * * Copyright 2009-2015, LabN Consulting, L.L.C. * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef _QUAGGA_BGP_ENCAP_H #define _QUAGGA_BGP_ENCAP_H extern void bgp_encap_init (void); extern int bgp_nlri_parse_encap (struct peer *, struct attr *, struct bgp_nlri *); #include "bgp_encap_types.h" #endif /* _QUAGGA_BGP_ENCAP_H */ quagga-1.2.4/bgpd/bgp_encap_tlv.c000066400000000000000000000655471325323223500166670ustar00rootroot00000000000000/* * Copyright 2015, LabN Consulting, L.L.C. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include "memory.h" #include "prefix.h" #include "vty.h" #include "filter.h" #include "bgpd.h" #include "bgp_attr.h" #include "bgp_encap_types.h" #include "bgp_encap_tlv.h" /*********************************************************************** * SUBTLV ENCODE ***********************************************************************/ /* rfc5512 4.1 */ static struct bgp_attr_encap_subtlv * subtlv_encode_encap_l2tpv3_over_ip( struct bgp_tea_subtlv_encap_l2tpv3_over_ip *st) { struct bgp_attr_encap_subtlv *new; uint8_t *p; int total = 4 + st->cookie_length; /* sanity check */ assert(st->cookie_length <= sizeof(st->cookie)); assert(total <= 0xff); new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); assert(new); new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; new->length = total; p = new->value; *p++ = (st->sessionid & 0xff000000) >> 24; *p++ = (st->sessionid & 0xff0000) >> 16; *p++ = (st->sessionid & 0xff00) >> 8; *p++ = (st->sessionid & 0xff); memcpy(p, st->cookie, st->cookie_length); return new; } /* rfc5512 4.1 */ static struct bgp_attr_encap_subtlv * subtlv_encode_encap_gre( struct bgp_tea_subtlv_encap_gre_key *st) { struct bgp_attr_encap_subtlv *new; uint8_t *p; int total = 4; assert(total <= 0xff); new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); assert(new); new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; new->length = total; p = new->value; *p++ = (st->gre_key & 0xff000000) >> 24; *p++ = (st->gre_key & 0xff0000) >> 16; *p++ = (st->gre_key & 0xff00) >> 8; *p++ = (st->gre_key & 0xff); return new; } static struct bgp_attr_encap_subtlv * subtlv_encode_encap_pbb( struct bgp_tea_subtlv_encap_pbb *st) { struct bgp_attr_encap_subtlv *new; uint8_t *p; int total = 1 + 3 + 6 + 2; /* flags + isid + madaddr + vid */ assert(total <= 0xff); new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); assert(new); new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; new->length = total; p = new->value; *p++ = (st->flag_isid? 0x80: 0) | (st->flag_vid? 0x40: 0) | 0; if (st->flag_isid) { *p = (st->isid & 0xff0000) >> 16; *(p+1) = (st->isid & 0xff00) >> 8; *(p+2) = (st->isid & 0xff); } p += 3; memcpy(p, st->macaddr, 6); p += 6; if (st->flag_vid) { *p++ = (st->vid & 0xf00) >> 8; *p++ = st->vid & 0xff; } return new; } /* rfc5512 4.2 */ static struct bgp_attr_encap_subtlv * subtlv_encode_proto_type( struct bgp_tea_subtlv_proto_type *st) { struct bgp_attr_encap_subtlv *new; uint8_t *p; int total = 2; assert(total <= 0xff); new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); assert(new); new->type = BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE; new->length = total; p = new->value; *p++ = (st->proto & 0xff00) >> 8; *p++ = (st->proto & 0xff); return new; } /* rfc5512 4.3 */ static struct bgp_attr_encap_subtlv * subtlv_encode_color( struct bgp_tea_subtlv_color *st) { struct bgp_attr_encap_subtlv *new; uint8_t *p; int total = 8; assert(total <= 0xff); new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); assert(new); new->type = BGP_ENCAP_SUBTLV_TYPE_COLOR; new->length = total; p = new->value; *p++ = 0x03; /* transitive*/ *p++ = 0x0b; *p++ = 0; /* reserved */ *p++ = 0; /* reserved */ *p++ = (st->color & 0xff000000) >> 24; *p++ = (st->color & 0xff0000) >> 16; *p++ = (st->color & 0xff00) >> 8; *p++ = (st->color & 0xff); return new; } /* rfc 5566 4. */ static struct bgp_attr_encap_subtlv * subtlv_encode_ipsec_ta( struct bgp_tea_subtlv_ipsec_ta *st) { struct bgp_attr_encap_subtlv *new; uint8_t *p; int total = 2 + st->authenticator_length; /* sanity check */ assert(st->authenticator_length <= sizeof(st->value)); assert(total <= 0xff); new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); assert(new); new->type = BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA; new->length = total; p = new->value; *p++ = (st->authenticator_type & 0xff00) >> 8; *p++ = st->authenticator_type & 0xff; memcpy(p, st->value, st->authenticator_length); return new; } /* draft-rosen-idr-tunnel-encaps 2.1 */ static struct bgp_attr_encap_subtlv * subtlv_encode_remote_endpoint( struct bgp_tea_subtlv_remote_endpoint *st) { struct bgp_attr_encap_subtlv *new; uint8_t *p; int total = (st->family==AF_INET?8:20); assert(total <= 0xff); new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); assert(new); new->type = BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT; new->length = total; p = new->value; if (st->family == AF_INET) { memcpy (p, &(st->ip_address.v4.s_addr), 4); p+=4; } else { assert (st->family == AF_INET6); memcpy (p, &(st->ip_address.v6.s6_addr), 16); p+=16; } memcpy (p, &(st->as4), 4); return new; } /*********************************************************************** * TUNNEL TYPE-SPECIFIC TLV ENCODE ***********************************************************************/ /* * requires "extra" and "last" to be defined in caller */ #define ENC_SUBTLV(flag, function, field) do {\ struct bgp_attr_encap_subtlv *new;\ if (CHECK_FLAG(bet->valid_subtlvs, (flag))) {\ new = function(&bet->field);\ if (last) {\ last->next = new;\ } else {\ extra->encap_subtlvs = new;\ }\ last = new;\ }\ } while (0) void bgp_encap_type_l2tpv3overip_to_tlv( struct bgp_encap_type_l2tpv3_over_ip *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ for (last = extra->encap_subtlvs; last && last->next; last = last->next); extra->encap_tunneltype = BGP_ENCAP_TYPE_L2TPV3_OVER_IP; assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP)); ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_l2tpv3_over_ip, st_encap); ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); ENC_SUBTLV(BGP_TEA_SUBTLV_REMOTE_ENDPOINT, subtlv_encode_remote_endpoint, st_endpoint); } void bgp_encap_type_gre_to_tlv( struct bgp_encap_type_gre *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ for (last = extra->encap_subtlvs; last && last->next; last = last->next); extra->encap_tunneltype = BGP_ENCAP_TYPE_GRE; ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_gre, st_encap); ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); ENC_SUBTLV(BGP_TEA_SUBTLV_REMOTE_ENDPOINT, subtlv_encode_remote_endpoint, st_endpoint); } void bgp_encap_type_ip_in_ip_to_tlv( struct bgp_encap_type_ip_in_ip *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ for (last = extra->encap_subtlvs; last && last->next; last = last->next); extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP; ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); ENC_SUBTLV(BGP_TEA_SUBTLV_REMOTE_ENDPOINT, subtlv_encode_remote_endpoint, st_endpoint); } void bgp_encap_type_transmit_tunnel_endpoint( struct bgp_encap_type_transmit_tunnel_endpoint *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ for (last = extra->encap_subtlvs; last && last->next; last = last->next); extra->encap_tunneltype = BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT; /* no subtlvs for this type */ } void bgp_encap_type_ipsec_in_tunnel_mode_to_tlv( struct bgp_encap_type_ipsec_in_tunnel_mode *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ for (last = extra->encap_subtlvs; last && last->next; last = last->next); extra->encap_tunneltype = BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE; ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); } void bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ for (last = extra->encap_subtlvs; last && last->next; last = last->next); extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); } void bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ for (last = extra->encap_subtlvs; last && last->next; last = last->next); extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); } void bgp_encap_type_pbb_to_tlv( struct bgp_encap_type_pbb *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); struct bgp_attr_encap_subtlv *last; /* advance to last subtlv */ for (last = extra->encap_subtlvs; last && last->next; last = last->next); extra->encap_tunneltype = BGP_ENCAP_TYPE_PBB; assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP)); ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_pbb, st_encap); } void bgp_encap_type_vxlan_to_tlv( struct bgp_encap_type_vxlan *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN; } void bgp_encap_type_nvgre_to_tlv( struct bgp_encap_type_nvgre *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); extra->encap_tunneltype = BGP_ENCAP_TYPE_NVGRE; } void bgp_encap_type_mpls_to_tlv( struct bgp_encap_type_mpls *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS; } void bgp_encap_type_mpls_in_gre_to_tlv( struct bgp_encap_type_mpls_in_gre *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_GRE; } void bgp_encap_type_vxlan_gpe_to_tlv( struct bgp_encap_type_vxlan_gpe *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN_GPE; } void bgp_encap_type_mpls_in_udp_to_tlv( struct bgp_encap_type_mpls_in_udp *bet, /* input structure */ struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_UDP; } /*********************************************************************** * SUBTLV DECODE ***********************************************************************/ /* rfc5512 4.1 */ static int subtlv_decode_encap_l2tpv3_over_ip( struct bgp_attr_encap_subtlv *subtlv, struct bgp_tea_subtlv_encap_l2tpv3_over_ip *st) { if (subtlv->length < 4) { zlog_debug("%s, subtlv length %d is less than 4", __func__, subtlv->length); return -1; } st->sessionid = (subtlv->value[0] << 24) | (subtlv->value[1] << 16) | (subtlv->value[2] << 8) | subtlv->value[3]; st->cookie_length = subtlv->length - 4; if (st->cookie_length > sizeof(st->cookie)) { zlog_debug("%s, subtlv length %d is greater than %d", __func__, st->cookie_length, (int)sizeof(st->cookie)); return -1; } memcpy(st->cookie, subtlv->value + 4, st->cookie_length); return 0; } /* rfc5512 4.1 */ static int subtlv_decode_encap_gre( struct bgp_attr_encap_subtlv *subtlv, struct bgp_tea_subtlv_encap_gre_key *st) { if (subtlv->length != 4) { zlog_debug("%s, subtlv length %d does not equal 4", __func__, subtlv->length); return -1; } st->gre_key = (subtlv->value[0] << 24) | (subtlv->value[1] << 16) | (subtlv->value[2] << 8) | subtlv->value[3]; return 0; } static int subtlv_decode_encap_pbb( struct bgp_attr_encap_subtlv *subtlv, struct bgp_tea_subtlv_encap_pbb *st) { if (subtlv->length != 1 + 3 + 6 + 2) { zlog_debug("%s, subtlv length %d does not equal %d", __func__, subtlv->length, 1 + 3 + 6 + 2); return -1; } if (subtlv->value[0] & 0x80) { st->flag_isid = 1; st->isid = (subtlv->value[1] << 16) | (subtlv->value[2] << 8) | subtlv->value[3]; } if (subtlv->value[0] & 0x40) { st->flag_vid = 1; st->vid = ((subtlv->value[10] & 0x0f) << 8) | subtlv->value[11]; } memcpy(st->macaddr, subtlv->value + 4, 6); return 0; } /* rfc5512 4.2 */ static int subtlv_decode_proto_type( struct bgp_attr_encap_subtlv *subtlv, struct bgp_tea_subtlv_proto_type *st) { if (subtlv->length != 2) { zlog_debug("%s, subtlv length %d does not equal 2", __func__, subtlv->length); return -1; } st->proto = (subtlv->value[0] << 8) | subtlv->value[1]; return 0; } /* rfc5512 4.3 */ static int subtlv_decode_color( struct bgp_attr_encap_subtlv *subtlv, struct bgp_tea_subtlv_color *st) { if (subtlv->length != 8) { zlog_debug("%s, subtlv length %d does not equal 8", __func__, subtlv->length); return -1; } if ((subtlv->value[0] != 0x03) || (subtlv->value[1] != 0x0b) || (subtlv->value[2] != 0) || (subtlv->value[3] != 0)) { zlog_debug("%s, subtlv value 1st 4 bytes are not 0x030b0000", __func__); return -1; } st->color = (subtlv->value[4] << 24) | (subtlv->value[5] << 16) | (subtlv->value[6] << 8) | subtlv->value[7]; return 0; } /* rfc 5566 4. */ static int subtlv_decode_ipsec_ta( struct bgp_attr_encap_subtlv *subtlv, struct bgp_tea_subtlv_ipsec_ta *st) { st->authenticator_length = subtlv->length - 2; if (st->authenticator_length > sizeof(st->value)) { zlog_debug("%s, authenticator length %d exceeds storage maximum %d", __func__, st->authenticator_length, (int)sizeof(st->value)); return -1; } st->authenticator_type = (subtlv->value[0] << 8) | subtlv->value[1]; memcpy(st->value, subtlv->value + 2, st->authenticator_length); return 0; } /* draft-rosen-idr-tunnel-encaps 2.1 */ static int subtlv_decode_remote_endpoint( struct bgp_attr_encap_subtlv *subtlv, struct bgp_tea_subtlv_remote_endpoint *st) { int i; if (subtlv->length != 8 && subtlv->length != 20 ) { zlog_debug("%s, subtlv length %d does not equal 8 or 20", __func__, subtlv->length); return -1; } if (subtlv->length == 8) { st->family = AF_INET; st->ip_address.v4.s_addr = ((subtlv->value[0] << 24) | (subtlv->value[1] << 16) | (subtlv->value[2] << 8) | subtlv->value[3]); } else { st->family = AF_INET6; memcpy (&(st->ip_address.v6.s6_addr), subtlv->value, 16); } i = subtlv->length - 4; st->as4 = ((subtlv->value[i] << 24) | (subtlv->value[i+1] << 16) | (subtlv->value[i+2] << 8) | subtlv->value[i+3]); return 0; } /*********************************************************************** * TUNNEL TYPE-SPECIFIC TLV DECODE ***********************************************************************/ int tlv_to_bgp_encap_type_l2tpv3overip( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_l2tpv3_over_ip *bet) /* caller-allocated */ { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: rc |= subtlv_decode_encap_l2tpv3_over_ip(st, &bet->st_encap); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_ENCAP); break; case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: rc |= subtlv_decode_proto_type(st, &bet->st_proto); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_PROTO_TYPE); break; case BGP_ENCAP_SUBTLV_TYPE_COLOR: rc |= subtlv_decode_color(st, &bet->st_color); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_COLOR); break; case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_gre( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_gre *bet) /* caller-allocated */ { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: rc |= subtlv_decode_encap_gre(st, &bet->st_encap); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_ENCAP); break; case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: rc |= subtlv_decode_proto_type(st, &bet->st_proto); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_PROTO_TYPE); break; case BGP_ENCAP_SUBTLV_TYPE_COLOR: rc |= subtlv_decode_color(st, &bet->st_color); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_COLOR); break; case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_ip_in_ip( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_ip_in_ip *bet) /* caller-allocated */ { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: rc |= subtlv_decode_proto_type(st, &bet->st_proto); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_PROTO_TYPE); break; case BGP_ENCAP_SUBTLV_TYPE_COLOR: rc |= subtlv_decode_color(st, &bet->st_color); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_COLOR); break; case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_transmit_tunnel_endpoint( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_transmit_tunnel_endpoint *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_ipsec_in_tunnel_mode( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_ipsec_in_tunnel_mode *bet) /* caller-allocated */ { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_IPSEC_TA); break; case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_IPSEC_TA); break; case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_IPSEC_TA); break; case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_vxlan( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_vxlan *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_nvgre( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_nvgre *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_mpls( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_mpls_in_gre( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls_in_gre *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_vxlan_gpe( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_vxlan_gpe *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_mpls_in_udp( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls_in_udp *bet) { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } int tlv_to_bgp_encap_type_pbb( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_pbb *bet) /* caller-allocated */ { struct bgp_attr_encap_subtlv *st; int rc = 0; for (st = stlv; st; st = st->next) { switch (st->type) { case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: rc |= subtlv_decode_encap_pbb(st, &bet->st_encap); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_ENCAP); break; case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: rc |= subtlv_decode_remote_endpoint(st, &bet->st_endpoint); SET_SUBTLV_FLAG(bet, BGP_TEA_SUBTLV_REMOTE_ENDPOINT); break; default: zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); rc |= -1; break; } } return rc; } quagga-1.2.4/bgpd/bgp_encap_tlv.h000066400000000000000000000122401325323223500166520ustar00rootroot00000000000000/* * Copyright 2015, LabN Consulting, L.L.C. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef _QUAGGA_BGP_ENCAP_TLV_H #define _QUAGGA_BGP_ENCAP_TLV_H /*********************************************************************** * TUNNEL TYPE-SPECIFIC TLV ENCODE ***********************************************************************/ extern void bgp_encap_type_l2tpv3overip_to_tlv( struct bgp_encap_type_l2tpv3_over_ip *bet, struct attr *attr); extern void bgp_encap_type_gre_to_tlv( struct bgp_encap_type_gre *bet, struct attr *attr); extern void bgp_encap_type_ip_in_ip_to_tlv( struct bgp_encap_type_ip_in_ip *bet, struct attr *attr); extern void bgp_encap_type_transmit_tunnel_endpoint( struct bgp_encap_type_transmit_tunnel_endpoint *bet, struct attr *attr); extern void bgp_encap_type_ipsec_in_tunnel_mode_to_tlv( struct bgp_encap_type_ipsec_in_tunnel_mode *bet, struct attr *attr); extern void bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet, struct attr *attr); extern void bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet, struct attr *attr); extern void bgp_encap_type_pbb_to_tlv( struct bgp_encap_type_pbb *bet, struct attr *attr); extern void bgp_encap_type_vxlan_to_tlv( struct bgp_encap_type_vxlan *bet, struct attr *attr); extern void bgp_encap_type_nvgre_to_tlv( struct bgp_encap_type_nvgre *bet, struct attr *attr); extern void bgp_encap_type_mpls_to_tlv( struct bgp_encap_type_mpls *bet, struct attr *attr); extern void bgp_encap_type_mpls_in_gre_to_tlv( struct bgp_encap_type_mpls_in_gre *bet, struct attr *attr); extern void bgp_encap_type_vxlan_gpe_to_tlv( struct bgp_encap_type_vxlan_gpe *bet, struct attr *attr); extern void bgp_encap_type_mpls_in_udp_to_tlv( struct bgp_encap_type_mpls_in_udp *bet, struct attr *attr); /*********************************************************************** * TUNNEL TYPE-SPECIFIC TLV DECODE ***********************************************************************/ extern int tlv_to_bgp_encap_type_l2tpv3overip( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_l2tpv3_over_ip *bet); /* caller-allocated */ extern int tlv_to_bgp_encap_type_gre( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_gre *bet); /* caller-allocated */ extern int tlv_to_bgp_encap_type_ip_in_ip( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_ip_in_ip *bet); /* caller-allocated */ extern int tlv_to_bgp_encap_type_transmit_tunnel_endpoint( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_transmit_tunnel_endpoint *bet); extern int tlv_to_bgp_encap_type_ipsec_in_tunnel_mode( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_ipsec_in_tunnel_mode *bet); /* caller-allocated */ extern int tlv_to_bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet); extern int tlv_to_bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet); extern int tlv_to_bgp_encap_type_vxlan( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_vxlan *bet); extern int tlv_to_bgp_encap_type_nvgre( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_nvgre *bet); extern int tlv_to_bgp_encap_type_mpls( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls *bet); extern int tlv_to_bgp_encap_type_mpls( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls *bet); extern int tlv_to_bgp_encap_type_mpls_in_gre( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls_in_gre *bet); extern int tlv_to_bgp_encap_type_vxlan_gpe( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_vxlan_gpe *bet); extern int tlv_to_bgp_encap_type_mpls_in_udp( struct bgp_attr_encap_subtlv *stlv, struct bgp_encap_type_mpls_in_udp *bet); extern int tlv_to_bgp_encap_type_pbb( struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ struct bgp_encap_type_pbb *bet); /* caller-allocated */ #endif /* _QUAGGA_BGP_ENCAP_TLV_H */ quagga-1.2.4/bgpd/bgp_encap_types.h000066400000000000000000000154061325323223500172200ustar00rootroot00000000000000/* * Copyright 2015, LabN Consulting, L.L.C. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef _QUAGGA_BGP_ENCAP_TYPES_H #define _QUAGGA_BGP_ENCAP_TYPES_H /* from http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#tunnel-types */ typedef enum { BGP_ENCAP_TYPE_RESERVED=0, BGP_ENCAP_TYPE_L2TPV3_OVER_IP=1, BGP_ENCAP_TYPE_GRE=2, BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT=3, BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE=4, BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE=5, BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE=6, BGP_ENCAP_TYPE_IP_IN_IP=7, BGP_ENCAP_TYPE_VXLAN=8, BGP_ENCAP_TYPE_NVGRE=9, BGP_ENCAP_TYPE_MPLS=10, BGP_ENCAP_TYPE_MPLS_IN_GRE=11, BGP_ENCAP_TYPE_VXLAN_GPE=12, BGP_ENCAP_TYPE_MPLS_IN_UDP=13, BGP_ENCAP_TYPE_PBB } bgp_encap_types; typedef enum { BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION=1, BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE=2, BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA=3, BGP_ENCAP_SUBTLV_TYPE_COLOR=4, BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT=6 /* speculative, IANA assignment TBD */ } bgp_encap_subtlv_types; /* * Tunnel Encapsulation Attribute subtlvs */ struct bgp_tea_subtlv_encap_l2tpv3_over_ip { uint32_t sessionid; uint8_t cookie_length; uint8_t cookie[8]; }; struct bgp_tea_subtlv_encap_gre_key { uint32_t gre_key; }; struct bgp_tea_subtlv_encap_pbb { uint32_t flag_isid:1; uint32_t flag_vid:1; uint32_t isid:24; uint16_t vid:12; uint8_t macaddr[6]; }; struct bgp_tea_subtlv_proto_type { uint16_t proto; /* ether-type */ }; struct bgp_tea_subtlv_color { uint32_t color; }; /* per draft-rosen-idr-tunnel-encaps */ struct bgp_tea_subtlv_remote_endpoint { u_char family; /* IPv4 or IPv6 */ union { struct in_addr v4; struct in6_addr v6; } ip_address; as_t as4; /* always 4 bytes */ }; /* * This is the length of the value part of the ipsec tunnel authenticator * subtlv. Currently we only support the length for authenticator type 1. */ #define BGP_ENCAP_SUBTLV_IPSEC_TA_SIZE 20 struct bgp_tea_subtlv_ipsec_ta { uint16_t authenticator_type; /* only type 1 is supported so far */ uint8_t authenticator_length; /* octets in value field */ uint8_t value[BGP_ENCAP_SUBTLV_IPSEC_TA_SIZE]; }; /* * Subtlv valid flags * TBD change names to add "VALID" */ #define BGP_TEA_SUBTLV_ENCAP 0x00000001 #define BGP_TEA_SUBTLV_PROTO_TYPE 0x00000002 #define BGP_TEA_SUBTLV_COLOR 0x00000004 #define BGP_TEA_SUBTLV_IPSEC_TA 0x00000008 #define BGP_TEA_SUBTLV_REMOTE_ENDPOINT 0x00000010 #define CHECK_SUBTLV_FLAG(ptr, flag) CHECK_FLAG((ptr)->valid_subtlvs, (flag)) #define SET_SUBTLV_FLAG(ptr, flag) SET_FLAG((ptr)->valid_subtlvs, (flag)) #define UNSET_SUBTLV_FLAG(ptr, flag) UNSET_FLAG((ptr)->valid_subtlvs, (flag)) /* * Tunnel Type-specific APIs */ struct bgp_encap_type_reserved { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_l2tpv3_over_ip { uint32_t valid_subtlvs; struct bgp_tea_subtlv_encap_l2tpv3_over_ip st_encap; struct bgp_tea_subtlv_proto_type st_proto; /* optional */ struct bgp_tea_subtlv_color st_color; /* optional */ struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_gre { uint32_t valid_subtlvs; struct bgp_tea_subtlv_encap_gre_key st_encap; /* optional */ struct bgp_tea_subtlv_proto_type st_proto; /* optional */ struct bgp_tea_subtlv_color st_color; /* optional */ struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_ip_in_ip { uint32_t valid_subtlvs; struct bgp_tea_subtlv_proto_type st_proto; /* optional */ struct bgp_tea_subtlv_color st_color; /* optional */ struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_transmit_tunnel_endpoint { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_ipsec_in_tunnel_mode { uint32_t valid_subtlvs; struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode { uint32_t valid_subtlvs; struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode { uint32_t valid_subtlvs; struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; struct bgp_encap_type_vxlan { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_nvgre { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_mpls { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_mpls_in_gre { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_vxlan_gpe { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_mpls_in_udp { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ /* No subtlvs defined in spec? */ }; struct bgp_encap_type_pbb { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ struct bgp_tea_subtlv_encap_pbb st_encap; }; #endif /* _QUAGGA_BGP_ENCAP_TYPES_H */ quagga-1.2.4/bgpd/bgp_filter.c000066400000000000000000000376051325323223500161730ustar00rootroot00000000000000/* 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 "filter.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) (void); /* Hook function which is executed when access_list is deleted. */ void (*delete_hook) (void); }; /* 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; }; /* AS path filter list. */ struct as_list { char *name; enum access_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. */ static struct as_filter * as_filter_new (void) { return XCALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter)); } /* Free allocated AS filter. */ static 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. */ static struct as_filter * as_filter_make (regex_t *reg, const 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; } static struct as_filter * as_filter_lookup (struct as_list *aslist, const 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; } static 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 (const 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; } static struct as_list * as_list_new (void) { return XCALLOC (MTYPE_AS_LIST, sizeof (struct as_list)); } static void as_list_free (struct as_list *aslist) { if (aslist->name) { free (aslist->name); aslist->name = NULL; } XFREE (MTYPE_AS_LIST, aslist); } /* Insert new AS list to list of as_list. Each as_list is sorted by the name. */ static struct as_list * as_list_insert (const char *name) { size_t 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); assert (aslist->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; } static struct as_list * as_list_get (const 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 const char * filter_type_str (enum as_filter_type type) { switch (type) { case AS_FILTER_PERMIT: return "permit"; case AS_FILTER_DENY: return "deny"; default: return ""; } } static 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; } static 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) (void)) { as_list_master.add_hook = func; } /* Delete hook function. */ void as_list_delete_hook (void (*func) (void)) { as_list_master.delete_hook = func; } static 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; char *regstr; /* 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. */ regstr = argv_concat(argv, argc, 2); regex = bgp_regcomp (regstr); if (!regex) { XFREE (MTYPE_TMP, regstr); vty_out (vty, "can't compile regexp %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } asfilter = as_filter_make (regex, regstr, type); XFREE (MTYPE_TMP, 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; 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. */ regstr = argv_concat(argv, argc, 2); regex = bgp_regcomp (regstr); if (!regex) { XFREE (MTYPE_TMP, 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); XFREE (MTYPE_TMP, 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; } static 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); } } static 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; } static 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; } static struct cmd_node as_list_node = { AS_LIST_NODE, "", 1 }; /* Register functions. */ void bgp_filter_init (void) { 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); } void bgp_filter_reset (void) { struct as_list *aslist; struct as_list *next; for (aslist = as_list_master.num.head; aslist; aslist = next) { next = aslist->next; as_list_delete (aslist); } for (aslist = as_list_master.str.head; aslist; aslist = next) { next = aslist->next; as_list_delete (aslist); } assert (as_list_master.num.head == NULL); assert (as_list_master.num.tail == NULL); assert (as_list_master.str.head == NULL); assert (as_list_master.str.tail == NULL); } quagga-1.2.4/bgpd/bgp_filter.h000066400000000000000000000023311325323223500161640ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_FILTER_H #define _QUAGGA_BGP_FILTER_H enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT }; extern void bgp_filter_init (void); extern void bgp_filter_reset (void); extern enum as_filter_type as_list_apply (struct as_list *, void *); extern struct as_list *as_list_lookup (const char *); extern void as_list_add_hook (void (*func) (void)); extern void as_list_delete_hook (void (*func) (void)); #endif /* _QUAGGA_BGP_FILTER_H */ quagga-1.2.4/bgpd/bgp_fsm.c000066400000000000000000001073251325323223500154700ustar00rootroot00000000000000/* 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 "workqueue.h" #include "filter.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" #include "bgpd/bgp_nht.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 start timer jitter. */ static int bgp_start_jitter (int time) { return ((random () % (time + 1)) - (time / 2)); } /* Check if suppress start/restart of sessions to peer. */ #define BGP_PEER_START_SUPPRESSED(P) \ (CHECK_FLAG ((P)->flags, PEER_FLAG_SHUTDOWN) \ || CHECK_FLAG ((P)->sflags, PEER_STATUS_PREFIX_OVERFLOW)) /* 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) { int jitter = 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 (BGP_PEER_START_SUPPRESSED (peer) || ! peer_active (peer)) { BGP_TIMER_OFF (peer->t_start); } else { jitter = bgp_start_jitter (peer->v_start); BGP_TIMER_ON (peer->t_start, bgp_start_timer, peer->v_start + jitter); } BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_routeadv); break; case Connect: /* After start timer is expired, the peer moves to Connect 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_routeadv); 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_PASSIVE) || CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) { BGP_TIMER_OFF (peer->t_connect); } 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_routeadv); 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_routeadv); 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_routeadv); 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); } break; case Deleted: BGP_TIMER_OFF (peer->t_gr_restart); BGP_TIMER_OFF (peer->t_gr_stale); BGP_TIMER_OFF (peer->t_pmax_restart); case Clearing: 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_routeadv); } } /* 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; 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); /* bgp_event unlocks peer */ 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); /* bgp_event unlocks peer */ 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); /* bgp_event unlocks peer */ 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); /* bgp_event unlocks peer */ return 0; } static int bgp_routeadv_timer (struct thread *thread) { struct peer *peer; peer = THREAD_ARG (thread); peer->t_routeadv = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (routeadv timer expire)", peer->host); peer->synctime = bgp_clock (); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, peer->v_routeadv); return 0; } /* BGP Peer Down Cause */ const 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", "Passive config change", "Multihop config change", "NSF peer closed the session" }; static 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_RESERVED_3 ; 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_debug ("%s graceful restart timer expired", peer->host); zlog_debug ("%s graceful restart stalepath timer stopped", peer->host); } bgp_timer_set (peer); return 0; } static 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_debug ("%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_RESERVED_3 ; safi++) if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); return 0; } /* Called after event occurred, 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); /* Transition into Clearing or Deleted must /always/ clear all routes.. * (and must do so before actually changing into Deleted.. */ if (status >= Clearing) { bgp_clear_route_all (peer); /* If no route was queued for the clear-node processing, generate the * completion event here. This is needed because if there are no routes * to trigger the background clear-node thread, the event won't get * generated and the peer would be stuck in Clearing. Note that this * event is for the peer and helps the peer transition out of Clearing * state; it should not be generated per (AFI,SAFI). The event is * directly posted here without calling clear_node_complete() as we * shouldn't do an extra unlock. This event will get processed after * the state change that happens below, so peer will be in Clearing * (or Deleted). */ if (!work_queue_is_scheduled (peer->clear_node_queue)) BGP_EVENT_ADD (peer, Clearing_Completed); } /* Preserve old status and change into new status. */ peer->ostatus = peer->status; peer->status = status; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s went from %s to %s", peer->host, LOOKUP (bgp_status_msg, peer->ostatus), LOOKUP (bgp_status_msg, peer->status)); } /* Flush the event queue and ensure the peer is shut down */ static int bgp_clearing_completed (struct peer *peer) { int rc = bgp_stop(peer); BGP_EVENT_FLUSH (peer); return rc; } /* Administrative BGP peer stop event. */ /* May be called multiple times for the same peer */ int bgp_stop (struct peer *peer) { afi_t afi; safi_t safi; char orf_name[BUFSIZ]; /* Can't do this in Clearing; events are used for state transitions */ if (peer->status != Clearing) { /* Delete all existing events of the peer */ BGP_EVENT_FLUSH (peer); } /* Increment Dropped count. */ if (peer->status == Established) { 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_debug ("%s graceful restart stalepath timer stopped", peer->host); } if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) { if (BGP_DEBUG (events, EVENTS)) { zlog_debug ("%s graceful restart timer started for %d sec", peer->host, peer->v_gr_restart); zlog_debug ("%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_RESERVED_3 ; safi++) peer->nsf[afi][safi] = 0; } /* set last reset time */ peer->resettime = peer->uptime = bgp_clock (); #ifdef HAVE_SNMP bgpTrapBackwardTransition (peer); #endif /* HAVE_SNMP */ /* Reset peer synctime */ peer->synctime = 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_routeadv); /* 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); if (peer->obuf) stream_fifo_clean (peer->obuf); /* Close of file descriptor. */ if (peer->fd >= 0) { close (peer->fd); peer->fd = -1; } 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 (afi, 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; } /* first-val * 2**x back-off, where x is the number of sucessive calls * originally used for peer v_start back-off */ __attribute__((unused)) static int back_off_exp2 (const int first, int val, const int max) { val <<= 1; return (val < max ? val : max); } /* exponential back off, but biased downward by the initial value. * this bias is significant at lower values, and tends to * insignificance fairly quickly, so it is equal to the previous at * scale. Is below first-val * 1.7**x at x == 6, and below first-val * * 1.75**x at x=10. * * I.e., this function is useful to get slower growth for the initial * points of x. */ __attribute__((unused)) static int back_off_exp2_bias (const int first, int val, const int max) { val = (val << 1) - (val > first ? first : 0); return (val < max ? val : max); } /* BGP peer is stoped by the error. */ static int bgp_stop_with_error (struct peer *peer) { peer->v_start = back_off_exp2_bias (BGP_INIT_START_TIMER, peer->v_start, 60); bgp_stop (peer); return 0; } /* something went wrong, send notify and tear down */ static int bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) { /* Send notify to remote peer */ bgp_notify_send (peer, code, sub_code); /* 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; } /* Clear start timer value to default. */ peer->v_start = BGP_INIT_START_TIMER; /* bgp_stop needs to be invoked while in Established state */ bgp_stop(peer); return 0; } /* TCP connection open. Next we send open message to remote peer. And add read thread for reading open message. */ static int bgp_connect_success (struct peer *peer) { struct peer *realpeer; 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)) { char buf1[SU_ADDRSTRLEN]; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) zlog_debug ("%s open active, local address %s", peer->host, sockunion2str (peer->su_local, buf1, SU_ADDRSTRLEN)); else zlog_debug ("%s passive open", peer->host); } /* Generally we want to send OPEN ASAP. Except, some partial BGP * implementations out there (e.g., conformance test tools / BGP * traffic generators) seem to be a bit funny about connection collisions, * and OPENs before they have sent. * * As a hack, delay sending OPEN on an inbound accept-peer session * _IF_ we locally have an outbound connection in progress, i.e. * we're in middle of a connection collision. If we delay, we delay until * an Open is received - as per old Quagga behaviour. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { realpeer = peer_lookup (peer->bgp, &peer->su); if (realpeer->status > Idle && realpeer->status <= Established) { SET_FLAG (peer->sflags, PEER_STATUS_OPEN_DEFERRED); return 0; } } bgp_open_send (peer); return 0; } /* TCP connect fail */ static 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; int connected = 0; if (BGP_PEER_START_SUPPRESSED (peer)) { if (BGP_DEBUG (fsm, FSM)) plog_err (peer->log, "%s [FSM] Trying to start suppressed peer" " - this is never supposed to happen!", peer->host); return -1; } /* Scrub some information that might be left over from a previous, * session */ /* Connection information. */ if (peer->su_local) { sockunion_free (peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { sockunion_free (peer->su_remote); peer->su_remote = NULL; } /* Clear remote router-id. */ peer->remote_id.s_addr = 0; /* Clear peer capability flag. */ peer->cap = 0; /* If the peer is passive mode, force to move to Active mode. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) { BGP_EVENT_ADD (peer, TCP_connection_open_failed); return 0; } /* Register to be notified on peer up */ if ((peer_ttl(peer) == 1 || peer->gtsm_hops == 1) && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) connected = 1; bgp_ensure_nexthop (NULL, peer, connected); status = bgp_connect (peer); switch (status) { case connect_error: if (BGP_DEBUG (fsm, FSM)) plog_debug (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_debug (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_debug (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. */ static int bgp_reconnect (struct peer *peer) { bgp_stop (peer); bgp_start (peer); return 0; } static 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; } /* Keepalive send to peer. */ static int bgp_fsm_keepalive_expire (struct peer *peer) { bgp_keepalive_send (peer); return 0; } /* FSM error, unexpected event. This is error of BGP connection. So cut the peer and change to Idle status. */ static int bgp_fsm_event_error (struct peer *peer) { plog_err (peer->log, "%s [FSM] unexpected packet received in state %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); return bgp_stop_with_notify (peer, BGP_NOTIFY_FSM_ERR, 0); } /* Hold timer expire. This is error of BGP connection. So cut the peer and change to Idle status. */ static int bgp_fsm_holdtime_expire (struct peer *peer) { if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Hold timer expire", peer->host); return bgp_stop_with_notify (peer, BGP_NOTIFY_HOLD_ERR, 0); } /* Status goes to Established. Send keepalive packet then make first update information. */ static 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 start timer value to default. */ peer->v_start = BGP_INIT_START_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_RESERVED_3 ; 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_debug ("%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_debug ("%s graceful restart timer stopped", peer->host); } #ifdef HAVE_SNMP bgpTrapEstablished (peer); #endif /* HAVE_SNMP */ /* Reset uptime, send keepalive, send current table. */ peer->uptime = bgp_clock (); /* 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); BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1); return 0; } /* Keepalive packet is received. */ static 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. */ static int bgp_fsm_update (struct peer *peer) { BGP_TIMER_OFF (peer->t_holdtime); return 0; } /* This is empty event. */ static 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 */ static const struct { int (*func) (struct peer *); 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_start, Connect}, /* 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 */ {bgp_ignore, Idle}, /* Clearing_Completed */ {bgp_ignore, Idle}, /* BGP_Stop_with_error */ }, { /* 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 */ {bgp_ignore, Idle}, /* Clearing_Completed */ {bgp_stop_with_error, Idle},/* BGP_Stop_with_error */ }, { /* 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 */ {bgp_ignore, Idle}, /* Clearing_Completed */ {bgp_stop_with_error, Idle},/* BGP_Stop_with_error */ }, { /* OpenSent, */ {bgp_ignore, OpenSent}, /* BGP_Start */ {bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Active}, /* TCP_connection_open */ {bgp_stop, Active}, /* TCP_connection_closed */ {bgp_stop, Active}, /* TCP_connection_open_failed */ {bgp_stop, Active}, /* 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_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */ {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ {bgp_stop_with_error, Idle},/* BGP_Stop_with_error */ }, { /* 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 */ {bgp_ignore, Idle}, /* Clearing_Completed */ {bgp_stop_with_error, Idle},/* BGP_Stop_with_error */ }, { /* Established, */ {bgp_ignore, Established}, /* BGP_Start */ {bgp_stop, Clearing}, /* BGP_Stop */ {bgp_stop, Clearing}, /* TCP_connection_open */ {bgp_stop, Clearing}, /* TCP_connection_closed */ {bgp_stop, Clearing}, /* TCP_connection_open_failed */ {bgp_stop, Clearing}, /* TCP_fatal_error */ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ {bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */ {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired */ {bgp_stop, Clearing}, /* Receive_OPEN_message */ {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */ {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ {bgp_stop_with_error, Clearing}, /* BGP_Stop_with_error */ }, { /* Clearing, */ {bgp_ignore, Clearing}, /* BGP_Start */ {bgp_stop, Clearing}, /* BGP_Stop */ {bgp_stop, Clearing}, /* TCP_connection_open */ {bgp_stop, Clearing}, /* TCP_connection_closed */ {bgp_stop, Clearing}, /* TCP_connection_open_failed */ {bgp_stop, Clearing}, /* TCP_fatal_error */ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ {bgp_stop, Clearing}, /* Hold_Timer_expired */ {bgp_stop, Clearing}, /* KeepAlive_timer_expired */ {bgp_stop, Clearing}, /* Receive_OPEN_message */ {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */ {bgp_stop, Clearing}, /* Receive_UPDATE_message */ {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_clearing_completed, Idle}, /* Clearing_Completed */ {bgp_stop_with_error, Clearing}, /* BGP_Stop_with_error */ }, { /* Deleted, */ {bgp_ignore, Deleted}, /* BGP_Start */ {bgp_ignore, Deleted}, /* BGP_Stop */ {bgp_ignore, Deleted}, /* TCP_connection_open */ {bgp_ignore, Deleted}, /* TCP_connection_closed */ {bgp_ignore, Deleted}, /* TCP_connection_open_failed */ {bgp_ignore, Deleted}, /* TCP_fatal_error */ {bgp_ignore, Deleted}, /* ConnectRetry_timer_expired */ {bgp_ignore, Deleted}, /* Hold_Timer_expired */ {bgp_ignore, Deleted}, /* KeepAlive_timer_expired */ {bgp_ignore, Deleted}, /* Receive_OPEN_message */ {bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Deleted}, /* Receive_UPDATE_message */ {bgp_ignore, Deleted}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Deleted}, /* Clearing_Completed */ {bgp_ignore, Deleted}, /* BGP_Stop_with_error */ }, }; static const 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", "Clearing_Completed", "BGP_Stop_with_error", }; /* Execute event process. */ int bgp_event (struct thread *thread) { int ret = 0; 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) && peer->status != next) plog_debug (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. */ if (FSM [peer->status -1][event - 1].func) ret = (*(FSM [peer->status - 1][event - 1].func))(peer); /* When function do not want proceed next job return -1. */ if (ret >= 0) { /* If status is changed. */ if (next != peer->status) bgp_fsm_change_status (peer, next); /* Make sure timer is set. */ bgp_timer_set (peer); } return ret; } quagga-1.2.4/bgpd/bgp_fsm.h000066400000000000000000000044001325323223500154630ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_FSM_H #define _QUAGGA_BGP_FSM_H /* Macro for BGP read, write and timer thread. */ #define BGP_READ_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ THREAD_READ_ON(bm->master,T,F,peer,V); \ } while (0) #define BGP_READ_OFF(T) \ do { \ if (T) \ THREAD_READ_OFF(T); \ } while (0) #define BGP_WRITE_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ THREAD_WRITE_ON(bm->master,(T),(F),peer,(V)); \ } while (0) #define BGP_WRITE_OFF(T) \ do { \ if (T) \ THREAD_WRITE_OFF(T); \ } while (0) #define BGP_TIMER_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ THREAD_TIMER_ON(bm->master,(T),(F),peer,(V)); \ } while (0) #define BGP_TIMER_OFF(T) \ do { \ if (T) \ THREAD_TIMER_OFF(T); \ } while (0) #define BGP_EVENT_ADD(P,E) \ do { \ if ((P)->status != Deleted) \ thread_add_event (bm->master, bgp_event, (P), (E)); \ } while (0) #define BGP_EVENT_FLUSH(P) \ do { \ assert (peer); \ thread_cancel_event (bm->master, (P)); \ } while (0) /* Prototypes. */ extern int bgp_event (struct thread *); extern int bgp_stop (struct peer *peer); extern void bgp_timer_set (struct peer *); extern void bgp_fsm_change_status (struct peer *peer, int status); extern const char *peer_down_str[]; #endif /* _QUAGGA_BGP_FSM_H */ quagga-1.2.4/bgpd/bgp_lcommunity.c000066400000000000000000000316521325323223500171020ustar00rootroot00000000000000/* BGP Large Communities Attribute Copyright (C) 2016 Keyur Patel This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU 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 "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_aspath.h" /* Hash of community attribute. */ static struct hash *lcomhash; /* Allocate a new lcommunities. */ static struct lcommunity * lcommunity_new (void) { return (struct lcommunity *) XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity)); } /* Allocate lcommunities. */ void lcommunity_free (struct lcommunity **lcom) { if ((*lcom)->val) XFREE (MTYPE_LCOMMUNITY_VAL, (*lcom)->val); if ((*lcom)->str) XFREE (MTYPE_LCOMMUNITY_STR, (*lcom)->str); XFREE (MTYPE_LCOMMUNITY, *lcom); lcom = NULL; } /* Add a new Large Communities value to Large 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 lcommunity_add_val (struct lcommunity *lcom, struct lcommunity_val *lval) { u_int8_t *p; int ret; int c; /* When this is fist value, just add it. */ if (lcom->val == NULL) { lcom->size++; lcom->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom_length (lcom)); memcpy (lcom->val, lval->val, LCOMMUNITY_SIZE); return 1; } /* If the value already exists in the structure return 0. */ c = 0; for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++) { ret = memcmp (p, lval->val, LCOMMUNITY_SIZE); if (ret == 0) return 0; if (ret > 0) break; } /* Add the value to the structure with numerical sorting. */ lcom->size++; lcom->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length (lcom)); memmove (lcom->val + (c + 1) * LCOMMUNITY_SIZE, lcom->val + c * LCOMMUNITY_SIZE, (lcom->size - 1 - c) * LCOMMUNITY_SIZE); memcpy (lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE); return 1; } /* This function takes pointer to Large Communites strucutre then create a new Large Communities structure by uniq and sort each Large Communities value. */ struct lcommunity * lcommunity_uniq_sort (struct lcommunity *lcom) { int i; struct lcommunity *new; struct lcommunity_val *lval; if (! lcom) return NULL; new = lcommunity_new (); for (i = 0; i < lcom->size; i++) { lval = (struct lcommunity_val *) (lcom->val + (i * LCOMMUNITY_SIZE)); lcommunity_add_val (new, lval); } return new; } /* Parse Large Communites Attribute in BGP packet. */ struct lcommunity * lcommunity_parse (u_int8_t *pnt, u_short length) { struct lcommunity tmp; struct lcommunity *new; /* Length check. */ if (length % LCOMMUNITY_SIZE) return NULL; /* Prepare tmporary structure for making a new Large Communities Attribute. */ tmp.size = length / LCOMMUNITY_SIZE; tmp.val = pnt; /* Create a new Large Communities Attribute by uniq and sort each Large Communities value */ new = lcommunity_uniq_sort (&tmp); return lcommunity_intern (new); } /* Duplicate the Large Communities Attribute structure. */ struct lcommunity * lcommunity_dup (struct lcommunity *lcom) { struct lcommunity *new; new = XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity)); new->size = lcom->size; if (new->size) { new->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom->size * LCOMMUNITY_SIZE); memcpy (new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE); } else new->val = NULL; return new; } /* Retrun string representation of communities attribute. */ char * lcommunity_str (struct lcommunity *lcom) { if (! lcom->str) lcom->str = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_DISPLAY); return lcom->str; } /* Merge two Large Communities Attribute structure. */ struct lcommunity * lcommunity_merge (struct lcommunity *lcom1, struct lcommunity *lcom2) { if (lcom1->val) lcom1->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom1->val, (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); else lcom1->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); memcpy (lcom1->val + (lcom1->size * LCOMMUNITY_SIZE), lcom2->val, lcom2->size * LCOMMUNITY_SIZE); lcom1->size += lcom2->size; return lcom1; } /* Intern Large Communities Attribute. */ struct lcommunity * lcommunity_intern (struct lcommunity *lcom) { struct lcommunity *find; assert (lcom->refcnt == 0); find = (struct lcommunity *) hash_get (lcomhash, lcom, hash_alloc_intern); if (find != lcom) lcommunity_free (&lcom); find->refcnt++; if (! find->str) find->str = lcommunity_lcom2str (find, LCOMMUNITY_FORMAT_DISPLAY); return find; } /* Unintern Large Communities Attribute. */ void lcommunity_unintern (struct lcommunity **lcom) { struct lcommunity *ret; if ((*lcom)->refcnt) (*lcom)->refcnt--; /* Pull off from hash. */ if ((*lcom)->refcnt == 0) { /* Large community must be in the hash. */ ret = (struct lcommunity *) hash_release (lcomhash, *lcom); assert (ret != NULL); lcommunity_free (lcom); } } /* Utility function to make hash key. */ unsigned int lcommunity_hash_make (void *arg) { const struct lcommunity *lcom = arg; int size = lcom->size * LCOMMUNITY_SIZE; u_int8_t *pnt = lcom->val; unsigned int key = 0; int c; for (c = 0; c < size; c += LCOMMUNITY_SIZE) { key += pnt[c]; key += pnt[c + 1]; key += pnt[c + 2]; key += pnt[c + 3]; key += pnt[c + 4]; key += pnt[c + 5]; key += pnt[c + 6]; key += pnt[c + 7]; key += pnt[c + 8]; key += pnt[c + 9]; key += pnt[c + 10]; key += pnt[c + 11]; } return key; } /* Compare two Large Communities Attribute structure. */ int lcommunity_cmp (const void *arg1, const void *arg2) { const struct lcommunity *lcom1 = arg1; const struct lcommunity *lcom2 = arg2; return (lcom1->size == lcom2->size && memcmp (lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) == 0); } /* Return communities hash. */ struct hash * lcommunity_hash (void) { return lcomhash; } /* Initialize Large Comminities related hash. */ void lcommunity_init (void) { lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp); } void lcommunity_finish (void) { hash_free (lcomhash); lcomhash = NULL; } /* Large Communities token enum. */ enum lcommunity_token { lcommunity_token_unknown = 0, lcommunity_token_val, }; /* Get next Large Communities token from the string. */ static const char * lcommunity_gettoken (const char *str, struct lcommunity_val *lval, enum lcommunity_token *token) { const char *p = str; /* Skip white space. */ while (isspace ((int) *p)) { p++; str++; } /* Check the end of the line. */ if (*p == '\0') return NULL; /* Community value. */ if (isdigit ((int) *p)) { int separator = 0; int digit = 0; u_int32_t globaladmin = 0; u_int32_t localdata1 = 0; u_int32_t localdata2 = 0; while (isdigit ((int) *p) || *p == ':') { if (*p == ':') { if (separator == 2) { *token = lcommunity_token_unknown; return NULL; } else { separator++; digit = 0; if (separator == 1) { globaladmin = localdata2; } else { localdata1 = localdata2; } localdata2 = 0; } } else { digit = 1; localdata2 *= 10; localdata2 += (*p - '0'); } p++; } if (! digit) { *token = lcommunity_token_unknown; return NULL; } /* * Copy the large comm. */ lval->val[0] = (globaladmin >> 24) & 0xff; lval->val[1] = (globaladmin >> 16) & 0xff; lval->val[2] = (globaladmin >> 8) & 0xff; lval->val[3] = globaladmin & 0xff; lval->val[4] = (localdata1 >> 24) & 0xff; lval->val[5] = (localdata1 >> 16) & 0xff; lval->val[6] = (localdata1 >> 8) & 0xff; lval->val[7] = localdata1 & 0xff; lval->val[8] = (localdata2 >> 24) & 0xff; lval->val[9] = (localdata2 >> 16) & 0xff; lval->val[10] = (localdata2 >> 8) & 0xff; lval->val[11] = localdata2 & 0xff; *token = lcommunity_token_val; return p; } *token = lcommunity_token_unknown; return p; } /* Convert string to large community attribute. When type is already known, please specify both str and type. When string includes keyword for each large community value. Please specify keyword_included as non-zero value. */ struct lcommunity * lcommunity_str2com (const char *str) { struct lcommunity *lcom = NULL; enum lcommunity_token token = lcommunity_token_unknown; struct lcommunity_val lval; while ((str = lcommunity_gettoken (str, &lval, &token))) { switch (token) { case lcommunity_token_val: if (lcom == NULL) lcom = lcommunity_new (); lcommunity_add_val (lcom, &lval); break; case lcommunity_token_unknown: default: if (lcom) lcommunity_free (&lcom); return NULL; } } return lcom; } int lcommunity_include (struct lcommunity *lcom, u_char *ptr) { int i; u_char *lcom_ptr; for (i = 0; i < lcom->size; i++) { lcom_ptr = lcom->val + (i * LCOMMUNITY_SIZE); if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0) return 1; } return 0; } /* Convert large community attribute to string. The large coms will be in 65535:65531:0 format. */ char * lcommunity_lcom2str (struct lcommunity *lcom, int format) { int i; u_int8_t *pnt; #define LCOMMUNITY_STR_DEFAULT_LEN 40 int str_size; int str_pnt; char *str_buf; int len = 0; int first = 1; u_int32_t globaladmin, localdata1, localdata2; if (lcom->size == 0) { str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1); str_buf[0] = '\0'; return str_buf; } /* Prepare buffer. */ str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1); str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1; str_pnt = 0; for (i = 0; i < lcom->size; i++) { /* Make it sure size is enough. */ while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size) { str_size *= 2; str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size); } /* Space between each value. */ if (! first) str_buf[str_pnt++] = ' '; pnt = lcom->val + (i * 12); globaladmin = (*pnt++ << 24); globaladmin |= (*pnt++ << 16); globaladmin |= (*pnt++ << 8); globaladmin |= (*pnt++); localdata1 = (*pnt++ << 24); localdata1 |= (*pnt++ << 16); localdata1 |= (*pnt++ << 8); localdata1 |= (*pnt++); localdata2 = (*pnt++ << 24); localdata2 |= (*pnt++ << 16); localdata2 |= (*pnt++ << 8); localdata2 |= (*pnt++); len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin, localdata1, localdata2); str_pnt += len; first = 0; } return str_buf; } int lcommunity_match (const struct lcommunity *lcom1, const struct lcommunity *lcom2) { int i = 0; int j = 0; if (lcom1 == NULL && lcom2 == NULL) return 1; if (lcom1 == NULL || lcom2 == NULL) return 0; if (lcom1->size < lcom2->size) return 0; /* Every community on com2 needs to be on com1 for this to match */ while (i < lcom1->size && j < lcom2->size) { if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0) j++; i++; } if (j == lcom2->size) return 1; else return 0; } /* Delete one lcommunity. */ void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr) { int i = 0; int c = 0; if (! lcom->val) return; while (i < lcom->size) { if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0) { c = lcom->size -i -1; if (c > 0) memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE); lcom->size--; if (lcom->size > 0) lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val, lcom_length (lcom)); else { XFREE (MTYPE_COMMUNITY_VAL, lcom->val); lcom->val = NULL; } return; } i++; } } quagga-1.2.4/bgpd/bgp_lcommunity.h000066400000000000000000000052661325323223500171110ustar00rootroot00000000000000/* BGP Large Communities Attribute. Copyright (C) 2016 Keyur Patel This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU 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 _QUAGGA_BGP_LCOMMUNITY_H #define _QUAGGA_BGP_LCOMMUNITY_H /* Extended communities attribute string format. */ #define LCOMMUNITY_FORMAT_ROUTE_MAP 0 #define LCOMMUNITY_FORMAT_COMMUNITY_LIST 1 #define LCOMMUNITY_FORMAT_DISPLAY 2 /* Large Communities value is twelve octets long. */ #define LCOMMUNITY_SIZE 12 /* Large Communities attribute. */ struct lcommunity { /* Reference counter. */ unsigned long refcnt; /* Size of Extended Communities attribute. */ int size; /* Extended Communities value. */ u_int8_t *val; /* Human readable format string. */ char *str; }; /* Extended community value is eight octet. */ struct lcommunity_val { char val[LCOMMUNITY_SIZE]; }; #define lcom_length(X) ((X)->size * LCOMMUNITY_SIZE) extern void lcommunity_init (void); extern void lcommunity_finish (void); extern void lcommunity_free (struct lcommunity **); extern struct lcommunity *lcommunity_parse (u_int8_t *, u_short); extern struct lcommunity *lcommunity_dup (struct lcommunity *); extern struct lcommunity *lcommunity_merge (struct lcommunity *, struct lcommunity *); extern struct lcommunity *lcommunity_uniq_sort (struct lcommunity *); extern struct lcommunity *lcommunity_intern (struct lcommunity *); extern int lcommunity_cmp (const void *, const void *); extern void lcommunity_unintern (struct lcommunity **); extern unsigned int lcommunity_hash_make (void *); extern struct hash *lcommunity_hash (void); extern struct lcommunity *lcommunity_str2com (const char *); extern char *lcommunity_lcom2str (struct lcommunity *, int); extern int lcommunity_match (const struct lcommunity *, const struct lcommunity *); extern char *lcommunity_str (struct lcommunity *); extern int lcommunity_include (struct lcommunity *lcom, u_char *ptr); extern void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr); #endif /* _QUAGGA_BGP_LCOMMUNITY_H */ quagga-1.2.4/bgpd/bgp_main.c000066400000000000000000000271241325323223500156250ustar00rootroot00000000000000/* 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 #include "memory.h" #include "prefix.h" #include "log.h" #include "privs.h" #include "sigevent.h" #include "zclient.h" #include "routemap.h" #include "filter.h" #include "plist.h" #include "stream.h" #include "vrf.h" #include "workqueue.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_filter.h" #include "bgpd/bgp_zebra.h" /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "bgp_port", required_argument, NULL, 'p'}, { "listenon", required_argument, NULL, 'l'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "no_kernel", no_argument, NULL, 'n'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "skip_runas", no_argument, NULL, 'S'}, { "version", no_argument, NULL, 'v'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { 0 } }; /* signal definitions */ void sighup (void); void sigint (void); void sigusr1 (void); static void bgp_exit (int); static struct quagga_signal_t bgp_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* Configuration file and directory. */ char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG; /* Route retain mode flag. */ static int retain_mode = 0; /* Manually specified configuration file name. */ char *config_file = NULL; /* Process ID saved for use by init system */ static const char *pid_file = PATH_BGPD_PID; /* VTY port number and address. */ int vty_port = BGP_VTY_PORT; char *vty_addr = NULL; /* privileges */ static zebra_capabilities_t _caps_p [] = { ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, }; struct zebra_privs_t bgpd_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), .cap_num_i = 0, }; /* 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\ -z, --socket Set path of zebra socket\n\ -p, --bgp_port Set bgp protocol's port number\n\ -l, --listenon Listen on specified address (implies -n)\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\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -S, --skip_runas Skip user and group run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\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 (void) { 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_default); /* Create VTY's socket */ vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); /* Try to return to normal operation. */ } /* SIGINT handler. */ void sigint (void) { zlog_notice ("Terminating on signal"); if (! retain_mode) { bgp_terminate (); if (bgpd_privs.user) /* NULL if skip_runas flag set */ zprivs_terminate (&bgpd_privs); } bgp_exit (0); } /* SIGUSR1 handler. */ void sigusr1 (void) { zlog_rotate (NULL); } /* Try to free up allocations we know about so that diagnostic tools such as valgrind are able to better illuminate leaks. Zebra route removal and protocol teardown are not meant to be done here. For example, "retain_mode" may be set. */ static void bgp_exit (int status) { struct bgp *bgp; struct listnode *node, *nnode; int *socket; struct interface *ifp; /* it only makes sense for this to be called on a clean exit */ assert (status == 0); /* reverse bgp_master_init */ for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) bgp_delete (bgp); list_free (bm->bgp); bm->bgp = NULL; /* * bgp_delete can re-allocate the process queues after they were * deleted in bgp_terminate. delete them again. * * It might be better to ensure the RIBs (including static routes) * are cleared by bgp_terminate() during its call to bgp_cleanup_routes(), * which currently only deletes the kernel routes. */ if (bm->process_main_queue) { work_queue_free (bm->process_main_queue); bm->process_main_queue = NULL; } if (bm->process_rsclient_queue) { work_queue_free (bm->process_rsclient_queue); bm->process_rsclient_queue = NULL; } /* reverse bgp_master_init */ for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket)) { if (close ((int)(long)socket) == -1) zlog_err ("close (%d): %s", (int)(long)socket, safe_strerror (errno)); } list_delete (bm->listen_sockets); /* reverse bgp_zebra_init/if_init */ if (retain_mode) if_add_hook (IF_DELETE_HOOK, NULL); for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct listnode *c_node, *c_nnode; struct connected *c; for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c)) bgp_connected_delete (c); } /* reverse bgp_attr_init */ bgp_attr_finish (); /* reverse bgp_dump_init */ bgp_dump_finish (); /* reverse bgp_route_init */ bgp_route_finish (); /* reverse bgp_route_map_init/route_map_init */ route_map_finish (); /* reverse access_list_init */ access_list_add_hook (NULL); access_list_delete_hook (NULL); access_list_reset (); /* reverse bgp_filter_init */ as_list_add_hook (NULL); as_list_delete_hook (NULL); bgp_filter_reset (); /* reverse prefix_list_init */ prefix_list_add_hook (NULL); prefix_list_delete_hook (NULL); prefix_list_reset (); /* reverse community_list_init */ community_list_terminate (bgp_clist); vrf_terminate (); cmd_terminate (); vty_terminate (); bgp_address_destroy(); bgp_scan_destroy(); bgp_zebra_destroy(); if (bgp_nexthop_buf) stream_free (bgp_nexthop_buf); if (bgp_ifindices_buf) stream_free (bgp_ifindices_buf); /* reverse bgp_scan_init */ bgp_scan_finish (); /* reverse bgp_master_init */ if (bm->master) thread_master_free (bm->master); if (zlog_default) closezlog (zlog_default); if (CONF_BGP_DEBUG (normal, NORMAL)) log_memstats_stderr ("bgpd"); exit (status); } /* 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; int dryrun = 0; char *progname; int tmp_port; int skip_runas = 0; /* 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_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:i:z:hp:l:A:P:rnu:g:vCS", 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 'z': zclient_serv_path_set (optarg); break; case 'p': tmp_port = atoi (optarg); if (tmp_port <= 0 || tmp_port > 0xffff) bm->port = BGP_PORT_DEFAULT; else bm->port = tmp_port; break; case 'A': vty_addr = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure, and bgpd not listening on bgp port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = BGP_VTY_PORT; break; case 'r': retain_mode = 1; break; case 'l': bm->address = optarg; /* listenon implies -n */ case 'n': bgp_option_set (BGP_OPT_NO_FIB); break; case 'u': bgpd_privs.user = optarg; break; case 'g': bgpd_privs.group = optarg; break; case 'S': /* skip run as = override bgpd_privs */ skip_runas = 1; break; case 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Initializations. */ srandom (time (NULL)); signal_init (bm->master, array_size(bgp_signals), bgp_signals); if (skip_runas) memset (&bgpd_privs, 0, sizeof (bgpd_privs)); zprivs_init (&bgpd_privs); cmd_init (1); vty_init (bm->master); memory_init (); vrf_init (); /* BGP related initialization. */ bgp_init (); /* Parse config file. */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if(dryrun) return(0); /* Turn into daemon if daemon_mode is set. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("BGPd daemon failed: %s", strerror(errno)); return (1); } /* 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_notice ("BGPd %s starting: vty@%d, bgp@%s:%d pid %d", QUAGGA_VERSION, vty_port, (bm->address ? bm->address : ""), bm->port, getpid ()); /* Start finite state machine, here we go! */ thread_main (bm->master); /* Not reached. */ return (0); } quagga-1.2.4/bgpd/bgp_mpath.c000066400000000000000000000532141325323223500160110ustar00rootroot00000000000000/* $QuaggaId: Format:%an, %ai, %h$ $ * * BGP Multipath * Copyright (C) 2010 Google Inc. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "linklist.h" #include "sockunion.h" #include "memory.h" #include "filter.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_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_mpath.h" bool bgp_mpath_is_configured_sort (struct bgp *bgp, bgp_peer_sort_t sort, afi_t afi, safi_t safi) { struct bgp_maxpaths_cfg *cfg = &bgp->maxpaths[afi][safi]; /* XXX: BGP_DEFAULT_MAXPATHS is 1, and this test only seems to make sense * if if it stays 1, so not sure the DEFAULT define is that useful. */ switch (sort) { case BGP_PEER_IBGP: return cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS; case BGP_PEER_EBGP: return cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS; default: return false; } } bool bgp_mpath_is_configured (struct bgp *bgp, afi_t afi, safi_t safi) { return bgp_mpath_is_configured_sort (bgp, BGP_PEER_IBGP, afi, safi) || bgp_mpath_is_configured_sort (bgp, BGP_PEER_EBGP, afi, safi); } /* * bgp_maximum_paths_set * * Record maximum-paths configuration for BGP instance */ int bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi, int peertype, u_int16_t maxpaths) { if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX)) return -1; switch (peertype) { case BGP_PEER_IBGP: bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths; break; case BGP_PEER_EBGP: bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths; break; default: return -1; } return 0; } /* * bgp_maximum_paths_unset * * Remove maximum-paths configuration from BGP instance */ int bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi, int peertype) { if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX)) return -1; switch (peertype) { case BGP_PEER_IBGP: bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; break; case BGP_PEER_EBGP: bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; break; default: return -1; } return 0; } /* * bgp_info_nexthop_cmp * * Compare the nexthops of two paths. Return value is less than, equal to, * or greater than zero if bi1 is respectively less than, equal to, * or greater than bi2. */ static int bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) { struct attr_extra *ae1, *ae2; int compare; ae1 = bi1->attr->extra; ae2 = bi2->attr->extra; compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop); if (!compare && ae1 && ae2) { if (ae1->mp_nexthop_len == ae2->mp_nexthop_len) { switch (ae1->mp_nexthop_len) { case 4: case 12: compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in); break; case 16: compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global); break; case 32: compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global); if (!compare) compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local); break; } } /* This can happen if one IPv6 peer sends you global and link-local * nexthops but another IPv6 peer only sends you global */ else if (ae1->mp_nexthop_len == 16 || ae1->mp_nexthop_len == 32) { compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global); if (!compare) { if (ae1->mp_nexthop_len < ae2->mp_nexthop_len) compare = -1; else compare = 1; } } } return compare; } /* * bgp_info_mpath_cmp * * This function determines our multipath list ordering. By ordering * the list we can deterministically select which paths are included * in the multipath set. The ordering also helps in detecting changes * in the multipath selection so we can detect whether to send an * update to zebra. * * The order of paths is determined first by received nexthop, and then * by peer address if the nexthops are the same. */ static int bgp_info_mpath_cmp (void *val1, void *val2) { struct bgp_info *bi1, *bi2; int compare; bi1 = val1; bi2 = val2; compare = bgp_info_nexthop_cmp (bi1, bi2); if (!compare) compare = sockunion_cmp (bi1->peer->su_remote, bi2->peer->su_remote); return compare; } /* * bgp_mp_list_init * * Initialize the mp_list, which holds the list of multipaths * selected by bgp_best_selection */ void bgp_mp_list_init (struct list *mp_list) { assert (mp_list); memset (mp_list, 0, sizeof (struct list)); mp_list->cmp = bgp_info_mpath_cmp; } /* * bgp_mp_list_clear * * Clears all entries out of the mp_list */ void bgp_mp_list_clear (struct list *mp_list) { assert (mp_list); list_delete_all_node (mp_list); } /* * bgp_mp_list_add * * Adds a multipath entry to the mp_list */ void bgp_mp_list_add (struct list *mp_list, struct bgp_info *mpinfo) { assert (mp_list && mpinfo); listnode_add_sort (mp_list, mpinfo); } /* * bgp_info_mpath_new * * Allocate and zero memory for a new bgp_info_mpath element */ static struct bgp_info_mpath * bgp_info_mpath_new (void) { struct bgp_info_mpath *new_mpath; new_mpath = XCALLOC (MTYPE_BGP_MPATH_INFO, sizeof (struct bgp_info_mpath)); return new_mpath; } /* * bgp_info_mpath_free * * Release resources for a bgp_info_mpath element and zero out pointer */ void bgp_info_mpath_free (struct bgp_info_mpath **mpath) { if (mpath && *mpath) { if ((*mpath)->mp_attr) bgp_attr_unintern (&(*mpath)->mp_attr); XFREE (MTYPE_BGP_MPATH_INFO, *mpath); *mpath = NULL; } } /* * bgp_info_mpath_get * * Fetch the mpath element for the given bgp_info. Used for * doing lazy allocation. */ static struct bgp_info_mpath * bgp_info_mpath_get (struct bgp_info *binfo) { struct bgp_info_mpath *mpath; if (!binfo->mpath) { mpath = bgp_info_mpath_new(); if (!mpath) return NULL; binfo->mpath = mpath; mpath->mp_info = binfo; } return binfo->mpath; } /* * bgp_info_mpath_enqueue * * Enqueue a path onto the multipath list given the previous multipath * list entry */ static void bgp_info_mpath_enqueue (struct bgp_info *prev_info, struct bgp_info *binfo) { struct bgp_info_mpath *prev, *mpath; prev = bgp_info_mpath_get (prev_info); mpath = bgp_info_mpath_get (binfo); if (!prev || !mpath) return; mpath->mp_next = prev->mp_next; mpath->mp_prev = prev; if (prev->mp_next) prev->mp_next->mp_prev = mpath; prev->mp_next = mpath; SET_FLAG (binfo->flags, BGP_INFO_MULTIPATH); } /* * bgp_info_mpath_dequeue * * Remove a path from the multipath list */ void bgp_info_mpath_dequeue (struct bgp_info *binfo) { struct bgp_info_mpath *mpath = binfo->mpath; if (!mpath) return; if (mpath->mp_prev) mpath->mp_prev->mp_next = mpath->mp_next; if (mpath->mp_next) mpath->mp_next->mp_prev = mpath->mp_prev; mpath->mp_next = mpath->mp_prev = NULL; UNSET_FLAG (binfo->flags, BGP_INFO_MULTIPATH); } /* * bgp_info_mpath_next * * Given a bgp_info, return the next multipath entry */ struct bgp_info * bgp_info_mpath_next (struct bgp_info *binfo) { if (!binfo->mpath || !binfo->mpath->mp_next) return NULL; return binfo->mpath->mp_next->mp_info; } /* * bgp_info_mpath_first * * Given bestpath bgp_info, return the first multipath entry. */ struct bgp_info * bgp_info_mpath_first (struct bgp_info *binfo) { return bgp_info_mpath_next (binfo); } /* * bgp_info_mpath_count * * Given the bestpath bgp_info, return the number of multipath entries */ u_int32_t bgp_info_mpath_count (struct bgp_info *binfo) { if (!binfo->mpath) return 0; return binfo->mpath->mp_count; } /* * bgp_info_mpath_count_set * * Sets the count of multipaths into bestpath's mpath element */ static void bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count) { struct bgp_info_mpath *mpath; if (!count && !binfo->mpath) return; mpath = bgp_info_mpath_get (binfo); if (!mpath) return; mpath->mp_count = count; } /* * bgp_info_mpath_attr * * Given bestpath bgp_info, return aggregated attribute set used * for advertising the multipath route */ struct attr * bgp_info_mpath_attr (struct bgp_info *binfo) { if (!binfo->mpath) return NULL; return binfo->mpath->mp_attr; } /* * bgp_info_mpath_attr_set * * Sets the aggregated attribute into bestpath's mpath element */ static void bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr) { struct bgp_info_mpath *mpath; if (!attr && !binfo->mpath) return; mpath = bgp_info_mpath_get (binfo); if (!mpath) return; mpath->mp_attr = attr; } /* * bgp_info_mpath_update * * Compare and sync up the multipath list with the mp_list generated by * bgp_best_selection */ void bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, struct bgp_info *old_best, struct list *mp_list, afi_t afi, safi_t safi) { u_int16_t maxpaths, mpath_count, old_mpath_count; struct listnode *mp_node, *mp_next_node; struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; int mpath_changed, debug; char pfx_buf[INET6_ADDRSTRLEN], nh_buf[2][INET6_ADDRSTRLEN]; struct bgp_maxpaths_cfg *mpath_cfg = NULL; mpath_changed = 0; maxpaths = BGP_DEFAULT_MAXPATHS; mpath_count = 0; cur_mpath = NULL; old_mpath_count = 0; prev_mpath = new_best; mp_node = listhead (mp_list); debug = BGP_DEBUG (events, EVENTS); if (debug) prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf)); if (new_best) { mpath_cfg = &new_best->peer->bgp->maxpaths[afi][safi]; mpath_count++; if (new_best != old_best) bgp_info_mpath_dequeue (new_best); maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ? mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp; } if (old_best) { cur_mpath = bgp_info_mpath_first (old_best); old_mpath_count = bgp_info_mpath_count (old_best); bgp_info_mpath_count_set (old_best, 0); bgp_info_mpath_dequeue (old_best); } /* * We perform an ordered walk through both lists in parallel. * The reason for the ordered walk is that if there are paths * that were previously multipaths and are still multipaths, the walk * should encounter them in both lists at the same time. Otherwise * there will be paths that are in one list or another, and we * will deal with these separately. * * Note that new_best might be somewhere in the mp_list, so we need * to skip over it */ while (mp_node || cur_mpath) { /* * We can bail out of this loop if all existing paths on the * multipath list have been visited (for cleanup purposes) and * the maxpath requirement is fulfulled */ if (!cur_mpath && (mpath_count >= maxpaths)) break; mp_next_node = mp_node ? listnextnode (mp_node) : NULL; next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL; /* * If equal, the path was a multipath and is still a multipath. * Insert onto new multipath list if maxpaths allows. */ if (mp_node && (listgetdata (mp_node) == cur_mpath)) { list_delete_node (mp_list, mp_node); bgp_info_mpath_dequeue (cur_mpath); if ((mpath_count < maxpaths) && bgp_info_nexthop_cmp (prev_mpath, cur_mpath)) { bgp_info_mpath_enqueue (prev_mpath, cur_mpath); prev_mpath = cur_mpath; mpath_count++; } else { mpath_changed = 1; if (debug) zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf, inet_ntop (AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), sockunion2str (cur_mpath->peer->su_remote, nh_buf[1], sizeof (nh_buf[1]))); } mp_node = mp_next_node; cur_mpath = next_mpath; continue; } if (cur_mpath && (!mp_node || (bgp_info_mpath_cmp (cur_mpath, listgetdata (mp_node)) < 0))) { /* * If here, we have an old multipath and either the mp_list * is finished or the next mp_node points to a later * multipath, so we need to purge this path from the * multipath list */ bgp_info_mpath_dequeue (cur_mpath); mpath_changed = 1; if (debug) zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf, inet_ntop (AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), sockunion2str (cur_mpath->peer->su_remote, nh_buf[1], sizeof (nh_buf[1]))); cur_mpath = next_mpath; } else { /* * If here, we have a path on the mp_list that was not previously * a multipath (due to non-equivalance or maxpaths exceeded), * or the matching multipath is sorted later in the multipath * list. Before we enqueue the path on the new multipath list, * make sure its not on the old_best multipath list or referenced * via next_mpath: * - If next_mpath points to this new path, update next_mpath to * point to the multipath after this one * - Dequeue the path from the multipath list just to make sure */ new_mpath = listgetdata (mp_node); list_delete_node (mp_list, mp_node); if ((mpath_count < maxpaths) && (new_mpath != new_best) && bgp_info_nexthop_cmp (prev_mpath, new_mpath)) { if (new_mpath == next_mpath) next_mpath = bgp_info_mpath_next (new_mpath); bgp_info_mpath_dequeue (new_mpath); bgp_info_mpath_enqueue (prev_mpath, new_mpath); prev_mpath = new_mpath; mpath_changed = 1; mpath_count++; if (debug) zlog_debug ("%s add mpath nexthop %s peer %s", pfx_buf, inet_ntop (AF_INET, &new_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), sockunion2str (new_mpath->peer->su_remote, nh_buf[1], sizeof (nh_buf[1]))); } mp_node = mp_next_node; } } if (new_best) { bgp_info_mpath_count_set (new_best, mpath_count-1); if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count)) SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG); } } /* * bgp_mp_dmed_deselect * * Clean up multipath information for BGP_INFO_DMED_SELECTED path that * is not selected as best path */ void bgp_mp_dmed_deselect (struct bgp_info *dmed_best) { struct bgp_info *mpinfo, *mpnext; if (!dmed_best) return; for (mpinfo = bgp_info_mpath_first (dmed_best); mpinfo; mpinfo = mpnext) { mpnext = bgp_info_mpath_next (mpinfo); bgp_info_mpath_dequeue (mpinfo); } bgp_info_mpath_count_set (dmed_best, 0); UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG); assert (bgp_info_mpath_first (dmed_best) == 0); } /* * bgp_info_mpath_aggregate_update * * Set the multipath aggregate attribute. We need to see if the * aggregate has changed and then set the ATTR_CHANGED flag on the * bestpath info so that a peer update will be generated. The * change is detected by generating the current attribute, * interning it, and then comparing the interned pointer with the * current value. We can skip this generate/compare step if there * is no change in multipath selection and no attribute change in * any multipath. */ void bgp_info_mpath_aggregate_update (struct bgp_info *new_best, struct bgp_info *old_best) { struct bgp_info *mpinfo; struct aspath *aspath; struct aspath *asmerge; struct attr *new_attr, *old_attr; u_char origin, attr_chg; struct community *community, *commerge; struct ecommunity *ecomm, *ecommerge; struct lcommunity *lcomm, *lcommerge; struct attr_extra *ae; struct attr attr = { 0 }; if (old_best && (old_best != new_best) && (old_attr = bgp_info_mpath_attr (old_best))) { bgp_attr_unintern (&old_attr); bgp_info_mpath_attr_set (old_best, NULL); } if (!new_best) return; if (!bgp_info_mpath_count (new_best)) { if ((new_attr = bgp_info_mpath_attr (new_best))) { bgp_attr_unintern (&new_attr); bgp_info_mpath_attr_set (new_best, NULL); SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); } return; } /* * Bail out here if the following is true: * - MULTIPATH_CHG bit is not set on new_best, and * - No change in bestpath, and * - ATTR_CHANGED bit is not set on new_best or any of the multipaths */ if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) && (old_best == new_best)) { attr_chg = 0; if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED)) attr_chg = 1; else for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED)) { attr_chg = 1; break; } } if (!attr_chg) { assert (bgp_info_mpath_attr (new_best)); return; } } bgp_attr_dup (&attr, new_best->attr); /* aggregate attribute from multipath constituents */ aspath = aspath_dup (attr.aspath); origin = attr.origin; community = attr.community ? community_dup (attr.community) : NULL; ae = attr.extra; ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL; lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL; for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { asmerge = aspath_aggregate_mpath (aspath, mpinfo->attr->aspath); aspath_free (aspath); aspath = asmerge; if (origin < mpinfo->attr->origin) origin = mpinfo->attr->origin; if (mpinfo->attr->community) { if (community) { commerge = community_merge (community, mpinfo->attr->community); community = community_uniq_sort (commerge); community_free (commerge); } else community = community_dup (mpinfo->attr->community); } ae = mpinfo->attr->extra; if (ae && ae->ecommunity) { if (ecomm) { ecommerge = ecommunity_merge (ecomm, ae->ecommunity); ecomm = ecommunity_uniq_sort (ecommerge); ecommunity_free (&ecommerge); } else ecomm = ecommunity_dup (ae->ecommunity); } if (ae && ae->lcommunity) { if (lcomm) { lcommerge = lcommunity_merge (lcomm, ae->lcommunity); lcomm = lcommunity_uniq_sort (lcommerge); lcommunity_free (&lcommerge); } else lcomm = lcommunity_dup (ae->lcommunity); } } attr.aspath = aspath; attr.origin = origin; if (community) { attr.community = community; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); } if (ecomm) { ae = bgp_attr_extra_get (&attr); ae->ecommunity = ecomm; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } /* Zap multipath attr nexthop so we set nexthop to self */ attr.nexthop.s_addr = 0; if (attr.extra) memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr)); /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */ new_attr = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); if (new_attr != bgp_info_mpath_attr (new_best)) { if ((old_attr = bgp_info_mpath_attr (new_best))) bgp_attr_unintern (&old_attr); bgp_info_mpath_attr_set (new_best, new_attr); SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); } else bgp_attr_unintern (&new_attr); } quagga-1.2.4/bgpd/bgp_mpath.h000066400000000000000000000061001325323223500160060ustar00rootroot00000000000000/* $QuaggaId: Format:%an, %ai, %h$ $ * * BGP Multipath * Copyright (C) 2010 Google Inc. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_BGP_MPATH_H #define _QUAGGA_BGP_MPATH_H /* BGP default maximum-paths */ #define BGP_DEFAULT_MAXPATHS 1 /* Supplemental information linked to bgp_info for keeping track of * multipath selections, lazily allocated to save memory */ struct bgp_info_mpath { /* Points to the first multipath (on bestpath) or the next multipath */ struct bgp_info_mpath *mp_next; /* Points to the previous multipath or NULL on bestpath */ struct bgp_info_mpath *mp_prev; /* Points to bgp_info associated with this multipath info */ struct bgp_info *mp_info; /* When attached to best path, the number of selected multipaths */ u_int32_t mp_count; /* Aggregated attribute for advertising multipath route */ struct attr *mp_attr; }; /* Functions to support maximum-paths configuration */ extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int, u_int16_t); extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int); bool bgp_mpath_is_configured_sort (struct bgp *, bgp_peer_sort_t, afi_t, safi_t); bool bgp_mpath_is_configured (struct bgp *, afi_t, safi_t); /* Functions used by bgp_best_selection to record current * multipath selections */ extern void bgp_mp_list_init (struct list *); extern void bgp_mp_list_clear (struct list *); extern void bgp_mp_list_add (struct list *, struct bgp_info *); extern void bgp_mp_dmed_deselect (struct bgp_info *); extern void bgp_info_mpath_update (struct bgp_node *, struct bgp_info *, struct bgp_info *, struct list *, afi_t, safi_t); extern void bgp_info_mpath_aggregate_update (struct bgp_info *, struct bgp_info *); /* Unlink and free multipath information associated with a bgp_info */ extern void bgp_info_mpath_dequeue (struct bgp_info *); extern void bgp_info_mpath_free (struct bgp_info_mpath **); /* Walk list of multipaths associated with a best path */ extern struct bgp_info *bgp_info_mpath_first (struct bgp_info *); extern struct bgp_info *bgp_info_mpath_next (struct bgp_info *); /* Accessors for multipath information */ extern u_int32_t bgp_info_mpath_count (struct bgp_info *); extern struct attr *bgp_info_mpath_attr (struct bgp_info *); #endif /* _QUAGGA_BGP_MPATH_H */ quagga-1.2.4/bgpd/bgp_mplsvpn.c000066400000000000000000000727421325323223500164060ustar00rootroot00000000000000/* 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 "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_packet.h" static 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; } /* type == RD_TYPE_AS */ static 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; } /* type == RD_TYPE_AS4 */ static void decode_rd_as4 (u_char *pnt, struct rd_as *rd_as) { rd_as->as = (u_int32_t) *pnt++ << 24; rd_as->as |= (u_int32_t) *pnt++ << 16; rd_as->as |= (u_int32_t) *pnt++ << 8; rd_as->as |= (u_int32_t) *pnt++; rd_as->val = ((u_int16_t) *pnt++ << 8); rd_as->val |= (u_int16_t) *pnt; } /* type == RD_TYPE_IP */ static 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_nlri_parse_vpn (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) { u_char *pnt; u_char *lim; struct prefix p; int psize = 0; int prefixlen; 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; #define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */ for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ memset (&p, 0, sizeof (struct prefix)); /* Fetch prefix length. */ prefixlen = *pnt++; p.family = afi2family (packet->afi); psize = PSIZE (prefixlen); /* sanity check against packet data */ if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8) { plog_err (peer->log, "%s [Error] Update packet error / VPNv4" " (prefix length %d less than VPNv4 min length)", peer->host, prefixlen); return -1; } if ((pnt + psize) > lim) { plog_err (peer->log, "%s [Error] Update packet error / VPNv4" " (psize %u exceeds packet size (%u)", peer->host, prefixlen, (uint)(lim-pnt)); return -1; } /* sanity check against storage for the IP address portion */ if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t) sizeof(p.u)) { plog_err (peer->log, "%s [Error] Update packet error / VPNv4" " (psize %u exceeds storage size (%zu)", peer->host, prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u)); return -1; } /* Sanity check against max bitlen of the address family */ if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen (&p)) { plog_err (peer->log, "%s [Error] Update packet error / VPNv4" " (psize %u exceeds family (%u) max byte len %u)", peer->host, prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, p.family, prefix_blen (&p)); return -1; } /* 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); switch (type) { case RD_TYPE_AS: decode_rd_as (pnt + 5, &rd_as); break; case RD_TYPE_AS4: decode_rd_as4 (pnt + 5, &rd_as); break; case RD_TYPE_IP: decode_rd_ip (pnt + 5, &rd_ip); break; default: zlog_err ("Unknown RD type %d", type); break; /* just report */ } p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8; memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, psize - VPN_PREFIXLEN_MIN_BYTES); if (attr) bgp_update (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); else bgp_withdraw (peer, &p, attr, packet->afi, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); } /* Packet length consistency check. */ if (pnt != lim) { plog_err (peer->log, "%s [Error] Update packet error / VPNv4" " (%zu data remaining after parsing)", peer->host, lim - pnt); return -1; } return 0; #undef VPN_PREFIXLEN_MIN_BYTES } int str2prefix_rd (const char *str, struct prefix_rd *prd) { int ret; /* ret of called functions */ int lret; /* local ret, of this func */ char *p; char *p2; struct stream *s = NULL; char *half = NULL; struct in_addr addr; s = stream_new (8); prd->family = AF_UNSPEC; prd->prefixlen = 64; lret = 0; p = strchr (str, ':'); if (! p) goto out; if (! all_digit (p + 1)) goto out; 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)) goto out; 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) goto out; stream_putw (s, RD_TYPE_IP); stream_put_in_addr (s, &addr); stream_putw (s, atol (p + 1)); } memcpy (prd->val, s->data, 8); lret = 1; out: if (s) stream_free (s); if (half) XFREE(MTYPE_TMP, half); return lret; } int str2tag (const char *str, u_char *tag) { unsigned long l; char *endptr; u_int32_t t; if (*str == '-') return 0; errno = 0; l = strtoul (str, &endptr, 10); if (*endptr != '\0' || errno || l > UINT32_MAX) return 0; t = (u_int32_t) l; tag[0] = (u_char)(t >> 12); tag[1] = (u_char)(t >> 4); tag[2] = (u_char)(t << 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, "%u:%d", rd_as.as, rd_as.val); return buf; } else if (type == RD_TYPE_AS4) { decode_rd_as4 (pnt + 2, &rd_as); snprintf (buf, size, "%u:%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_safi (SAFI_MPLS_VPN, vty, argv[0], argv[1], argv[2], NULL); } DEFUN (vpnv4_network_route_map, vpnv4_network_route_map_cmd, "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD route-map 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" "route map\n" "route map name\n") { return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[0], argv[1], argv[2], argv[3]); } /* 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_safi (SAFI_MPLS_VPN, vty, argv[0], argv[1], argv[2]); } static 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_AS4) decode_rd_as4 (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, "%u:%d", rd_as.as, rd_as.val); else if (type == RD_TYPE_AS4) vty_out (vty, "%u:%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 }; static int bgp_show_mpls_vpn( struct vty *vty, afi_t afi, 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"; unsigned long output_count = 0; unsigned long total_count = 0; bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } if ((afi != AFI_IP) && (afi != AFI_IP6)) { vty_out (vty, "Afi %d not supported%s", afi, VTY_NEWLINE); return CMD_WARNING; } for (rn = bgp_table_top (bgp->rib[afi][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) { total_count++; 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_AS4) decode_rd_as4 (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, "as2 %u:%d", rd_as.as, rd_as.val); else if (type == RD_TYPE_AS4) vty_out (vty, "as4 %u:%d", rd_as.as, rd_as.val); else if (type == RD_TYPE_IP) vty_out (vty, "ip %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); output_count++; } } } if (output_count == 0) { vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); } else vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (show_bgp_ipv4_vpn, show_bgp_ipv4_vpn_cmd, "show bgp ipv4 vpn", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\n") { return bgp_show_mpls_vpn (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 0); } DEFUN (show_bgp_ipv6_vpn, show_bgp_ipv6_vpn_cmd, "show bgp ipv6 vpn", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\n") { return bgp_show_mpls_vpn (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 0); } DEFUN (show_bgp_ipv4_vpn_rd, show_bgp_ipv4_vpn_rd_cmd, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn", SHOW_STR BGP_STR "Address Family\n" "Display VPN 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, AFI_IP, &prd, bgp_show_type_normal, NULL, 0); } DEFUN (show_bgp_ipv6_vpn_rd, show_bgp_ipv6_vpn_rd_cmd, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn", SHOW_STR BGP_STR "Address Family\n" "Display VPN 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, AFI_IP6, &prd, bgp_show_type_normal, NULL, 0); } DEFUN (show_bgp_ipv4_vpn_tags, show_bgp_ipv4_vpn_tags_cmd, "show bgp ipv4 vpn tags", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\n" "Display BGP tags for prefixes\n") { return bgp_show_mpls_vpn (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 1); } DEFUN (show_bgp_ipv6_vpn_tags, show_bgp_ipv6_vpn_tags_cmd, "show bgp ipv6 vpn tags", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\n" "Display BGP tags for prefixes\n") { return bgp_show_mpls_vpn (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 1); } DEFUN (show_bgp_ipv4_vpn_rd_tags, show_bgp_ipv4_vpn_rd_tags_cmd, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn tags", SHOW_STR BGP_STR "Address Family\n" "Display VPN 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, AFI_IP, &prd, bgp_show_type_normal, NULL, 1); } DEFUN (show_bgp_ipv6_vpn_rd_tags, show_bgp_ipv6_vpn_rd_tags_cmd, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn tags", SHOW_STR BGP_STR "Address Family\n" "Display VPN 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, AFI_IP6, &prd, bgp_show_type_normal, NULL, 1); } DEFUN (show_bgp_ipv4_vpn_neighbor_routes, show_bgp_ipv4_vpn_neighbor_routes_cmd, "show bgp ipv4 vpn neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific 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") { union sockunion su; struct peer *peer; int ret; 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 bgp_show_mpls_vpn (vty, AFI_IP, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv6_vpn_neighbor_routes, show_bgp_ipv6_vpn_neighbor_routes_cmd, "show bgp ipv6 vpn neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific 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") { union sockunion su; struct peer *peer; int ret; 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_IP6][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, AFI_IP6, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv4_vpn_neighbor_advertised_routes, show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd, "show bgp ipv4 vpn neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\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_bgp_ipv6_vpn_neighbor_advertised_routes, show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd, "show bgp ipv6 vpn neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\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_IP6][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_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Address Family\n" "Display VPN 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" "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[1], 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); } DEFUN (show_ip_bgp_vpnv6_rd_neighbor_advertised_routes, show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Address Family\n" "Display VPN 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" "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[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP6][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); } DEFUN (show_bgp_ipv4_vpn_rd_neighbor_routes, show_bgp_ipv4_vpn_rd_neighbor_routes_cmd, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Address Family\n" "Address Family modifier\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; } if (str2sockunion(argv[1], &su)) { vty_out (vty, "Malformed address: %s%s", argv[1], 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, AFI_IP, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_bgp_ipv6_vpn_rd_neighbor_routes, show_bgp_ipv6_vpn_rd_neighbor_routes_cmd, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Address Family\n" "Address Family modifier\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; } if (str2sockunion(argv[1], &su)) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP6][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, AFI_IP6, &prd, bgp_show_type_neighbor, &su, 0); } void bgp_mplsvpn_init (void) { install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd); install_element (BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd); install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_tags_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_tags_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_tags_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_tags_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_routes_cmd); } quagga-1.2.4/bgpd/bgp_mplsvpn.h000066400000000000000000000026661325323223500164110ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_MPLSVPN_H #define _QUAGGA_BGP_MPLSVPN_H #define RD_TYPE_AS 0 #define RD_TYPE_IP 1 #define RD_TYPE_AS4 2 #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; }; extern void bgp_mplsvpn_init (void); extern int bgp_nlri_parse_vpn (struct peer *, struct attr *, struct bgp_nlri *); extern u_int32_t decode_label (u_char *); extern int str2prefix_rd (const char *, struct prefix_rd *); extern int str2tag (const char *, u_char *); extern char *prefix_rd2str (struct prefix_rd *, char *, size_t); #endif /* _QUAGGA_BGP_MPLSVPN_H */ quagga-1.2.4/bgpd/bgp_network.c000066400000000000000000000334101325323223500163650ustar00rootroot00000000000000/* 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 "sockopt.h" #include "memory.h" #include "log.h" #include "if.h" #include "prefix.h" #include "command.h" #include "privs.h" #include "linklist.h" #include "network.h" #include "filter.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" extern struct zebra_privs_t bgpd_privs; /* BGP listening socket. */ struct bgp_listener { int fd; union sockunion su; struct thread *thread; }; /* * Set MD5 key for the socket, for the given IPv4 peer address. * If the password is NULL or zero-length, the option will be disabled. */ static int bgp_md5_set_socket (int socket, union sockunion *su, const char *password) { int ret = -1; int en = ENOSYS; assert (socket >= 0); #if HAVE_DECL_TCP_MD5SIG ret = sockopt_tcp_signature (socket, su, password); en = errno; #endif /* HAVE_TCP_MD5SIG */ if (ret < 0) zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s", socket, safe_strerror (en)); return ret; } /* Helper for bgp_connect */ static int bgp_md5_set_connect (int socket, union sockunion *su, const char *password) { int ret = -1; #if HAVE_DECL_TCP_MD5SIG if ( bgpd_privs.change (ZPRIVS_RAISE) ) { zlog_err ("%s: could not raise privs", __func__); return ret; } ret = bgp_md5_set_socket (socket, su, password); if (bgpd_privs.change (ZPRIVS_LOWER) ) zlog_err ("%s: could not lower privs", __func__); #endif /* HAVE_TCP_MD5SIG */ return ret; } int bgp_md5_set (struct peer *peer) { struct listnode *node; int ret = 0; struct bgp_listener *listener; if ( bgpd_privs.change (ZPRIVS_RAISE) ) { zlog_err ("%s: could not raise privs", __func__); return -1; } /* Just set the password on the listen socket(s). Outbound connections * are taken care of in bgp_connect() below. */ for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) if (listener->su.sa.sa_family == peer->su.sa.sa_family) { ret = bgp_md5_set_socket (listener->fd, &peer->su, peer->password); break; } if (bgpd_privs.change (ZPRIVS_LOWER) ) zlog_err ("%s: could not lower privs", __func__); return ret; } /* Update BGP socket send buffer size */ static void bgp_update_sock_send_buffer_size (int fd) { int size = BGP_SOCKET_SNDBUF_SIZE; int optval; socklen_t optlen = sizeof(optval); if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) { zlog_err("getsockopt of SO_SNDBUF failed %s\n", safe_strerror(errno)); return; } if (optval < size) { if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) { zlog_err("Couldn't increase send buffer: %s\n", safe_strerror(errno)); } } } void bgp_set_socket_ttl (struct peer *peer, int bgp_sock) { char buf[INET_ADDRSTRLEN]; int ret, ttl, minttl; if (bgp_sock < 0) return; if (peer->gtsm_hops) { ttl = 255; minttl = 256 - peer->gtsm_hops; } else { ttl = peer_ttl (peer); minttl = 0; } ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, ttl); if (ret) zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", __func__, inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), errno); ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock, minttl); if (ret && (errno != ENOTSUP || minttl)) zlog_err ("%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d", __func__, inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), errno); } /* Accept bgp connection. */ static int bgp_accept (struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct bgp_listener *listener = THREAD_ARG(thread); struct peer *peer; struct peer *peer1; char buf[SU_ADDRSTRLEN]; /* Register accept thread. */ accept_sock = THREAD_FD (thread); if (accept_sock < 0) { zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } listener->thread = thread_add_read (bm->master, bgp_accept, listener, accept_sock); /* Accept client connection. */ bgp_sock = sockunion_accept (accept_sock, &su); if (bgp_sock < 0) { zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno)); return -1; } set_nonblocking (bgp_sock); /* Set socket send buffer size */ bgp_update_sock_send_buffer_size(bgp_sock); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s:%d", inet_sutop (&su, buf), sockunion_get_port (&su)); /* Check remote IP address */ peer1 = peer_lookup (NULL, &su); /* We could perhaps just drop new connections from already Established * peers here. */ if (! peer1 || peer1->status == Idle || peer1->status > Established) { if (BGP_DEBUG (events, EVENTS)) { if (! peer1) zlog_debug ("[Event] BGP connection IP address %s is not configured", inet_sutop (&su, buf)); else zlog_debug ("[Event] BGP connection IP address %s is %s state", inet_sutop (&su, buf), LOOKUP (bgp_status_msg, peer1->status)); } close (bgp_sock); return -1; } bgp_set_socket_ttl (peer1, bgp_sock); /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] Make dummy peer structure until read Open packet"); { char buf[SU_ADDRSTRLEN]; peer = peer_create_accept (peer1->bgp); peer->su = su; peer->fd = bgp_sock; peer->status = Active; /* Config state that should affect OPEN packet must be copied over */ peer->local_id = peer1->local_id; peer->v_holdtime = peer1->v_holdtime; peer->v_keepalive = peer1->v_keepalive; peer->local_as = peer1->local_as; peer->change_local_as = peer1->change_local_as; peer->flags = peer1->flags; peer->sflags = peer1->sflags; #define PEER_ARRAY_COPY(D,S,A) \ memcpy ((D)->A, (S)->A, sizeof (((D)->A)[0][0])*AFI_MAX*SAFI_MAX); PEER_ARRAY_COPY(peer, peer1, afc); PEER_ARRAY_COPY(peer, peer1, af_flags); #undef PEER_ARRAY_COPY /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); } BGP_EVENT_ADD (peer, TCP_connection_open); return 0; } /* BGP socket bind. */ static int bgp_bind (struct peer *peer) { #ifdef SO_BINDTODEVICE int ret; struct ifreq ifreq; int myerrno; if (! peer->ifname) return 0; strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name)); if ( bgpd_privs.change (ZPRIVS_RAISE) ) zlog_err ("bgp_bind: could not raise privs"); ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof (ifreq)); myerrno = errno; if (bgpd_privs.change (ZPRIVS_LOWER) ) zlog_err ("bgp_bind: could not lower privs"); if (ret < 0) { zlog (peer->log, LOG_INFO, "bind to interface %s failed, errno=%d", peer->ifname, myerrno); return ret; } #endif /* SO_BINDTODEVICE */ return 0; } static int bgp_update_address (struct interface *ifp, const union sockunion *dst, union sockunion *addr) { struct prefix *p, *sel, d; struct connected *connected; struct listnode *node; int common; sockunion2hostprefix (dst, &d); sel = NULL; common = -1; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { p = connected->address; if (p->family != d.family) continue; if (prefix_common_bits (p, &d) > common) { sel = p; common = prefix_common_bits (sel, &d); } } if (!sel) return 1; prefix2sockunion (sel, addr); return 0; } /* Update source selection. */ static void bgp_update_source (struct peer *peer) { struct interface *ifp; union sockunion addr; /* Source is specified with interface name. */ if (peer->update_if) { ifp = if_lookup_by_name (peer->update_if); if (! ifp) return; if (bgp_update_address (ifp, &peer->su, &addr)) return; sockunion_bind (peer->fd, &addr, 0, &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) { ifindex_t ifindex = 0; /* Make socket for the peer. */ peer->fd = sockunion_socket (&peer->su); if (peer->fd < 0) return -1; set_nonblocking (peer->fd); /* Set socket send buffer size */ bgp_update_sock_send_buffer_size(peer->fd); bgp_set_socket_ttl (peer, peer->fd); sockopt_reuseaddr (peer->fd); sockopt_reuseport (peer->fd); #ifdef IPTOS_PREC_INTERNETCONTROL if (bgpd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs", __func__); if (sockunion_family (&peer->su) == AF_INET) setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL); else if (sockunion_family (&peer->su) == AF_INET6) setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL); if (bgpd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs", __func__); #endif if (peer->password) bgp_md5_set_connect (peer->fd, &peer->su, peer->password); /* Bind socket. */ bgp_bind (peer); /* Update source bind. */ bgp_update_source (peer); if (peer->ifname) ifindex = ifname2ifindex (peer->ifname); if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] Connect start to %s fd %d", peer->host, peer->host, peer->fd); /* 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) { sockunion_free (peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { sockunion_free (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); } static int bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) { struct bgp_listener *listener; int ret, en; sockopt_reuseaddr (sock); sockopt_reuseport (sock); if (bgpd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs", __func__); #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); else if (sa->sa_family == AF_INET6) setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); #endif sockopt_v6only (sa->sa_family, sock); ret = bind (sock, sa, salen); en = errno; if (bgpd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs", __func__); if (ret < 0) { zlog_err ("bind: %s", safe_strerror (en)); return ret; } ret = listen (sock, 3); if (ret < 0) { zlog_err ("listen: %s", safe_strerror (errno)); return ret; } listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener)); listener->fd = sock; memcpy(&listener->su, sa, salen); listener->thread = thread_add_read (bm->master, bgp_accept, listener, sock); listnode_add (bm->listen_sockets, listener); return 0; } /* IPv6 supported version of BGP server socket setup. */ int bgp_socket (unsigned short port, const char *address) { struct addrinfo *ainfo; struct addrinfo *ainfo_save; static const struct addrinfo req = { .ai_family = AF_UNSPEC, .ai_flags = AI_PASSIVE, .ai_socktype = SOCK_STREAM, }; int ret, count; char port_str[BUFSIZ]; snprintf (port_str, sizeof(port_str), "%d", port); port_str[sizeof (port_str) - 1] = '\0'; ret = getaddrinfo (address, port_str, &req, &ainfo_save); if (ret != 0) { zlog_err ("getaddrinfo: %s", gai_strerror (ret)); return -1; } count = 0; for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next) { int sock; 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", safe_strerror (errno)); continue; } /* if we intend to implement ttl-security, this socket needs ttl=255 */ sockopt_ttl (ainfo->ai_family, sock, MAXTTL); ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen); if (ret == 0) ++count; else close(sock); } freeaddrinfo (ainfo_save); if (count == 0) { zlog_err ("%s: no usable addresses", __func__); return -1; } return 0; } void bgp_close (void) { struct listnode *node, *next; struct bgp_listener *listener; for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener)) { thread_cancel (listener->thread); close (listener->fd); listnode_delete (bm->listen_sockets, listener); XFREE (MTYPE_BGP_LISTENER, listener); } } quagga-1.2.4/bgpd/bgp_network.h000066400000000000000000000022541325323223500163740ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_NETWORK_H #define _QUAGGA_BGP_NETWORK_H #define BGP_SOCKET_SNDBUF_SIZE 65536 extern int bgp_socket (unsigned short, const char *); extern void bgp_close (void); extern int bgp_connect (struct peer *); extern void bgp_getsockname (struct peer *); extern void bgp_set_socket_ttl (struct peer *peer, int bgp_sock); extern int bgp_md5_set (struct peer *); #endif /* _QUAGGA_BGP_NETWORK_H */ quagga-1.2.4/bgpd/bgp_nexthop.c000066400000000000000000000303621325323223500163640ustar00rootroot00000000000000/* 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 "hash.h" #include "jhash.h" #include "filter.h" #include "nexthop.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_nht.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_damp.h" #include "zebra/rib.h" #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ /* Route table for next-hop lookup cache. */ struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; static struct bgp_table *cache1_table[AFI_MAX]; /* Route table for connected route. */ static struct bgp_table *bgp_connected_table[AFI_MAX]; char * bnc_str (struct bgp_nexthop_cache *bnc, char *buf, int size) { prefix2str(&(bnc->node->p), buf, size); return buf; } 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 (void) { struct bgp_nexthop_cache *bnc; bnc = XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); LIST_INIT(&(bnc->paths)); return bnc; } void bnc_free (struct bgp_nexthop_cache *bnc) { bnc_nexthop_free (bnc); XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); } /* If nexthop exists on connected network return 1. */ int bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop); if (rn) { bgp_unlock_node (rn); return 1; } } else if (afi == AFI_IP6) { if (attr->extra->mp_nexthop_len == 32) return 1; else if (attr->extra->mp_nexthop_len == 16) { if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) return 1; rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6], &attr->extra->mp_nexthop_global); if (rn) { bgp_unlock_node (rn); return 1; } } } return 0; } /* BGP own address structure */ struct bgp_addr { struct in_addr addr; int refcnt; }; static struct hash *bgp_address_hash; static void * bgp_address_hash_alloc (void *p) { struct in_addr *val = p; struct bgp_addr *addr; addr = XMALLOC (MTYPE_BGP_ADDR, sizeof (struct bgp_addr)); addr->refcnt = 0; addr->addr.s_addr = val->s_addr; return addr; } static unsigned int bgp_address_hash_key_make (void *p) { const struct bgp_addr *addr = p; return jhash_1word(addr->addr.s_addr, 0); } static int bgp_address_hash_cmp (const void *p1, const void *p2) { const struct bgp_addr *addr1 = p1; const struct bgp_addr *addr2 = p2; return addr1->addr.s_addr == addr2->addr.s_addr; } void bgp_address_init (void) { bgp_address_hash = hash_create (bgp_address_hash_key_make, bgp_address_hash_cmp); } void bgp_address_destroy (void) { if (bgp_address_hash == NULL) return; hash_clean(bgp_address_hash, NULL); hash_free(bgp_address_hash); bgp_address_hash = NULL; } static void bgp_address_add (struct prefix *p) { struct bgp_addr tmp; struct bgp_addr *addr; tmp.addr = p->u.prefix4; addr = hash_get (bgp_address_hash, &tmp, bgp_address_hash_alloc); if (!addr) return; addr->refcnt++; } static void bgp_address_del (struct prefix *p) { struct bgp_addr tmp; struct bgp_addr *addr; tmp.addr = p->u.prefix4; addr = hash_lookup (bgp_address_hash, &tmp); /* may have been deleted earlier by bgp_interface_down() */ if (addr == NULL) return; addr->refcnt--; if (addr->refcnt == 0) { hash_release (bgp_address_hash, addr); XFREE (MTYPE_BGP_ADDR, addr); } } struct bgp_connected_ref { unsigned int refcnt; }; void bgp_connected_add (struct connected *ifc) { struct prefix p; struct prefix *addr; struct interface *ifp; struct bgp_node *rn; struct bgp_connected_ref *bc; ifp = ifc->ifp; if (! ifp) return; if (if_is_loopback (ifp)) return; addr = ifc->address; p = *(CONNECTED_PREFIX(ifc)); if (addr->family == AF_INET) { apply_mask_ipv4 ((struct prefix_ipv4 *) &p); if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) return; bgp_address_add (addr); rn = bgp_node_get (bgp_connected_table[AFI_IP], (struct prefix *) &p); if (rn->info) { bc = rn->info; bc->refcnt++; } else { bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref)); bc->refcnt = 1; rn->info = bc; } } else if (addr->family == AF_INET6) { 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_table[AFI_IP6], (struct prefix *) &p); if (rn->info) { bc = rn->info; bc->refcnt++; } else { bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref)); bc->refcnt = 1; rn->info = bc; } } } void bgp_connected_delete (struct connected *ifc) { struct prefix p; struct prefix *addr; struct interface *ifp; struct bgp_node *rn; struct bgp_connected_ref *bc; ifp = ifc->ifp; if (if_is_loopback (ifp)) return; addr = ifc->address; p = *(CONNECTED_PREFIX(ifc)); if (addr->family == AF_INET) { apply_mask_ipv4 ((struct prefix_ipv4 *) &p); if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) return; bgp_address_del (addr); rn = bgp_node_lookup (bgp_connected_table[AFI_IP], &p); if (! rn) return; bc = rn->info; bc->refcnt--; if (bc->refcnt == 0) { XFREE (MTYPE_BGP_CONN, bc); rn->info = NULL; } bgp_unlock_node (rn); bgp_unlock_node (rn); } else if (addr->family == AF_INET6) { 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_table[AFI_IP6], (struct prefix *) &p); if (! rn) return; bc = rn->info; bc->refcnt--; if (bc->refcnt == 0) { XFREE (MTYPE_BGP_CONN, bc); rn->info = NULL; } bgp_unlock_node (rn); bgp_unlock_node (rn); } } int bgp_nexthop_self (struct attr *attr) { struct bgp_addr tmp, *addr; tmp.addr = attr->nexthop; addr = hash_lookup (bgp_address_hash, &tmp); if (addr) return 1; return 0; } int bgp_multiaccess_check_v4 (struct in_addr nexthop, struct peer *peer) { struct bgp_node *rn1; struct bgp_node *rn2; struct prefix p; int ret; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = nexthop; rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p); if (!rn1) return 0; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = peer->su.sin.sin_addr; rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p); if (!rn2) { bgp_unlock_node(rn1); return 0; } ret = (rn1 == rn2) ? 1 : 0; bgp_unlock_node(rn1); bgp_unlock_node(rn2); return (ret); } static int show_ip_bgp_nexthop_table (struct vty *vty, int detail) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; char buf[INET6_ADDRSTRLEN]; struct nexthop *nexthop; time_t tbuf; afi_t afi; vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) { if (!bgp_nexthop_cache_table[afi]) continue; for (rn = bgp_table_top (bgp_nexthop_cache_table[afi]); rn; rn = bgp_route_next (rn)) { if ((bnc = rn->info) != NULL) { if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) { vty_out (vty, " %s valid [IGP metric %d], #paths %d%s", inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)), bnc->metric, bnc->path_count, VTY_NEWLINE); if (detail) for (nexthop = bnc->nexthop ; nexthop; nexthop = nexthop->next) switch (nexthop->type) { case NEXTHOP_TYPE_IPV6: vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; case NEXTHOP_TYPE_IPV6_IFINDEX: vty_out(vty, " gate %s, if %s%s", inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, INET6_ADDRSTRLEN), ifindex2ifname(nexthop->ifindex), VTY_NEWLINE); break; case NEXTHOP_TYPE_IPV4: vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &nexthop->gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " if %s%s", ifindex2ifname(nexthop->ifindex), VTY_NEWLINE); break; case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " gate %s, if %s%s", inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, INET6_ADDRSTRLEN), ifindex2ifname(nexthop->ifindex), VTY_NEWLINE); break; default: vty_out (vty, " invalid nexthop type %u%s", nexthop->type, VTY_NEWLINE); } } else vty_out (vty, " %s invalid%s", inet_ntop (AF_INET, &rn->p.u.prefix, buf, sizeof (buf)), VTY_NEWLINE); #ifdef HAVE_CLOCK_MONOTONIC tbuf = time(NULL) - (bgp_clock() - bnc->last_update); vty_out (vty, " Last update: %s", ctime(&tbuf)); #else vty_out (vty, " Last update: %s", ctime(&bnc->uptime)); #endif /* HAVE_CLOCK_MONOTONIC */ vty_out(vty, "%s", VTY_NEWLINE); } } } return CMD_SUCCESS; } DEFUN (show_ip_bgp_nexthop, show_ip_bgp_nexthop_cmd, "show ip bgp nexthop", SHOW_STR IP_STR BGP_STR "BGP nexthop table\n") { return show_ip_bgp_nexthop_table (vty, 0); } DEFUN (show_ip_bgp_nexthop_detail, show_ip_bgp_nexthop_detail_cmd, "show ip bgp nexthop detail", SHOW_STR IP_STR BGP_STR "BGP nexthop table\n") { return show_ip_bgp_nexthop_table (vty, 1); } void bgp_scan_init (void) { cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP]; bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6]; bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); cache1_table[AFI_ETHER] = bgp_table_init (AFI_ETHER, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_ETHER] = cache1_table[AFI_ETHER]; bgp_connected_table[AFI_ETHER] = bgp_table_init (AFI_ETHER, SAFI_UNICAST); } void bgp_scan_vty_init() { install_element (VIEW_NODE, &show_ip_bgp_nexthop_cmd); install_element (VIEW_NODE, &show_ip_bgp_nexthop_detail_cmd); } void bgp_scan_finish (void) { if (cache1_table[AFI_IP]) bgp_table_unlock (cache1_table[AFI_IP]); cache1_table[AFI_IP] = NULL; if (bgp_connected_table[AFI_IP]) bgp_table_unlock (bgp_connected_table[AFI_IP]); bgp_connected_table[AFI_IP] = NULL; if (cache1_table[AFI_IP6]) bgp_table_unlock (cache1_table[AFI_IP6]); cache1_table[AFI_IP6] = NULL; if (bgp_connected_table[AFI_IP6]) bgp_table_unlock (bgp_connected_table[AFI_IP6]); bgp_connected_table[AFI_IP6] = NULL; if (cache1_table[AFI_ETHER]) bgp_table_unlock (cache1_table[AFI_ETHER]); cache1_table[AFI_ETHER] = NULL; if (bgp_connected_table[AFI_ETHER]) bgp_table_unlock (bgp_connected_table[AFI_ETHER]); bgp_connected_table[AFI_ETHER] = NULL; } void bgp_scan_destroy (void) { bgp_scan_finish(); } quagga-1.2.4/bgpd/bgp_nexthop.h000066400000000000000000000053751325323223500163770ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_NEXTHOP_H #define _QUAGGA_BGP_NEXTHOP_H #include "if.h" #include "queue.h" #include "prefix.h" #define NEXTHOP_FAMILY(nexthop_len) ( \ ((nexthop_len) == 4 || \ (nexthop_len) == 12 ? AF_INET : \ ((nexthop_len) == 16 || \ (nexthop_len) == 24 || \ (nexthop_len) == 48 ? AF_INET6 : \ AF_UNSPEC)) \ ) /* BGP nexthop cache value structure. */ struct bgp_nexthop_cache { /* IGP route's metric. */ u_int32_t metric; /* Nexthop number and nexthop linked list.*/ u_char nexthop_num; struct nexthop *nexthop; time_t last_update; u_int16_t flags; #define BGP_NEXTHOP_VALID (1 << 0) #define BGP_NEXTHOP_REGISTERED (1 << 1) #define BGP_NEXTHOP_CONNECTED (1 << 2) #define BGP_NEXTHOP_PEER_NOTIFIED (1 << 3) u_int16_t change_flags; #define BGP_NEXTHOP_CHANGED (1 << 0) #define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) #define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) struct bgp_node *node; void *nht_info; /* In BGP, peer session */ LIST_HEAD(path_list, bgp_info) paths; unsigned int path_count; }; extern int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *, int *, int *); extern void bgp_connected_add (struct connected *c); extern void bgp_connected_delete (struct connected *c); extern int bgp_multiaccess_check_v4 (struct in_addr, struct peer *); extern int bgp_config_write_scan_time (struct vty *); extern int bgp_nexthop_onlink (afi_t, struct attr *); extern int bgp_nexthop_self (struct attr *); extern void bgp_address_init (void); extern void bgp_address_destroy (void); extern void bgp_scan_destroy (void); extern struct bgp_nexthop_cache *bnc_new(void); extern void bnc_free(struct bgp_nexthop_cache *bnc); extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc); extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size); extern void bgp_scan_init (void); extern void bgp_scan_vty_init (void); #endif /* _QUAGGA_BGP_NEXTHOP_H */ quagga-1.2.4/bgpd/bgp_nht.c000066400000000000000000000352211325323223500154670ustar00rootroot00000000000000/* BGP Nexthop tracking * Copyright (C) 2013 Cumulus Networks, 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 "command.h" #include "thread.h" #include "prefix.h" #include "zclient.h" #include "stream.h" #include "network.h" #include "log.h" #include "memory.h" #include "nexthop.h" #include "filter.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_nht.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_zebra.h" extern struct zclient *zclient; extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; static void register_nexthop(struct bgp_nexthop_cache *bnc); static void unregister_nexthop (struct bgp_nexthop_cache *bnc); static void evaluate_paths(struct bgp_nexthop_cache *bnc); static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p); static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, int keep); int bgp_nexthop_check (struct bgp_info *path, int connected) { struct bgp_nexthop_cache *bnc = path->nexthop; if (!bnc) return 0; if (BGP_DEBUG(nht, NHT)) { char buf[INET6_ADDRSTRLEN]; zlog_debug("%s: NHT checking %s", __FUNCTION__, bnc_str (bnc, buf, INET6_ADDRSTRLEN)); } if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))) return 0; return (bgp_zebra_num_connects() == 0 || CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } /* Helper to get the rn for the appropriate nexthop for path or peer. * returns the locked rn - caller must bump down the refcnt. * * may return NULL in error cases. */ static struct bgp_node * bgp_get_nexthop_rn (struct bgp_info *path, struct peer *peer) { struct prefix p; afi_t afi; assert (path || peer); if (!(path || peer)) return NULL; if (path) { afi = family2afi (path->net->p.family); if (make_prefix(afi, path, &p) < 0) return NULL; } else { afi = family2afi(peer->su.sa.sa_family); if (afi == AFI_IP) { p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = peer->su.sin.sin_addr; } else if (afi == AFI_IP6) { p.family = AF_INET6; p.prefixlen = IPV6_MAX_BITLEN; p.u.prefix6 = peer->su.sin6.sin6_addr; } else return NULL; } return bgp_node_get (bgp_nexthop_cache_table[afi], &p); } static struct bgp_nexthop_cache * bgp_find_nexthop (struct bgp_info *path, struct peer *peer) { struct bgp_nexthop_cache *bnc = NULL; struct bgp_node *rn = bgp_get_nexthop_rn (path, peer); if (!rn) return NULL; bnc = rn->info; bgp_unlock_node (rn); return bnc; } static void bgp_unlink_nexthop_check (struct bgp_nexthop_cache *bnc) { if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) { if (BGP_DEBUG(nht, NHT)) { char buf[INET6_ADDRSTRLEN]; zlog_debug("bgp_unlink_nexthop: freeing bnc %s", bnc_str (bnc, buf, INET6_ADDRSTRLEN)); } unregister_nexthop(bnc); bnc->node->info = NULL; bgp_unlock_node (bnc->node); bnc->node = NULL; bnc_free (bnc); } } void bgp_unlink_nexthop (struct bgp_info *path) { struct bgp_nexthop_cache *bnc = path->nexthop; if (!bnc) return; if (BGP_DEBUG(nht, NHT)) { char buf[INET6_ADDRSTRLEN]; zlog_debug("%s: NHT unlinking %s", __FUNCTION__, bnc_str (bnc, buf, INET6_ADDRSTRLEN)); } path_nh_map(path, NULL, 0); bgp_unlink_nexthop_check (bnc); } void bgp_unlink_nexthop_by_peer (struct peer *peer) { struct bgp_nexthop_cache *bnc = bgp_find_nexthop (NULL, peer); if (!bnc) return; if (BGP_DEBUG(nht, NHT)) zlog_debug("%s: NHT unlinking %s", __FUNCTION__, peer->host); bnc->nht_info = NULL; bgp_unlink_nexthop_check (bnc); } int bgp_ensure_nexthop (struct bgp_info *ri, struct peer *peer, int connected) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; rn = bgp_get_nexthop_rn (ri, peer); if (!rn) { zlog_debug("%s: NHT could not ensure, failed to get rn!", __FUNCTION__); return 0; } if (!rn->info) { bnc = bnc_new(); rn->info = bnc; bnc->node = rn; bgp_lock_node(rn); if (connected) SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); } bnc = rn->info; bgp_unlock_node (rn); if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) register_nexthop(bnc); if (ri) { path_nh_map(ri, bnc, 1); /* updates NHT ri list reference */ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) (bgp_info_extra_get(ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; } else if (peer) bnc->nht_info = (void *)peer; /* NHT peer reference */ if (BGP_DEBUG(nht, NHT)) { char buf[INET6_ADDRSTRLEN]; zlog_debug("%s: NHT ensured %s", __FUNCTION__, bnc_str (bnc, buf, INET6_ADDRSTRLEN)); } return (bgp_zebra_num_connects() == 0 || CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)); } void bgp_parse_nexthop_update (void) { struct stream *s; struct bgp_node *rn; struct bgp_nexthop_cache *bnc; struct nexthop *nexthop; struct nexthop *oldnh; struct nexthop *nhlist_head = NULL; struct nexthop *nhlist_tail = NULL; uint32_t metric; u_char nexthop_num; struct prefix p; int i; s = zclient->ibuf; memset(&p, 0, sizeof(struct prefix)); p.family = stream_getw(s); p.prefixlen = stream_getc(s); switch (p.family) { case AF_INET: p.u.prefix4.s_addr = stream_get_ipv4 (s); break; case AF_INET6: stream_get(&p.u.prefix6, s, 16); break; default: break; } rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p); if (!rn || !rn->info) { if (BGP_DEBUG(nht, NHT)) { char buf[INET6_ADDRSTRLEN]; prefix2str(&p, buf, INET6_ADDRSTRLEN); zlog_debug("parse nexthop update(%s): rn not found", buf); } if (rn) bgp_unlock_node (rn); return; } bnc = rn->info; bgp_unlock_node (rn); bnc->last_update = bgp_clock(); bnc->change_flags = 0; metric = stream_getl (s); nexthop_num = stream_getc (s); /* debug print the input */ if (BGP_DEBUG(nht, NHT)) { char buf[INET6_ADDRSTRLEN]; prefix2str(&p, buf, INET6_ADDRSTRLEN); zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf, metric, nexthop_num); } if (metric != bnc->metric) bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; if(nexthop_num != bnc->nexthop_num) bnc->change_flags |= BGP_NEXTHOP_CHANGED; if (nexthop_num) { bnc->flags |= BGP_NEXTHOP_VALID; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = nexthop_new(); 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; case ZEBRA_NEXTHOP_IPV4_IFINDEX: case ZEBRA_NEXTHOP_IPV4_IFNAME: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); nexthop->ifindex = stream_getl (s); break; #ifdef HAVE_IPV6 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; #endif default: /* do nothing */ break; } if (nhlist_tail) { nhlist_tail->next = nexthop; nhlist_tail = nexthop; } else { nhlist_tail = nexthop; nhlist_head = nexthop; } /* No need to evaluate the nexthop if we have already determined * that there has been a change. */ if (bnc->change_flags & BGP_NEXTHOP_CHANGED) continue; for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next) if (nexthop_same_no_recurse(oldnh, nexthop)) break; if (!oldnh) bnc->change_flags |= BGP_NEXTHOP_CHANGED; } bnc_nexthop_free(bnc); bnc->nexthop = nhlist_head; } else { bnc->flags &= ~BGP_NEXTHOP_VALID; UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); bnc_nexthop_free(bnc); bnc->nexthop = NULL; } evaluate_paths(bnc); } /** * make_prefix - make a prefix structure from the path (essentially * path's node. */ static int make_prefix (int afi, struct bgp_info *ri, struct prefix *p) { memset (p, 0, sizeof (struct prefix)); switch (afi) { case AFI_IP: p->family = AF_INET; p->prefixlen = IPV4_MAX_BITLEN; p->u.prefix4 = ri->attr->nexthop; break; #ifdef HAVE_IPV6 case AFI_IP6: if (ri->attr->extra->mp_nexthop_len == 16 && IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global)) return -1; p->family = AF_INET6; p->prefixlen = IPV6_MAX_BITLEN; p->u.prefix6 = ri->attr->extra->mp_nexthop_global; break; #endif default: break; } return 0; } /** * sendmsg_nexthop -- Format and send a nexthop register/Unregister * command to Zebra. * ARGUMENTS: * struct bgp_nexthop_cache *bnc -- the nexthop structure. * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER * RETURNS: * void. */ static void sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command) { struct stream *s; struct prefix *p; int ret; /* Check socket. */ if (!zclient || zclient->sock < 0) { zlog_debug("%s: Can't send NH register, Zebra client not established", __FUNCTION__); return; } p = &(bnc->node->p); s = zclient->obuf; stream_reset (s); zclient_create_header (s, command, VRF_DEFAULT); if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) stream_putc(s, 1); else stream_putc(s, 0); stream_putw(s, PREFIX_FAMILY(p)); stream_putc(s, p->prefixlen); switch (PREFIX_FAMILY(p)) { case AF_INET: stream_put_in_addr (s, &p->u.prefix4); break; case AF_INET6: stream_put(s, &(p->u.prefix6), 16); break; default: break; } stream_putw_at (s, 0, stream_get_endp (s)); ret = zclient_send_message(zclient); /* TBD: handle the failure */ if (ret < 0) zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); if (command == ZEBRA_NEXTHOP_REGISTER) SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); else if (command == ZEBRA_NEXTHOP_UNREGISTER) UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); return; } /** * register_nexthop - register a nexthop with Zebra for notification * when the route to the nexthop changes. * ARGUMENTS: * struct bgp_nexthop_cache *bnc -- the nexthop structure. * RETURNS: * void. */ static void register_nexthop (struct bgp_nexthop_cache *bnc) { /* Check if we have already registered */ if (bnc->flags & BGP_NEXTHOP_REGISTERED) return; sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER); } /** * unregister_nexthop -- Unregister the nexthop from Zebra. * ARGUMENTS: * struct bgp_nexthop_cache *bnc -- the nexthop structure. * RETURNS: * void. */ static void unregister_nexthop (struct bgp_nexthop_cache *bnc) { /* Check if we have already registered */ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) return; sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER); } /** * evaluate_paths - Evaluate the paths/nets associated with a nexthop. * ARGUMENTS: * struct bgp_nexthop_cache *bnc -- the nexthop structure. * RETURNS: * void. */ static void evaluate_paths (struct bgp_nexthop_cache *bnc) { struct bgp_node *rn; struct bgp_info *path; struct bgp *bgp = bgp_get_default(); int afi; struct peer *peer = (struct peer *)bnc->nht_info; LIST_FOREACH(path, &(bnc->paths), nh_thread) { if (!(path->type == ZEBRA_ROUTE_BGP && path->sub_type == BGP_ROUTE_NORMAL)) continue; rn = path->net; afi = family2afi(rn->p.family); /* Path becomes valid/invalid depending on whether the nexthop * reachable/unreachable. */ if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) != (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0)) { if (CHECK_FLAG (path->flags, BGP_INFO_VALID)) { bgp_aggregate_decrement (bgp, &rn->p, path, afi, SAFI_UNICAST); bgp_info_unset_flag (rn, path, BGP_INFO_VALID); } else { bgp_info_set_flag (rn, path, BGP_INFO_VALID); bgp_aggregate_increment (bgp, &rn->p, path, afi, SAFI_UNICAST); } } /* Copy the metric to the path. Will be used for bestpath computation */ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) (bgp_info_extra_get(path))->igpmetric = bnc->metric; else if (path->extra) path->extra->igpmetric = 0; if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) || CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED); bgp_process(bgp, rn, afi, SAFI_UNICAST); } if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) { if (BGP_DEBUG(nht, NHT)) zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host); SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); } RESET_FLAG(bnc->change_flags); } /** * path_nh_map - make or break path-to-nexthop association. * ARGUMENTS: * path - pointer to the path structure * bnc - pointer to the nexthop structure * make - if set, make the association. if unset, just break the existing * association. */ static void path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make) { if (path->nexthop) { LIST_REMOVE(path, nh_thread); path->nexthop->path_count--; path->nexthop = NULL; } if (make) { LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread); path->nexthop = bnc; path->nexthop->path_count++; } } quagga-1.2.4/bgpd/bgp_nht.h000066400000000000000000000042321325323223500154720ustar00rootroot00000000000000/* BGP Nexthop tracking * Copyright (C) 2013 Cumulus Networks, 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. */ #ifndef _BGP_NHT_H #define _BGP_NHT_H /** * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra. */ void bgp_parse_nexthop_update (void); /** * bgp_nexthop_check() - check if the bnc object is valid. * ARGUMENTS: * p - path for which the nexthop object is being looked up * connected - True if NH MUST be a connected route */ int bgp_nexthop_check (struct bgp_info *, int connected); /** * bgp_ensure_nexthop() - Ensure a bgp_nexthop_cache object exists for * the given prefix or peer. If an existing one is not found, * create a new object and register with ZEBRA for nexthop * notification. * ARGUMENTS: * afi: AFI_IP or AF_IP6 * struct bgp_info *: path for which the nexthop object is * being looked up * OR * struct peer The BGP peer associated with this NHT * connected - True if NH MUST be a connected route */ int bgp_ensure_nexthop (struct bgp_info *, struct peer *, int connected); /** * bgp_unlink_nexthop() - Unlink the nexthop object from the path structure. * ARGUMENTS: * struct bgp_info *: path structure. */ void bgp_unlink_nexthop (struct bgp_info *); /** * bgp_unlink_nexthop() - Unlink the nexthop object for the given peer. */ extern void bgp_unlink_nexthop(struct bgp_info *p); void bgp_unlink_nexthop_by_peer (struct peer *); #endif /* _BGP_NHT_H */ quagga-1.2.4/bgpd/bgp_open.c000066400000000000000000001044131325323223500156370ustar00rootroot00000000000000/* 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 "memory.h" #include "filter.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_aspath.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) { char *pnt; char *end; struct capability_mp_data mpc; struct capability_header *hdr; pnt = peer->notify.data; end = pnt + peer->notify.length; while (pnt < end) { if (pnt + sizeof (struct capability_mp_data) + 2 > end) return; hdr = (struct capability_header *)pnt; if (pnt + hdr->length + 2 > end) return; memcpy (&mpc, pnt + 2, sizeof(struct capability_mp_data)); if (hdr->code == CAPABILITY_CODE_MP) { vty_out (vty, " Capability error for: Multi protocol "); switch (ntohs (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 (mpc.afi)); break; } switch (mpc.safi) { case SAFI_UNICAST: vty_out (vty, "SAFI Unicast"); break; case SAFI_MULTICAST: vty_out (vty, "SAFI Multicast"); break; case SAFI_MPLS_LABELED_VPN: vty_out (vty, "SAFI MPLS-labeled VPN"); break; case SAFI_ENCAP: vty_out (vty, "SAFI ENCAP"); break; default: vty_out (vty, "SAFI Unknown %d ", mpc.safi); break; } vty_out (vty, "%s", VTY_NEWLINE); } else if (hdr->code >= 128) vty_out (vty, " Capability error: vendor specific capability code %d", hdr->code); else vty_out (vty, " Capability error: unknown capability code %d", hdr->code); pnt += hdr->length + 2; } } static void bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc) { afi_t afi = stream_getw (s); memcpy(&mpc->afi, &afi, sizeof(mpc->afi)); mpc->reserved = stream_getc (s); mpc->safi = stream_getc (s); } int bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) { switch (afi) { case AFI_IP: case AFI_IP6: switch (*safi) { /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ case SAFI_MPLS_LABELED_VPN: *safi = SAFI_MPLS_VPN; case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_MPLS_VPN: case SAFI_ENCAP: return 1; } case AFI_ETHER: default: break; } zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi); return 0; } /* Set negotiated capability value. */ static int bgp_capability_mp (struct peer *peer, struct capability_header *hdr) { struct capability_mp_data mpc; struct stream *s = BGP_INPUT (peer); bgp_capability_mp_data (s, &mpc); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u", peer->host, mpc.afi, mpc.safi); if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi)) return -1; /* Now safi remapped, and afi/safi are valid array indices */ peer->afc_recv[mpc.afi][mpc.safi] = 1; if (peer->afc[mpc.afi][mpc.safi]) peer->afc_nego[mpc.afi][mpc.safi] = 1; else return -1; return 0; } static 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_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported", peer->host, afi, safi, type, mode); } static const struct message orf_type_str[] = { { ORF_TYPE_PREFIX, "Prefixlist" }, { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" }, }; static const int orf_type_str_max = array_size(orf_type_str); static const struct message orf_mode_str[] = { { ORF_MODE_RECEIVE, "Receive" }, { ORF_MODE_SEND, "Send" }, { ORF_MODE_BOTH, "Both" }, }; static const int orf_mode_str_max = array_size(orf_mode_str); static int bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) { struct stream *s = BGP_INPUT (peer); struct capability_orf_entry entry; afi_t afi; safi_t safi; 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; /* ORF Entry header */ bgp_capability_mp_data (s, &entry.mpc); entry.num = stream_getc (s); afi = entry.mpc.afi; safi = entry.mpc.safi; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u", peer->host, entry.mpc.afi, entry.mpc.safi); /* Check AFI and SAFI. */ if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi)) { zlog_info ("%s Addr-family %d/%d not supported." " Ignoring the ORF capability", peer->host, entry.mpc.afi, entry.mpc.safi); return 0; } /* validate number field */ if (CAPABILITY_CODE_ORF_LEN + (entry.num * 2) > hdr->length) { zlog_info ("%s ORF Capability entry length error," " Cap length %u, num %u", peer->host, hdr->length, entry.num); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } for (i = 0 ; i < entry.num ; i++) { type = stream_getc(s); mode = stream_getc(s); /* ORF Mode error check */ switch (mode) { case ORF_MODE_BOTH: case ORF_MODE_SEND: case ORF_MODE_RECEIVE: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* ORF Type and afi/safi error checks */ /* capcode versus type */ switch (hdr->code) { case CAPABILITY_CODE_ORF: switch (type) { case ORF_TYPE_PREFIX: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } break; case CAPABILITY_CODE_ORF_OLD: switch (type) { case ORF_TYPE_PREFIX_OLD: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* AFI vs SAFI */ if (!((afi == AFI_IP && safi == SAFI_UNICAST) || (afi == AFI_IP && safi == SAFI_MULTICAST) || (afi == AFI_IP6 && safi == SAFI_UNICAST))) { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s ORF capability" " as %s for afi/safi: %d/%d", peer->host, LOOKUP (orf_type_str, type), LOOKUP (orf_mode_str, mode), entry.mpc.afi, safi); if (hdr->code == CAPABILITY_CODE_ORF) { sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; } else if (hdr->code == CAPABILITY_CODE_ORF_OLD) { sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; } 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; } static int bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) { struct stream *s = BGP_INPUT (peer); u_int16_t restart_flag_time; size_t end = stream_get_getp (s) + caphdr->length; SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); restart_flag_time = stream_getw(s); if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV); UNSET_FLAG (restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; if (BGP_DEBUG (normal, NORMAL)) { zlog_debug ("%s OPEN has Graceful Restart capability", peer->host); zlog_debug ("%s Peer has%srestarted. Restart Time : %d", peer->host, CHECK_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV) ? " " : " not ", peer->v_gr_restart); } while (stream_get_getp (s) + 4 <= end) { afi_t afi = stream_getw (s); safi_t safi = stream_getc (s); u_char flag = stream_getc (s); if (!bgp_afi_safi_valid_indices (afi, &safi)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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_debug ("%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_debug ("%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); if (CHECK_FLAG (flag, RESTART_F_BIT)) SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV); } } return 0; } static as_t bgp_capability_as4 (struct peer *peer, struct capability_header *hdr) { SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); if (hdr->length != CAPABILITY_CODE_AS4_LEN) { zlog_err ("%s AS4 capability has incorrect data length %d", peer->host, hdr->length); return 0; } as_t as4 = stream_getl (BGP_INPUT(peer)); if (BGP_DEBUG (as4, AS4)) zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", peer->host, as4); return as4; } static const struct message capcode_str[] = { { CAPABILITY_CODE_MP, "MultiProtocol Extensions" }, { CAPABILITY_CODE_REFRESH, "Route Refresh" }, { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" }, { CAPABILITY_CODE_RESTART, "Graceful Restart" }, { CAPABILITY_CODE_AS4, "4-octet AS number" }, { CAPABILITY_CODE_DYNAMIC, "Dynamic" }, { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" }, { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" }, }; static const int capcode_str_max = array_size(capcode_str); /* Minimum sizes for length field of each cap (so not inc. the header) */ static const size_t cap_minsizes[] = { [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN, }; /* value the capability must be a multiple of. * 0-data capabilities won't be checked against this. * Other capabilities whose data doesn't fall on convenient boundaries for this * table should be set to 1. */ static const size_t cap_modsizes[] = { [CAPABILITY_CODE_MP] = 4, [CAPABILITY_CODE_REFRESH] = 1, [CAPABILITY_CODE_ORF] = 1, [CAPABILITY_CODE_RESTART] = 1, [CAPABILITY_CODE_AS4] = 4, [CAPABILITY_CODE_DYNAMIC] = 1, [CAPABILITY_CODE_REFRESH_OLD] = 1, [CAPABILITY_CODE_ORF_OLD] = 1, }; /** * Parse given capability. * XXX: This is reading into a stream, but not using stream API * * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol * capabilities were encountered. */ static int bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, u_char **error) { int ret; struct stream *s = BGP_INPUT (peer); size_t end = stream_get_getp (s) + length; assert (STREAM_READABLE (s) >= length); while (stream_get_getp (s) < end) { size_t start; u_char *sp = stream_pnt (s); struct capability_header caphdr; /* We need at least capability code and capability length. */ if (stream_get_getp(s) + 2 > end) { zlog_info ("%s Capability length error (< header)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } caphdr.code = stream_getc (s); caphdr.length = stream_getc (s); start = stream_get_getp (s); /* Capability length check sanity check. */ if (start + caphdr.length > end) { zlog_info ("%s Capability length error (< length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s capability (%u), length %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.code, caphdr.length); /* Length sanity check, type-specific, for known capabilities */ switch (caphdr.code) { case CAPABILITY_CODE_MP: case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH_OLD: case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: case CAPABILITY_CODE_RESTART: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info ("%s %s Capability length error: got %u," " expected at least %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length, (unsigned) cap_minsizes[caphdr.code]); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } if (caphdr.length && caphdr.length % cap_modsizes[caphdr.code] != 0) { zlog_info ("%s %s Capability length error: got %u," " expected a multiple of %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length, (unsigned) cap_modsizes[caphdr.code]); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } /* we deliberately ignore unknown codes, see below */ default: break; } switch (caphdr.code) { case CAPABILITY_CODE_MP: { *mp_capability = 1; /* Ignore capability when override-capability is set. */ if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { /* Set negotiated value. */ ret = bgp_capability_mp (peer, &caphdr); /* Unsupported Capability. */ if (ret < 0) { /* Store return data. */ memcpy (*error, sp, caphdr.length + 2); *error += caphdr.length + 2; } } } break; case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH_OLD: { /* BGP refresh capability */ if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD) SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); else SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); } break; case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: if (bgp_capability_orf_entry (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_RESTART: if (bgp_capability_restart (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_DYNAMIC: SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); break; case CAPABILITY_CODE_AS4: /* Already handled as a special-case parsing of the capabilities * at the beginning of OPEN processing. So we care not a jot * for the value really, only error case. */ if (!bgp_capability_as4 (peer, &caphdr)) return -1; break; default: if (caphdr.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, caphdr.code); } else { zlog_warn ("%s unrecognized capability code: %d - ignored", peer->host, caphdr.code); memcpy (*error, sp, caphdr.length + 2); *error += caphdr.length + 2; } } if (stream_get_getp(s) != (start + caphdr.length)) { if (stream_get_getp(s) > (start + caphdr.length)) zlog_warn ("%s Cap-parser for %s read past cap-length, %u!", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length); stream_set_getp (s, start + caphdr.length); } } return 0; } static int bgp_auth_parse (struct peer *peer, size_t length) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_AUTH_FAILURE); return -1; } static 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; } /* peek into option, stores ASN to *as4 if the AS4 capability was found. * Returns 0 if no as4 found, as4cap value otherwise. */ as_t peek_for_as4_capability (struct peer *peer, u_char length) { struct stream *s = BGP_INPUT (peer); size_t orig_getp = stream_get_getp (s); size_t end = orig_getp + length; as_t as4 = 0; /* The full capability parser will better flag the error.. */ if (STREAM_READABLE(s) < length) return 0; if (BGP_DEBUG (as4, AS4)) zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u," " peeking for as4", peer->host, length); /* the error cases we DONT handle, we ONLY try to read as4 out of * correctly formatted options. */ while (stream_get_getp(s) < end) { u_char opt_type; u_char opt_length; /* Check the length. */ if (stream_get_getp (s) + 2 > end) goto end; /* Fetch option type and length. */ opt_type = stream_getc (s); opt_length = stream_getc (s); /* Option length check. */ if (stream_get_getp (s) + opt_length > end) goto end; if (opt_type == BGP_OPEN_OPT_CAP) { unsigned long capd_start = stream_get_getp (s); unsigned long capd_end = capd_start + opt_length; assert (capd_end <= end); while (stream_get_getp (s) < capd_end) { struct capability_header hdr; if (stream_get_getp (s) + 2 > capd_end) goto end; hdr.code = stream_getc (s); hdr.length = stream_getc (s); if ((stream_get_getp(s) + hdr.length) > capd_end) goto end; if (hdr.code == CAPABILITY_CODE_AS4) { if (BGP_DEBUG (as4, AS4)) zlog_info ("[AS4] found AS4 capability, about to parse"); as4 = bgp_capability_as4 (peer, &hdr); goto end; } stream_forward_getp (s, hdr.length); } } } end: stream_set_getp (s, orig_getp); return as4; } /** * Parse open option. * * @param[out] mp_capability @see bgp_capability_parse() for semantics. */ int bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) { int ret; u_char *error; u_char error_data[BGP_MAX_PACKET_SIZE]; struct stream *s = BGP_INPUT(peer); size_t end = stream_get_getp (s) + length; ret = 0; error = error_data; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u", peer->host, length); while (stream_get_getp(s) < end) { u_char opt_type; u_char opt_length; /* Must have at least an OPEN option header */ if (STREAM_READABLE(s) < 2) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } /* Fetch option type and length. */ opt_type = stream_getc (s); opt_length = stream_getc (s); /* Option length check. */ if (STREAM_READABLE (s) < opt_length) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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, opt_length); break; case BGP_OPEN_OPT_CAP: ret = bgp_capability_parse (peer, opt_length, mp_capability, &error); 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; } /* 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 are no common AFI/SAFIs and send Unsupported Capability error. */ if (*mp_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_IP][SAFI_ENCAP] && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]) { plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " "overlap with received MP capabilities", 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; } static 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 = SAFI_MPLS_LABELED_VPN; stream_putc (s, BGP_OPEN_OPT_CAP); capp = stream_get_endp (s); /* Set Capability Len Pointer */ stream_putc (s, 0); /* Capability Length */ stream_putc (s, code); /* Capability Code */ orfp = stream_get_endp (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_endp (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_endp (s) - orfp - 1; stream_putc_at (s, orfp, orf_len); /* Total Capability Len. */ cap_len = stream_get_endp (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, capp, rcapp; afi_t afi; safi_t safi; as_t local_as; u_int32_t restart_time; /* Remember current pointer for Opt Parm Len. */ cp = stream_get_endp (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, SAFI_MPLS_LABELED_VPN); } /* ENCAP */ if (peer->afc[AFI_IP][SAFI_ENCAP]) { peer->afc_adv[AFI_IP][SAFI_ENCAP] = 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_ENCAP); } /* 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); } /* IPv6 VPN. */ if (peer->afc[AFI_IP6][SAFI_MPLS_VPN]) { peer->afc_adv[AFI_IP6][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_IP6); stream_putc (s, 0); stream_putc (s, SAFI_MPLS_LABELED_VPN); } /* IPv6 ENCAP. */ if (peer->afc[AFI_IP6][SAFI_ENCAP]) { peer->afc_adv[AFI_IP6][SAFI_ENCAP] = 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_ENCAP); } /* 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); /* AS4 */ SET_FLAG (peer->cap, PEER_CAP_AS4_ADV); stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2); stream_putc (s, CAPABILITY_CODE_AS4); stream_putc (s, CAPABILITY_CODE_AS4_LEN); if ( peer->change_local_as ) local_as = peer->change_local_as; else local_as = peer->local_as; stream_putl (s, local_as ); /* 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); } /* Sending base graceful-restart capability irrespective of the config */ SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV); stream_putc (s, BGP_OPEN_OPT_CAP); capp = stream_get_endp (s); /* Set Capability Len Pointer */ stream_putc (s, 0); /* Capability Length */ stream_putc (s, CAPABILITY_CODE_RESTART); rcapp = stream_get_endp (s); /* Set Restart Capability Len Pointer */ stream_putc (s, 0); restart_time = peer->bgp->restart_time; if (peer->bgp->t_startup) { SET_FLAG (restart_time, RESTART_R_BIT); SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_ADV); } stream_putw (s, restart_time); /* Send address-family specific graceful-restart capability only when GR config is present */ if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) { for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (peer->afc[afi][safi]) { stream_putw (s, afi); stream_putc (s, safi); stream_putc (s, 0); //Forwarding is not retained as of now. } } /* Total Graceful restart capability Len. */ len = stream_get_endp (s) - rcapp - 1; stream_putc_at (s, rcapp, len); /* Total Capability Len. */ len = stream_get_endp (s) - capp - 1; stream_putc_at (s, capp, len); /* Total Opt Parm Len. */ len = stream_get_endp (s) - cp - 1; stream_putc_at (s, cp, len); } quagga-1.2.4/bgpd/bgp_open.h000066400000000000000000000063231325323223500156450ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_OPEN_H #define _QUAGGA_BGP_OPEN_H /* Standard header for capability TLV */ struct capability_header { u_char code; u_char length; }; /* Generic MP capability data */ struct capability_mp_data { afi_t afi; u_char reserved; safi_t safi; }; #pragma pack(1) struct capability_orf_entry { struct capability_mp_data mpc; u_char num; struct { u_char type; u_char mode; } orfs[]; } __attribute__ ((packed)); #pragma pack() struct capability_as4 { uint32_t as4; }; struct graceful_restart_af { afi_t afi; safi_t safi; u_char flag; }; struct capability_gr { u_int16_t restart_flag_time; struct graceful_restart_af gr[]; }; /* 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_AS4 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 */ #define CAPABILITY_CODE_AS4_LEN 4 #define CAPABILITY_CODE_ORF_LEN 5 /* 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 /* 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 extern int bgp_open_option_parse (struct peer *, u_char, int *); extern void bgp_open_capability (struct stream *, struct peer *); extern void bgp_capability_vty_out (struct vty *, struct peer *); extern as_t peek_for_as4_capability (struct peer *, u_char); extern int bgp_afi_safi_valid_indices (afi_t, safi_t *); #endif /* _QUAGGA_BGP_OPEN_H */ quagga-1.2.4/bgpd/bgp_packet.c000066400000000000000000002310501325323223500161430ustar00rootroot00000000000000/* 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 "sockopt.h" #include "linklist.h" #include "plist.h" #include "filter.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_encap.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_endp (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_endp (s); stream_putw_at (s, BGP_MARKER_SIZE, cp); return cp; } /* Add new packet to the peer. */ static 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. */ static void bgp_packet_delete (struct peer *peer) { stream_free (stream_fifo_pop (peer->obuf)); } /* Check file descriptor whether connect is established. */ static void bgp_connect_check (struct peer *peer) { int status; socklen_t 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_debug (peer->log, "%s [Event] Connect failed (%s)", peer->host, safe_strerror (errno)); BGP_EVENT_ADD (peer, TCP_connection_open_failed); } } /* Make BGP update packet. */ static struct stream * bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; struct stream *snlri; 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 attrlen_pos = 0; int space_remaining = 0; int space_needed = 0; size_t mpattrlen_pos = 0; size_t mpattr_pos = 0; s = peer->work; stream_reset (s); snlri = peer->scratch; stream_reset (snlri); adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); while (adv) { assert (adv->rn); rn = adv->rn; adj = adv->adj; if (adv->binfo) binfo = adv->binfo; space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) - BGP_MAX_PACKET_SIZE_OVERFLOW; space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p); /* When remaining space can't include NLRI and it's length. */ if (space_remaining < space_needed) break; /* If packet is empty, set attribute. */ if (stream_empty (s)) { struct prefix_rd *prd = NULL; u_char *tag = NULL; struct peer *from = NULL; if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; if (binfo) { from = binfo->peer; if (binfo->extra) tag = binfo->extra->tag; } /* 1: Write the BGP message header - 16 bytes marker, 2 bytes length, * one byte message type. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); /* 2: withdrawn routes length */ stream_putw (s, 0); /* 3: total attributes length - attrlen_pos stores the position */ attrlen_pos = stream_get_endp (s); stream_putw (s, 0); /* 4: if there is MP_REACH_NLRI attribute, that should be the first * attribute, according to draft-ietf-idr-error-handling. Save the * position. */ mpattr_pos = stream_get_endp(s); /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */ total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, ((afi == AFI_IP && safi == SAFI_UNICAST) ? &rn->p : NULL), afi, safi, from, prd, tag); space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) - BGP_MAX_PACKET_SIZE_OVERFLOW; space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p);; /* If the attributes alone do not leave any room for NLRI then * return */ if (space_remaining < space_needed) { zlog_err ("%s cannot send UPDATE, the attributes do not leave " "room for NLRI", peer->host); /* Flush the FIFO update queue */ while (adv) adv = bgp_advertise_clean (peer, adv->adj, afi, safi); return NULL; } } if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); else { /* Encode the prefix in MP_REACH_NLRI attribute */ struct prefix_rd *prd = NULL; u_char *tag = NULL; if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; if (binfo && binfo->extra) tag = binfo->extra->tag; if (stream_empty(snlri)) mpattrlen_pos = bgp_packet_mpattr_start(snlri, afi, safi, adv->baa->attr); bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, tag); } if (BGP_DEBUG (update, UPDATE_OUT)) { char buf[INET6_BUFSIZ]; zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d", peer->host, inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_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 (! stream_empty (s)) { if (!stream_empty(snlri)) { bgp_packet_mpattr_end(snlri, mpattrlen_pos); total_attr_len += stream_get_endp(snlri); } /* set the total attribute length correctly */ stream_putw_at (s, attrlen_pos, total_attr_len); if (!stream_empty(snlri)) packet = stream_dupcat(s, snlri, mpattr_pos); else packet = stream_dup (s); bgp_packet_set_size (packet); bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); stream_reset (s); stream_reset (snlri); return packet; } return NULL; } static struct stream * bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; if (DISABLE_BGP_ANNOUNCE) return NULL; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("send End-of-RIB for %s to %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); bgp_packet_add (peer, s); return s; } /* Make BGP withdraw packet. */ /* For ipv4 unicast: 16-octet marker | 2-octet length | 1-octet type | 2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0) */ /* For other afi/safis: 16-octet marker | 2-octet length | 1-octet type | 2-octet withdrawn route length (=0) | 2-octet attrlen | mp_unreach attr type | attr len | afi | safi | withdrawn prefixes */ static 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; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; size_t mp_start = 0; size_t attrlen_pos = 0; size_t mplen_pos = 0; u_char first_time = 1; int space_remaining = 0; int space_needed = 0; s = peer->work; stream_reset (s); while ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) { assert (adv->rn); adj = adv->adj; rn = adv->rn; space_remaining = STREAM_REMAIN (s) - BGP_MAX_PACKET_SIZE_OVERFLOW; space_needed = (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p)); if (space_remaining < space_needed) break; if (stream_empty (s)) { bgp_packet_set_marker (s, BGP_MSG_UPDATE); stream_putw (s, 0); /* unfeasible routes length */ } else first_time = 0; if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); else { struct prefix_rd *prd = NULL; if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; /* If first time, format the MP_UNREACH header */ if (first_time) { attrlen_pos = stream_get_endp (s); /* total attr length = 0 for now. reevaluate later */ stream_putw (s, 0); mp_start = stream_get_endp (s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); } bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL); } if (BGP_DEBUG (update, UPDATE_OUT)) { char buf[INET6_BUFSIZ]; zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", peer->host, inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), rn->p.prefixlen); } peer->scount[afi][safi]--; bgp_adj_out_remove (rn, adj, peer, afi, safi); bgp_unlock_node (rn); } if (! stream_empty (s)) { if (afi == AFI_IP && safi == SAFI_UNICAST) { unfeasible_len = stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN; stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len); stream_putw (s, 0); } else { /* Set the mp_unreach attr's length */ bgp_packet_mpunreach_end(s, mplen_pos); /* Set total path attribute length. */ total_attr_len = stream_get_endp(s) - mp_start; stream_putw_at (s, attrlen_pos, total_attr_len); } bgp_packet_set_size (s); packet = stream_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 prefix p; unsigned long pos; bgp_size_t total_attr_len; if (DISABLE_BGP_ANNOUNCE) return; if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); else str2prefix ("::/0", &p); /* Logging the attribute. */ if (BGP_DEBUG (update, UPDATE_OUT)) { char attrstr[BUFSIZ]; char buf[INET6_BUFSIZ]; attrstr[0] = '\0'; bgp_dump_attr (peer, attr, attrstr, BUFSIZ); zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d %s", peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_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_endp (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); /* Dump packet if debug option is set. */ #ifdef DEBUG /* bgp_packet_dump (packet); */ #endif /* DEBUG */ /* Add packet to the peer. */ bgp_packet_add (peer, s); 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 prefix p; unsigned long attrlen_pos = 0; unsigned long cp; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; size_t mp_start = 0; size_t mplen_pos = 0; if (DISABLE_BGP_ANNOUNCE) return; if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); else str2prefix ("::/0", &p); total_attr_len = 0; if (BGP_DEBUG (update, UPDATE_OUT)) { char buf[INET6_BUFSIZ]; zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_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_endp (s); stream_putw (s, 0); /* Withdrawn Routes. */ if (p.family == AF_INET && safi == SAFI_UNICAST) { stream_put_prefix (s, &p); unfeasible_len = stream_get_endp (s) - cp - 2; /* Set unfeasible len. */ stream_putw_at (s, cp, unfeasible_len); /* Set total path attribute length. */ stream_putw (s, 0); } else { attrlen_pos = stream_get_endp (s); stream_putw (s, 0); mp_start = stream_get_endp (s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); bgp_packet_mpunreach_prefix(s, &p, afi, safi, NULL, NULL); /* Set the mp_unreach attr's length */ bgp_packet_mpunreach_end(s, mplen_pos); /* Set total path attribute length. */ total_attr_len = stream_get_endp(s) - mp_start; stream_putw_at (s, attrlen_pos, total_attr_len); } bgp_packet_set_size (s); /* Add packet to the peer. */ bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* Get next packet to be written. */ static 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 = BGP_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 = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); if (adv) { if (adv->binfo && adv->binfo->uptime < peer->synctime) { 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->peer->cap, PEER_CAP_RESTART_BIT_RCV) && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_BIT_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 && ! 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. */ static 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 = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) if (adv->binfo->uptime < peer->synctime) 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; unsigned int count = 0; /* 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; } s = bgp_write_packet (peer); if (!s) return 0; /* nothing to send */ sockopt_cork (peer->fd, 1); /* Nonblocking write until TCP output buffer is full. */ do { int writenum; /* 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); if (num < 0) { /* write failed either retry needed or error */ if (ERRNO_IO_RETRY(errno)) break; BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } if (num != writenum) { /* Partial write */ stream_forward_getp (s, num); break; } /* 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++; /* Flush any existing events */ BGP_EVENT_ADD (peer, BGP_Stop_with_error); goto done; 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); } while (++count < BGP_WRITE_PACKET_MAX && (s = bgp_write_packet (peer)) != NULL); if (bgp_write_proceed (peer)) BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); done: sockopt_cork (peer->fd, 0); return 0; } /* This is only for sending NOTIFICATION message to neighbor. */ static int bgp_write_notify (struct peer *peer) { int ret, val; 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); /* Stop collecting data within the socket */ sockopt_cork (peer->fd, 0); /* socket is in nonblocking mode, if we can't deliver the NOTIFY, well, * we only care about getting a clean shutdown at this point. */ ret = write (peer->fd, STREAM_DATA (s), stream_get_endp (s)); /* only connection reset/close gets counted as TCP_fatal_error, failure * to write the entire NOTIFY doesn't get different FSM treatment */ if (ret <= 0) { BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } /* Disable Nagle, make NOTIFY packet go out right away */ val = 1; (void) setsockopt (peer->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val, sizeof (val)); /* 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++; BGP_EVENT_ADD (peer, BGP_Stop_with_error); 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_debug ("%s sending KEEPALIVE", peer->host); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_KEEPALIVE, length); /* 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 <= BGP_AS_MAX) ? (u_int16_t) local_as : BGP_AS_TRANS); 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_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s", peer->host, BGP_VERSION_4, local_as, send_holdtime, inet_ntoa (peer->local_id)); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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); bgp_notify.data = NULL; bgp_notify.length = 0; } } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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; zlog_info ("Notification sent to neighbor %s:%u: User reset", peer->host, sockunion_get_port (&peer->su)); } else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) { peer->last_reset = PEER_DOWN_USER_SHUTDOWN; zlog_info ("Notification sent to neighbor %s:%u shutdown", peer->host, sockunion_get_port (&peer->su)); } else { peer->last_reset = PEER_DOWN_NOTIFY_SEND; zlog_info ("Notification sent to neighbor %s:%u: type %u/%u", peer->host, sockunion_get_port (&peer->su), code, sub_code); } } else zlog_info ("Notification sent to neighbor %s:%u: configuration change", peer->host, sockunion_get_port (&peer->su)); /* Call immediately. */ 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); } /* 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; int length; struct bgp_filter *filter; int orf_refresh = 0; if (DISABLE_BGP_ANNOUNCE) return; filter = &peer->filter[afi][safi]; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = SAFI_MPLS_LABELED_VPN; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_NEW); else bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_OLD); /* 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_endp (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_debug ("%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_debug ("%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_endp (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_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d", peer->host, afi, safi); zlog_debug ("%s send message type %d, length (incl. header) %d", peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ? BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length); } /* Add packet to the peer. */ bgp_packet_add (peer, s); 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; int length; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = SAFI_MPLS_LABELED_VPN; 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_debug ("%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); /* Add packet to the peer. */ bgp_packet_add (peer, s); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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. */ static int bgp_collision_detect (struct peer *new, struct in_addr remote_id) { struct peer *peer; struct listnode *node, *nnode; 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: */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer == new) continue; if (!sockunion_same (&peer->su, &new->su)) continue; /* Unless allowed via configuration, a connection collision with an existing BGP connection that is in the Established state causes closing of the newly created connection. */ if (peer->status == Established) { /* GR may do things slightly differently to classic RFC . Punt to * open_receive, see below */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) continue; if (new->fd >= 0) { if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s:%u Existing Established peer, sending NOTIFY", new->host, sockunion_get_port (&new->su)); bgp_notify_send (new, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); } return -1; } /* Note: Quagga historically orders explicitly only on the processing * of the Opens, treating 'new' as the passive, inbound and connection * and 'peer' as the active outbound connection. */ /* The local_id is always set, so we can match the given remote-ID * from the OPEN against both OpenConfirm and OpenSent peers. */ if (peer->status == OpenConfirm || peer->status == OpenSent) { struct peer *out = peer; struct peer *in = new; int ret_close_out = 1, ret_close_in = -1; if (!CHECK_FLAG (new->sflags, PEER_STATUS_ACCEPT_PEER)) { out = new; ret_close_out = -1; in = peer; ret_close_in = 1; } /* 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 (out->fd >= 0) { if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s Collision resolution, remote ID higher," " closing outbound", peer->host); bgp_notify_send (out, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); } return ret_close_out; } 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 (in->fd >= 0) { if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s Collision resolution, local ID higher," " closing inbound", peer->host); bgp_notify_send (in, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); } return ret_close_in; } } } return 0; } static 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; as_t as4 = 0; struct peer *realpeer; struct in_addr remote_id; int mp_capability; u_int8_t notify_data_remote_as[2]; u_int8_t 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_debug ("%s rcv OPEN, version %d, remote-as (in open) %u," " holdtime %d, id %s, %sbound connection", peer->host, version, remote_as, holdtime, inet_ntoa (remote_id), CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER) ? "in" : "out"); /* BEGIN to read the capability here, but dont do it yet */ mp_capability = 0; optlen = stream_getc (peer->ibuf); if (optlen != 0) { /* We need the as4 capability value *right now* because * if it is there, we have not got the remote_as yet, and without * that we do not know which peer is connecting to us now. */ as4 = peek_for_as4_capability (peer, optlen); } /* Just in case we have a silly peer who sends AS4 capability set to 0 */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && !as4) { zlog_err ("%s bad OPEN, got AS4 capability, but AS4 set to 0", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } if (remote_as == BGP_AS_TRANS) { /* Take the AS4 from the capability. We must have received the * capability now! Otherwise we have a asn16 peer who uses * BGP_AS_TRANS, for some unknown reason. */ if (as4 == BGP_AS_TRANS) { zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } if (!as4 && BGP_DEBUG (as4, AS4)) zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4." " Odd, but proceeding.", peer->host); else if (as4 < BGP_AS_MAX && BGP_DEBUG (as4, AS4)) zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 (%u) fits " "in 2-bytes, very odd peer.", peer->host, as4); if (as4) remote_as = as4; } else { /* We may have a partner with AS4 who has an asno < BGP_AS_MAX */ /* If we have got the capability, peer->as4cap must match remote_as */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && as4 != remote_as) { /* raise error, log this, close session */ zlog_err ("%s bad OPEN, got AS4 capability, but remote_as %u" " mismatch with 16bit 'myasn' %u in open", peer->host, as4, remote_as); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } } /* 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_debug ("%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_debug ("%s bad OPEN, remote AS is %u, expected %u", 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; /* Bit hacky */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { /* Connection FSM state is intertwined with our peer configuration * (the RFC encourages this a bit). At _this_ point we have a * 'realpeer' which represents the configuration and any earlier FSM * (outbound, unless the remote side has opened two connections to * us), and a 'peer' which here represents an inbound connection that * has not yet been reconciled with a 'realpeer'. * * As 'peer' has just sent an OPEN that reconciliation must now * happen, as only the 'realpeer' can ever proceed to Established. * * bgp_collision_detect should have resolved any collisions with * realpeers that are in states OpenSent, OpenConfirm or Established, * and may have sent a notify on the 'realpeer' connection. * bgp_accept will have rejected any connections where the 'realpeer' * is in Idle or >Established (though, that status may have changed * since). * * Need to finish off any reconciliation here, and ensure that * 'realpeer' is left holding any needed state from the appropriate * connection (fd, buffers, etc.), and any state from the other * connection is cleaned up. */ /* Is realpeer in some globally-down state, that precludes any and all * connections (Idle, Clearing, Deleted, etc.)? */ if (realpeer->status == Idle || realpeer->status > Established) { if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s peer status is %s, closing the new connection", realpeer->host, LOOKUP (bgp_status_msg, realpeer->status)); return -1; } /* GR does things differently, and prefers any new connection attempts * over an Established one (why not just rely on KEEPALIVE and avoid * having to special case this?) */ 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) { /* If we're here, RFC collision-detect did not reconcile the * connections, and the 'realpeer' is still available. So * 'realpeer' must be 'Active' or 'Connect'. * * According to the RFC we should just let this connection (of the * accepted 'peer') continue on to Established if the other * onnection (the 'realpeer') is in a more larval state, and * reconcile them when OPEN is sent on the 'realpeer'. * * However, the accepted 'peer' must be reconciled with 'peer' at * this point, due to the implementation, if 'peer' is to be able * to proceed. So it should be allowed to go to Established, as * long as the 'realpeer' was in Active or Connect state - which * /should/ be the case if we're here. * * So we should only need to sanity check that that is the case * here, and allow the code to get on with transferring the 'peer' * connection state over. */ if (realpeer->status != Active && realpeer->status != Connect) { if (BGP_DEBUG (events, EVENTS)) zlog_warn ("%s real peer status should be Active or Connect," " but is %s", realpeer->host, LOOKUP (bgp_status_msg, realpeer->status)); bgp_notify_send (realpeer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); } } if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s:%u [Event] Transfer accept BGP peer to real (state %s)", peer->host, sockunion_get_port (&peer->su), LOOKUP (bgp_status_msg, realpeer->status)); 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 output buffer, there may be an OPEN queued to send */ stream_fifo_free (realpeer->obuf); realpeer->obuf = peer->obuf; peer->obuf = NULL; bool open_deferred = CHECK_FLAG (peer->sflags, PEER_STATUS_OPEN_DEFERRED); /* Transfer status. */ realpeer->status = peer->status; bgp_stop (peer); /* peer pointer change */ peer = realpeer; 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); if (stream_fifo_head (peer->obuf)) BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); /* hack: we may defer OPEN on accept peers, when there seems to be a * realpeer in progress, when an accept peer connection is opened. This * is to avoid interoperability issues, with test/conformance tools * particularly. See bgp_fsm.c::bgp_connect_success * * If OPEN was deferred there, then we must send it now. */ if (open_deferred) bgp_open_send (peer); } /* remote router-id check. */ if (remote_id.s_addr == 0 || IPV4_CLASS_DE (ntohl (remote_id.s_addr)) || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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) { u_int16_t maxver = htons(BGP_VERSION_4); /* XXX this reply may not be correct if version < 4 XXX */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad protocol version, remote requested %d, local request %d", peer->host, version, BGP_VERSION_4); /* Data must be in network byte order here */ bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_VERSION, (u_int8_t *) &maxver, 2); return -1; } /* Check neighbor as number. */ if (remote_as != peer->as) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad OPEN, remote AS is %u, expected %u", 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) { uint16_t netholdtime = htons (holdtime); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, (u_int8_t *) &netholdtime, 2); 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. */ if (optlen != 0) { if ((ret = bgp_open_option_parse (peer, optlen, &mp_capability)) < 0) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return ret; } } else { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd OPEN w/ OPTION parameter len: 0", peer->host); } /* * Assume that the peer supports the locally configured set of * AFI/SAFIs if the peer did not send us any Mulitiprotocol * capabilities, or if 'override-capability' is configured. */ if (! mp_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); peer->rtt = sockopt_tcp_rtt (peer->fd); BGP_EVENT_ADD (peer, Receive_OPEN_message); peer->packet_size = 0; if (peer->ibuf) stream_reset (peer->ibuf); return 0; } /* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers */ int bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) { switch (packet->safi) { case SAFI_UNICAST: case SAFI_MULTICAST: return bgp_nlri_parse_ip (peer, attr, packet); case SAFI_MPLS_VPN: case SAFI_MPLS_LABELED_VPN: return bgp_nlri_parse_vpn (peer, attr, packet); case SAFI_ENCAP: return bgp_nlri_parse_encap (peer, attr, packet); } return -1; } /* Parse BGP Update packet and make attribute object. */ static int bgp_update_receive (struct peer *peer, bgp_size_t size) { int ret, nlri_ret; u_char *end; struct stream *s; struct attr attr; struct attr_extra extra; bgp_size_t attribute_len; bgp_size_t update_len; bgp_size_t withdraw_len; int i; enum NLRI_TYPES { NLRI_UPDATE, NLRI_WITHDRAW, NLRI_MP_UPDATE, NLRI_MP_WITHDRAW, NLRI_TYPE_MAX, }; struct bgp_nlri nlris[NLRI_TYPE_MAX]; /* 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 (&extra, 0, sizeof (struct attr_extra)); memset (&nlris, 0, sizeof nlris); attr.extra = &extra; 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) { nlris[NLRI_WITHDRAW].afi = AFI_IP; nlris[NLRI_WITHDRAW].safi = SAFI_UNICAST; nlris[NLRI_WITHDRAW].nlri = stream_pnt (s); nlris[NLRI_WITHDRAW].length = withdraw_len; if (BGP_DEBUG (packet, PACKET_RECV)) zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); stream_forward_getp (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; } /* Certain attribute parsing errors should not be considered bad enough * to reset the session for, most particularly any partial/optional * attributes that have 'tunneled' over speakers that don't understand * them. Instead we withdraw only the prefix concerned. * * Complicates the flow a little though.. */ bgp_attr_parse_ret_t attr_parse_ret = BGP_ATTR_PARSE_PROCEED; /* This define morphs the update case into a withdraw when lower levels * have signalled an error condition where this is best. */ #define NLRI_ATTR_ARG (attr_parse_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL) /* Parse attribute when it exists. */ if (attribute_len) { attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len, &nlris[NLRI_MP_UPDATE], &nlris[NLRI_MP_WITHDRAW]); if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) { bgp_attr_unintern_sub (&attr); bgp_attr_flush (&attr); return -1; } } /* Logging the attribute. */ if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW || BGP_DEBUG (update, UPDATE_IN)) { char attrstr[BUFSIZ]; attrstr[0] = '\0'; ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) ? LOG_ERR : LOG_DEBUG; if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) zlog (peer->log, LOG_ERR, "%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", peer->host); if (ret) zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s", peer->host, attrstr); } /* Network Layer Reachability Information. */ update_len = end - stream_pnt (s); if (update_len) { /* Set NLRI portion to structure. */ nlris[NLRI_UPDATE].afi = AFI_IP; nlris[NLRI_UPDATE].safi = SAFI_UNICAST; nlris[NLRI_UPDATE].nlri = stream_pnt (s); nlris[NLRI_UPDATE].length = update_len; stream_forward_getp (s, update_len); } /* Parse any given NLRIs */ for (i = NLRI_UPDATE; i < NLRI_TYPE_MAX; i++) { if (!nlris[i].nlri) continue; /* We use afi and safi as indices into tables and what not. It would * be impossible, at this time, to support unknown afi/safis. And * anyway, the peer needs to be configured to enable the afi/safi * explicitly which requires UI support. * * Ignore unknown afi/safi NLRIs. * * Note: this means nlri[x].afi/safi still can not be trusted for * indexing later in this function! * * Note2: This will also remap the wire code-point for VPN safi to the * internal safi_t point, as needs be. */ if (!bgp_afi_safi_valid_indices (nlris[i].afi, &nlris[i].safi)) { plog_info (peer->log, "%s [Info] UPDATE with unsupported AFI/SAFI %u/%u", peer->host, nlris[i].afi, nlris[i].safi); continue; } /* NLRI is processed only when the peer is configured specific Address Family and Subsequent Address Family. */ if (!peer->afc[nlris[i].afi][nlris[i].safi]) { plog_info (peer->log, "%s [Info] UPDATE for non-enabled AFI/SAFI %u/%u", peer->host, nlris[i].afi, nlris[i].safi); continue; } /* EoR handled later */ if (nlris[i].length == 0) continue; switch (i) { case NLRI_UPDATE: case NLRI_MP_UPDATE: nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i]); break; case NLRI_WITHDRAW: case NLRI_MP_WITHDRAW: nlri_ret = bgp_nlri_parse (peer, NULL, &nlris[i]); } if (nlri_ret < 0) { plog_err (peer->log, "%s [Error] Error parsing NLRI", peer->host); if (peer->status == Established) bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, i <= NLRI_WITHDRAW ? BGP_NOTIFY_UPDATE_INVAL_NETWORK : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); bgp_attr_unintern_sub (&attr); return -1; } } /* EoR checks. * * Non-MP IPv4/Unicast EoR is a completely empty UPDATE * and MP EoR should have only an empty MP_UNREACH */ if (!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0) { afi_t afi = 0; safi_t safi; /* Non-MP IPv4/Unicast is a completely empty UPDATE - already * checked update and withdraw NLRI lengths are 0. */ if (!attribute_len) { afi = AFI_IP; safi = SAFI_UNICAST; } /* otherwise MP AFI/SAFI is an empty update, other than an empty * MP_UNREACH_NLRI attr (with an AFI/SAFI we recognise). */ else if (attr.flag == BGP_ATTR_MP_UNREACH_NLRI && nlris[NLRI_MP_WITHDRAW].length == 0 && bgp_afi_safi_valid_indices (nlris[NLRI_MP_WITHDRAW].afi, &nlris[NLRI_MP_WITHDRAW].safi)) { afi = nlris[NLRI_MP_WITHDRAW].afi; safi = nlris[NLRI_MP_WITHDRAW].safi; } if (afi && peer->afc[afi][safi]) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); if (BGP_DEBUG (normal, NORMAL)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for %s from %s", peer->host, afi_safi_print (afi, safi)); } } /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ bgp_attr_unintern_sub (&attr); bgp_attr_flush (&attr); /* 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 = bgp_clock (); /* Rearm holdtime timer */ BGP_TIMER_OFF (peer->t_holdtime); bgp_timer_set (peer); return 0; } /* Notify message treatment function. */ static 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); bgp_notify.data = NULL; bgp_notify.length = 0; } } /* 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); BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message); } /* Keepalive treatment function -- get keepalive send keepalive */ static void bgp_keepalive_receive (struct peer *peer, bgp_size_t size) { if (BGP_DEBUG (keepalive, KEEPALIVE)) zlog_debug ("%s KEEPALIVE rcvd", peer->host); BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message); } /* Route refresh message is received. */ static void bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) { afi_t afi; safi_t safi; 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 byte */ stream_getc (s); safi = stream_getc (s); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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 != SAFI_MPLS_LABELED_VPN)) { if (BGP_DEBUG (normal, NORMAL)) { zlog_debug ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", peer->host, afi, safi); } return; } /* Adjust safi code. */ if (safi == SAFI_MPLS_LABELED_VPN) 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) + 2) < end) { orf_type = stream_getc (s); orf_len = stream_getw (s); /* orf_len in bounds? */ if ((stream_pnt (s) + orf_len) > end) break; /* XXX: Notify instead?? */ if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) { uint8_t *p_pnt = stream_pnt (s); uint8_t *p_end = stream_pnt (s) + orf_len; struct orf_prefix orfp; u_char common = 0; u_int32_t seq; int psize; char name[BUFSIZ]; int ret; if (BGP_DEBUG (normal, NORMAL)) { zlog_debug ("%s rcvd Prefixlist ORF(%d) length %d", peer->host, orf_type, orf_len); } /* we're going to read at least 1 byte of common ORF header, * and 7 bytes of ORF Address-filter entry from the stream */ if (orf_len < 7) break; /* ORF prefix-list name */ sprintf (name, "%s.%d.%d", peer->host, afi, safi); while (p_pnt < p_end) { /* If the ORF entry is malformed, want to read as much of it * as possible without going beyond the bounds of the entry, * to maximise debug information. */ int ok; memset (&orfp, 0, sizeof (struct orf_prefix)); common = *p_pnt++; /* after ++: p_pnt <= p_end */ if (common & ORF_COMMON_PART_REMOVE_ALL) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host); prefix_bgp_orf_remove_all (afi, name); break; } ok = ((size_t)(p_end - p_pnt) >= sizeof(u_int32_t)) ; if (ok) { memcpy (&seq, p_pnt, sizeof (u_int32_t)); p_pnt += sizeof (u_int32_t); orfp.seq = ntohl (seq); } else p_pnt = p_end ; if ((ok = (p_pnt < p_end))) orfp.ge = *p_pnt++ ; /* value checked in prefix_bgp_orf_set() */ if ((ok = (p_pnt < p_end))) orfp.le = *p_pnt++ ; /* value checked in prefix_bgp_orf_set() */ if ((ok = (p_pnt < p_end))) orfp.p.prefixlen = *p_pnt++ ; orfp.p.family = afi2family (afi); /* afi checked already */ psize = PSIZE (orfp.p.prefixlen); /* 0 if not ok */ if (psize > prefix_blen(&orfp.p)) /* valid for family ? */ { ok = 0 ; psize = prefix_blen(&orfp.p) ; } if (psize > (p_end - p_pnt)) /* valid for packet ? */ { ok = 0 ; psize = p_end - p_pnt ; } if (psize > 0) memcpy (&orfp.p.u.prefix, p_pnt, psize); p_pnt += psize; if (BGP_DEBUG (normal, NORMAL)) { char buf[INET6_BUFSIZ]; zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d%s", 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, INET6_BUFSIZ), orfp.p.prefixlen, orfp.ge, orfp.le, ok ? "" : " MALFORMED"); } if (ok) ret = prefix_bgp_orf_set (name, afi, &orfp, (common & ORF_COMMON_PART_DENY ? 0 : 1 ), (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); if (!ok || (ok && ret != CMD_SUCCESS)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Received misformatted prefixlist ORF." " Remove All pfxlist", peer->host); prefix_bgp_orf_remove_all (afi, name); break; } } peer->orf_plist[afi][safi] = prefix_bgp_orf_lookup (afi, name); } stream_forward_getp (s, orf_len); } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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); } static int bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) { u_char *end; struct capability_mp_data mpc; struct capability_header *hdr; u_char action; afi_t afi; safi_t safi; end = pnt + length; /* XXX: Streamify this */ for (; pnt < end; pnt += hdr->length + 3) { /* 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; hdr = (struct capability_header *)(pnt + 1); /* 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_debug ("%s CAPABILITY has action: %d, code: %u, length %u", peer->host, action, hdr->code, hdr->length); /* Capability length check. */ if ((pnt + hdr->length + 3) > end) { zlog_info ("%s Capability length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* Fetch structure to the byte stream. */ memcpy (&mpc, pnt + 3, sizeof (struct capability_mp_data)); /* We know MP Capability Code. */ if (hdr->code == CAPABILITY_CODE_MP) { afi = ntohs (mpc.afi); safi = mpc.safi; /* Ignore capability when override-capability is set. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) continue; if (!bgp_afi_safi_valid_indices (afi, &safi)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid " "(%u/%u)", peer->host, afi, safi); continue; } /* Address family check. */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", peer->host, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", ntohs(mpc.afi) , mpc.safi); 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, BGP_CLEAR_ROUTE_NORMAL); else BGP_EVENT_ADD (peer, BGP_Stop); } } else { zlog_warn ("%s unrecognized capability code: %d - ignored", peer->host, hdr->code); } } return 0; } /* Dynamic Capability is received. * * This is exported for unit-test purposes */ int bgp_capability_receive (struct peer *peer, bgp_size_t size) { u_char *pnt; /* Fetch pointer. */ pnt = stream_pnt (peer->ibuf); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%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 -1; } /* 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 -1; } /* Parse packet. */ return bgp_capability_msg_parse (peer, pnt, size); } /* BGP read utility function. */ static int bgp_read_packet (struct peer *peer) { int nbytes; int readsize; readsize = peer->packet_size - stream_get_endp (peer->ibuf); /* If size is zero then return. */ if (! readsize) return 0; /* Read packet from fd. */ nbytes = stream_read_try (peer->ibuf, peer->fd, readsize); /* If read byte is smaller than zero then error occurred. */ if (nbytes < 0) { /* Transient error should retry */ if (nbytes == -2) return -1; plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", peer->host, safe_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_debug (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 (stream_get_endp (peer->ibuf) != peer->packet_size) return -1; return 0; } /* Marker check. */ static 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; } /* Recent thread time. On same clock base as bgp_clock (MONOTONIC) but can be time of last context switch to bgp_read thread. */ static time_t bgp_recent_clock (void) { return recent_relative_time().tv_sec; } /* 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 (stream_get_endp (peer->ibuf) < 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_getp (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) && type != 2 && type != 0) zlog_debug ("%s rcv message type %d, length (excl. header) %d", peer->host, type, size - BGP_HEADER_SIZE); /* Marker check */ if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE)) && ! 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_debug (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_debug (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, (u_char *) 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); /* XXX return value ignored! */ break; case BGP_MSG_UPDATE: peer->readtime = bgp_recent_clock (); bgp_update_receive (peer, size); break; case BGP_MSG_NOTIFY: bgp_notify_receive (peer, size); break; case BGP_MSG_KEEPALIVE: peer->readtime = bgp_recent_clock (); 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_debug ("%s [Event] Accepting BGP peer delete", peer->host); peer_delete (peer); } return 0; } quagga-1.2.4/bgpd/bgp_packet.h000066400000000000000000000042601325323223500161510ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_PACKET_H #define _QUAGGA_BGP_PACKET_H #define BGP_NLRI_LENGTH 1U #define BGP_TOTAL_ATTR_LEN 2U #define BGP_UNFEASIBLE_LEN 2U #define BGP_WRITE_PACKET_MAX 10U /* 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. */ extern int bgp_read (struct thread *); extern int bgp_write (struct thread *); extern void bgp_keepalive_send (struct peer *); extern void bgp_open_send (struct peer *); extern void bgp_notify_send (struct peer *, u_int8_t, u_int8_t); extern void bgp_notify_send_with_data (struct peer *, u_int8_t, u_int8_t, u_int8_t *, size_t); extern void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int); extern void bgp_capability_send (struct peer *, afi_t, safi_t, int, int); extern void bgp_default_update_send (struct peer *, struct attr *, afi_t, safi_t, struct peer *); extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t); extern int bgp_capability_receive (struct peer *, bgp_size_t); extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); #endif /* _QUAGGA_BGP_PACKET_H */ quagga-1.2.4/bgpd/bgp_regex.c000066400000000000000000000042261325323223500160110ustar00rootroot00000000000000/* 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 "filter.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 (const 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|REG_NOSUB); 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); } quagga-1.2.4/bgpd/bgp_regex.h000066400000000000000000000023371325323223500160170ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_REGEX_H #define _QUAGGA_BGP_REGEX_H #include #ifdef HAVE_LIBPCREPOSIX # include #else # ifdef HAVE_GNU_REGEX # include # else # include "regex-gnu.h" # endif /* HAVE_GNU_REGEX */ #endif /* HAVE_LIBPCREPOSIX */ extern void bgp_regex_free (regex_t *regex); extern regex_t *bgp_regcomp (const char *str); extern int bgp_regexec (regex_t *regex, struct aspath *aspath); #endif /* _QUAGGA_BGP_REGEX_H */ quagga-1.2.4/bgpd/bgp_route.c000066400000000000000000021446721325323223500160510ustar00rootroot00000000000000/* BGP routing information Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro Copyright (C) 2016 Job Snijders This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU 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 "workqueue.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_lcommunity.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" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; static struct bgp_node * bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd) { struct bgp_node *rn; struct bgp_node *prn = NULL; assert (table); if (!table) return NULL; if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) { prn = bgp_node_get (table, (struct prefix *) prd); if (prn->info == NULL) prn->info = bgp_table_init (afi, safi); else bgp_unlock_node (prn); table = prn->info; } rn = bgp_node_get (table, p); if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) rn->prn = prn; return rn; } /* Allocate bgp_info_extra */ static struct bgp_info_extra * bgp_info_extra_new (void) { struct bgp_info_extra *new; new = XCALLOC (MTYPE_BGP_ROUTE_EXTRA, sizeof (struct bgp_info_extra)); return new; } static void bgp_info_extra_free (struct bgp_info_extra **extra) { if (extra && *extra) { if ((*extra)->damp_info) bgp_damp_info_free ((*extra)->damp_info, 0); (*extra)->damp_info = NULL; XFREE (MTYPE_BGP_ROUTE_EXTRA, *extra); *extra = NULL; } } /* Get bgp_info extra information for the given bgp_info, lazy allocated * if required. */ struct bgp_info_extra * bgp_info_extra_get (struct bgp_info *ri) { if (!ri->extra) ri->extra = bgp_info_extra_new(); return ri->extra; } /* Free bgp route information. */ static void bgp_info_free (struct bgp_info *binfo) { if (binfo->attr) bgp_attr_unintern (&binfo->attr); bgp_unlink_nexthop (binfo); bgp_info_extra_free (&binfo->extra); bgp_info_mpath_free (&binfo->mpath); peer_unlock (binfo->peer); /* bgp_info peer reference */ XFREE (MTYPE_BGP_ROUTE, binfo); } struct bgp_info * bgp_info_lock (struct bgp_info *binfo) { binfo->lock++; return binfo; } struct bgp_info * bgp_info_unlock (struct bgp_info *binfo) { assert (binfo && binfo->lock > 0); binfo->lock--; if (binfo->lock == 0) { #if 0 zlog_debug ("%s: unlocked and freeing", __func__); zlog_backtrace (LOG_DEBUG); #endif bgp_info_free (binfo); return NULL; } #if 0 if (binfo->lock == 1) { zlog_debug ("%s: unlocked to 1", __func__); zlog_backtrace (LOG_DEBUG); } #endif return 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; bgp_info_lock (ri); bgp_lock_node (rn); peer_lock (ri->peer); /* bgp_info peer reference */ } /* Do the actual removal of info from RIB, for use by bgp_process completion callback *only* */ static void bgp_info_reap (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; bgp_info_mpath_dequeue (ri); bgp_info_unlock (ri); bgp_unlock_node (rn); } void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri) { bgp_info_set_flag (rn, ri, BGP_INFO_REMOVED); /* set of previous already took care of pcount */ UNSET_FLAG (ri->flags, BGP_INFO_VALID); } /* undo the effects of a previous call to bgp_info_delete; typically called when a route is deleted and then quickly re-added before the deletion has been processed */ static void bgp_info_restore (struct bgp_node *rn, struct bgp_info *ri) { bgp_info_unset_flag (rn, ri, BGP_INFO_REMOVED); /* unset of previous already took care of pcount */ SET_FLAG (ri->flags, BGP_INFO_VALID); } /* Adjust pcount as required */ static void bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) { struct bgp_table *table; assert (rn && bgp_node_table (rn)); assert (ri && ri->peer && ri->peer->bgp); table = bgp_node_table (rn); /* Ignore 'pcount' for RS-client tables */ if (table->type != BGP_TABLE_MAIN || ri->peer == ri->peer->bgp->peer_self) return; if (!BGP_INFO_COUNTABLE (ri) && CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { UNSET_FLAG (ri->flags, BGP_INFO_COUNTED); /* slight hack, but more robust against errors. */ if (ri->peer->pcount[table->afi][table->safi]) ri->peer->pcount[table->afi][table->safi]--; else { zlog_warn ("%s: Asked to decrement 0 prefix count for peer %s", __func__, ri->peer->host); zlog_backtrace (LOG_WARNING); zlog_warn ("%s: Please report to Quagga bugzilla", __func__); } } else if (BGP_INFO_COUNTABLE (ri) && !CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { SET_FLAG (ri->flags, BGP_INFO_COUNTED); ri->peer->pcount[table->afi][table->safi]++; } } /* Set/unset bgp_info flags, adjusting any other state as needed. * This is here primarily to keep prefix-count in check. */ void bgp_info_set_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag) { SET_FLAG (ri->flags, flag); /* early bath if we know it's not a flag that changes countability state */ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_HISTORY|BGP_INFO_REMOVED)) return; bgp_pcount_adjust (rn, ri); } void bgp_info_unset_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag) { UNSET_FLAG (ri->flags, flag); /* early bath if we know it's not a flag that changes countability state */ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_HISTORY|BGP_INFO_REMOVED)) return; bgp_pcount_adjust (rn, ri); } /* Get MED value. If MED value is missing and "bgp bestpath missing-as-worst" is specified, treat it as the worst value. */ static 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 BGP_MED_MAX; else return 0; } } /* Compare two bgp route entity. Return -1 if new is preferred, 1 if exist * is preferred, or 0 if they are the same (usually will only occur if * multipath is enabled */ static int bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, afi_t afi, safi_t safi) { struct attr *newattr, *existattr; struct attr_extra *newattre, *existattre; bgp_peer_sort_t new_sort; bgp_peer_sort_t exist_sort; u_int32_t new_pref; u_int32_t exist_pref; u_int32_t new_med; u_int32_t exist_med; u_int32_t new_weight; u_int32_t exist_weight; uint32_t newm, existm; struct in_addr new_id; struct in_addr exist_id; int new_cluster; int exist_cluster; int internal_as_route; int confed_as_route; int ret; /* 0. Null check. */ if (new == NULL) return 1; if (exist == NULL) return -1; newattr = new->attr; existattr = exist->attr; newattre = newattr->extra; existattre = existattr->extra; /* 1. Weight check. */ new_weight = exist_weight = 0; if (newattre) new_weight = newattre->weight; if (existattre) exist_weight = existattre->weight; if (new_weight > exist_weight) return -1; if (new_weight < exist_weight) return 1; /* 2. Local preference check. */ new_pref = exist_pref = bgp->default_local_pref; if (newattr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) new_pref = newattr->local_pref; if (existattr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) exist_pref = existattr->local_pref; if (new_pref > exist_pref) return -1; if (new_pref < exist_pref) return 1; /* 3. Local route check. We prefer: * - BGP_ROUTE_STATIC * - BGP_ROUTE_AGGREGATE * - BGP_ROUTE_REDISTRIBUTE */ if (! (new->sub_type == BGP_ROUTE_NORMAL)) return -1; if (! (exist->sub_type == BGP_ROUTE_NORMAL)) return 1; /* 4. AS path length check. */ if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) { int exist_hops = aspath_count_hops (existattr->aspath); int exist_confeds = aspath_count_confeds (existattr->aspath); if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_CONFED)) { int aspath_hops; aspath_hops = aspath_count_hops (newattr->aspath); aspath_hops += aspath_count_confeds (newattr->aspath); if ( aspath_hops < (exist_hops + exist_confeds)) return -1; if ( aspath_hops > (exist_hops + exist_confeds)) return 1; } else { int newhops = aspath_count_hops (newattr->aspath); if (newhops < exist_hops) return -1; if (newhops > exist_hops) return 1; } } /* 5. Origin check. */ if (newattr->origin < existattr->origin) return -1; if (newattr->origin > existattr->origin) return 1; /* 6. MED check. */ internal_as_route = (aspath_count_hops (newattr->aspath) == 0 && aspath_count_hops (existattr->aspath) == 0); confed_as_route = (aspath_count_confeds (newattr->aspath) > 0 && aspath_count_confeds (existattr->aspath) > 0 && aspath_count_hops (newattr->aspath) == 0 && aspath_count_hops (existattr->aspath) == 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 (newattr->aspath, existattr->aspath) || aspath_cmp_left_confed (newattr->aspath, existattr->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 1; } /* 7. Peer type check. */ new_sort = new->peer->sort; exist_sort = exist->peer->sort; if (new_sort == BGP_PEER_EBGP && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED)) return -1; if (exist_sort == BGP_PEER_EBGP && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED)) return 1; /* 8. IGP metric check. */ newm = existm = 0; if (new->extra) newm = new->extra->igpmetric; if (exist->extra) existm = exist->extra->igpmetric; if (newm < existm) return -1; if (newm > existm) return 1; /* 9. Maximum path check. */ if (bgp_mpath_is_configured (bgp, afi, safi)) { if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { /* * For the two paths, all comparison steps till IGP metric * have succeeded - including AS_PATH hop count. Since 'bgp * bestpath as-path multipath-relax' knob is on, we don't need * an exact match of AS_PATH. Thus, mark the paths are equal. * That will trigger both these paths to get into the multipath * array. */ return 0; } else if (new->peer->sort == BGP_PEER_IBGP) { if (aspath_cmp (new->attr->aspath, exist->attr->aspath)) return 0; } else if (new->peer->as == exist->peer->as) return 0; } /* 10. 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) && new_sort == BGP_PEER_EBGP && exist_sort == BGP_PEER_EBGP) { if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED)) return -1; if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED)) return 1; } /* 11. Router-ID comparision. */ /* If one of the paths is "stale", the corresponding peer router-id will * be 0 and would always win over the other path. If originator id is * used for the comparision, it will decide which path is better. */ if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) new_id.s_addr = newattre->originator_id.s_addr; else new_id.s_addr = new->peer->remote_id.s_addr; if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) exist_id.s_addr = existattre->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 1; /* 12. Cluster length comparision. */ new_cluster = exist_cluster = 0; if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) new_cluster = newattre->cluster->length; if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) exist_cluster = existattre->cluster->length; if (new_cluster < exist_cluster) return -1; if (new_cluster > exist_cluster) return 1; /* 13. Neighbor address comparision. */ /* Do this only if neither path is "stale" as stale paths do not have * valid peer information (as the connection may or may not be up). */ if (CHECK_FLAG (exist->flags, BGP_INFO_STALE)) return -1; if (CHECK_FLAG (new->flags, BGP_INFO_STALE)) return 1; /* locally configured routes to advertise do not have su_remote */ if (new->peer->su_remote == NULL) return 1; if (exist->peer->su_remote == NULL) return -1; ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote); if (ret == 1) return 1; if (ret == -1) return -1; return -1; } static 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]; #define FILTER_EXIST_WARN(F,f,filter) \ if (BGP_DEBUG (update, UPDATE_IN) \ && !(F ## _IN (filter))) \ plog_warn (peer->log, "%s: Could not find configured input %s-list %s!", \ peer->host, #f, F ## _IN_NAME(filter)); if (DISTRIBUTE_IN_NAME (filter)) { FILTER_EXIST_WARN(DISTRIBUTE, distribute, filter); if (access_list_apply (DISTRIBUTE_IN (filter), p) == FILTER_DENY) return FILTER_DENY; } if (PREFIX_LIST_IN_NAME (filter)) { FILTER_EXIST_WARN(PREFIX_LIST, prefix, filter); if (prefix_list_apply (PREFIX_LIST_IN (filter), p) == PREFIX_DENY) return FILTER_DENY; } if (FILTER_LIST_IN_NAME (filter)) { FILTER_EXIST_WARN(FILTER_LIST, as, filter); if (as_list_apply (FILTER_LIST_IN (filter), attr->aspath)== AS_FILTER_DENY) return FILTER_DENY; } return FILTER_PERMIT; #undef FILTER_EXIST_WARN } static 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]; #define FILTER_EXIST_WARN(F,f,filter) \ if (BGP_DEBUG (update, UPDATE_OUT) \ && !(F ## _OUT (filter))) \ plog_warn (peer->log, "%s: Could not find configured output %s-list %s!", \ peer->host, #f, F ## _OUT_NAME(filter)); if (DISTRIBUTE_OUT_NAME (filter)) { FILTER_EXIST_WARN(DISTRIBUTE, distribute, filter); if (access_list_apply (DISTRIBUTE_OUT (filter), p) == FILTER_DENY) return FILTER_DENY; } if (PREFIX_LIST_OUT_NAME (filter)) { FILTER_EXIST_WARN(PREFIX_LIST, prefix, filter); if (prefix_list_apply (PREFIX_LIST_OUT (filter), p) == PREFIX_DENY) return FILTER_DENY; } if (FILTER_LIST_OUT_NAME (filter)) { FILTER_EXIST_WARN(FILTER_LIST, as, filter); if (as_list_apply (FILTER_LIST_OUT (filter), attr->aspath) == AS_FILTER_DENY) return FILTER_DENY; } return FILTER_PERMIT; #undef FILTER_EXIST_WARN } /* If community attribute includes no_export then return 1. */ static 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 == BGP_PEER_EBGP && community_include (attr->community, COMMUNITY_NO_EXPORT)) return 1; /* NO_EXPORT_SUBCONFED check. */ if (peer->sort == BGP_PEER_EBGP || peer->sort == 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->extra && attr->extra->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->extra->cluster, cluster_id)) return 1; } return 0; } static 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 (peer->weight) (bgp_attr_extra_get (attr))->weight = peer->weight; /* 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) /* caller has multiple error paths with bgp_attr_flush() */ return RMAP_DENY; } return RMAP_PERMIT; } static int bgp_export_modifier (struct peer *rsclient, 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]; /* Route map apply. */ if (ROUTE_MAP_EXPORT_NAME (filter)) { /* Duplicate current value to new strucutre for modification. */ info.peer = rsclient; info.attr = attr; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); /* Apply BGP route map to the attribute. */ ret = route_map_apply (ROUTE_MAP_EXPORT (filter), p, RMAP_BGP, &info); rsclient->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; } static int bgp_import_modifier (struct peer *rsclient, 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 = &rsclient->filter[afi][safi]; /* Apply default weight value. */ if (peer->weight) (bgp_attr_extra_get (attr))->weight = peer->weight; /* Route map apply. */ if (ROUTE_MAP_IMPORT_NAME (filter)) { /* Duplicate current value to new strucutre for modification. */ info.peer = peer; info.attr = attr; SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT); /* Apply BGP route map to the attribute. */ ret = route_map_apply (ROUTE_MAP_IMPORT (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; } static 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 peer *from; struct bgp *bgp; int transparent; int reflect; struct attr *riattr; from = ri->peer; filter = &peer->filter[afi][safi]; bgp = peer->bgp; riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; if (DISABLE_BGP_ANNOUNCE) return 0; /* Do not send announces to RS-clients from the 'normal' bgp_table. */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) return 0; /* Do not send back route to sender. */ if (from == peer) return 0; /* Aggregate-address suppress check. */ if (ri->extra && ri->extra->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; else if (p->family == AF_INET6 && p->prefixlen == 0) return 0; } /* 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, riattr)) return 0; /* If the attribute has originator-id and it is same as remote peer's id. */ if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) { if (IPV4_ADDR_SAME (&peer->remote_id, &riattr->extra->originator_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, "%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, riattr, afi, safi) == FILTER_DENY) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, "%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 (riattr->aspath, peer->as)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, "%s [Update:SEND] suppress announcement to peer AS %u is AS path.", peer->host, peer->as); return 0; } /* 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(riattr->aspath, bgp->confed_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, "%s [Update:SEND] suppress announcement to peer AS %u is AS path.", peer->host, bgp->confed_id); return 0; } } #endif /* BGP_SEND_ASPATH_CHECK */ /* Route-Reflect check. */ if (from->sort == BGP_PEER_IBGP && peer->sort == 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. */ bgp_attr_dup (attr, riattr); /* If local-preference is not set. */ if ((peer->sort == BGP_PEER_IBGP || peer->sort == 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; } /* If originator-id is not set and the route is to be reflected, set the originator id */ if (peer && from && peer->sort == BGP_PEER_IBGP && from->sort == BGP_PEER_IBGP && (! (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) { attr->extra = bgp_attr_extra_get(attr); IPV4_ADDR_COPY(&(attr->extra->originator_id), &(from->remote_id)); SET_FLAG(attr->flag, BGP_ATTR_ORIGINATOR_ID); } /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ if (peer->sort == 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)); } #define NEXTHOP_IS_V4 (\ (safi != SAFI_ENCAP && p->family == AF_INET) || \ (safi == SAFI_ENCAP && attr->extra->mp_nexthop_len == 4)) #define NEXTHOP_IS_V6 (\ (safi != SAFI_ENCAP && p->family == AF_INET6) || \ (safi == SAFI_ENCAP && attr->extra->mp_nexthop_len == 16)) /* next-hop-set */ if (transparent || (reflect && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL)) || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) && ((NEXTHOP_IS_V4 && attr->nexthop.s_addr) || (NEXTHOP_IS_V6 && ! IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) ))) { /* NEXT-HOP Unchanged. */ } else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) || (NEXTHOP_IS_V4 && attr->nexthop.s_addr == 0) || (NEXTHOP_IS_V6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) || (peer->sort == BGP_PEER_EBGP && (bgp_multiaccess_check_v4 (attr->nexthop, peer) == 0))) { /* Set IPv4 nexthop. */ if (NEXTHOP_IS_V4) { if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) memcpy (&attr->extra->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN); else memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); } /* Set IPv6 nexthop. */ if (NEXTHOP_IS_V6) { /* IPv6 global nexthop must be included. */ memcpy (&attr->extra->mp_nexthop_global, &peer->nexthop.v6_global, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 16; } } if (p->family == AF_INET6 && safi != SAFI_ENCAP) { /* Left nexthop_local unchanged if so configured. */ if ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) { if ( IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_local) ) attr->extra->mp_nexthop_len=32; else attr->extra->mp_nexthop_len=16; } /* Default nexthop_local treatment for non-RS-Clients */ else { /* Link-local address should not be transit to different peer. */ attr->extra->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->extra->mp_nexthop_local, &peer->nexthop.v6_local, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 32; } /* If bgpd act as BGP-4+ route-reflector, do not send link-local address.*/ if (reflect) attr->extra->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->extra->mp_nexthop_len = 16; } } /* If this is EBGP peer and remove-private-AS is set. */ if (peer->sort == 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->extra && ri->extra->suppress) ) { struct bgp_info info; struct attr dummy_attr; struct attr_extra dummy_extra; dummy_attr.extra = &dummy_extra; info.peer = peer; info.attr = attr; /* The route reflector is not allowed to modify the attributes of the reflected IBGP routes, unless configured to allow it */ if ((from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) && !bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { bgp_attr_dup (&dummy_attr, attr); info.attr = &dummy_attr; } SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT); if (ri->extra && ri->extra->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; } static int bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, 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 attr *riattr; from = ri->peer; filter = &rsclient->filter[afi][safi]; riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; if (DISABLE_BGP_ANNOUNCE) return 0; /* Do not send back route to sender. */ if (from == rsclient) return 0; /* Aggregate-address suppress check. */ if (ri->extra && ri->extra->suppress) if (! UNSUPPRESS_MAP_NAME (filter)) return 0; /* Default route check. */ if (CHECK_FLAG (rsclient->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) { if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) return 0; else if (p->family == AF_INET6 && p->prefixlen == 0) return 0; } /* If the attribute has originator-id and it is same as remote peer's id. */ if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) { if (IPV4_ADDR_SAME (&rsclient->remote_id, &riattr->extra->originator_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, "%s [Update:SEND] %s/%d originator-id is same as remote router-id", rsclient->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); return 0; } } /* ORF prefix-list filter check */ if (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) && (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) || CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) if (rsclient->orf_plist[afi][safi]) { if (prefix_list_apply (rsclient->orf_plist[afi][safi], p) == PREFIX_DENY) return 0; } /* Output filter check. */ if (bgp_output_filter (rsclient, p, riattr, afi, safi) == FILTER_DENY) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, "%s [Update:SEND] %s/%d is filtered", rsclient->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 (riattr->aspath, rsclient->as)) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, "%s [Update:SEND] suppress announcement to peer AS %u is AS path.", rsclient->host, rsclient->as); return 0; } #endif /* BGP_SEND_ASPATH_CHECK */ /* For modify attribute, copy it to temporary structure. */ bgp_attr_dup (attr, riattr); /* next-hop-set */ if ((p->family == AF_INET && attr->nexthop.s_addr == 0) || (p->family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) ) { /* Set IPv4 nexthop. */ if (p->family == AF_INET) { if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); else memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); } /* Set IPv6 nexthop. */ if (p->family == AF_INET6) { /* IPv6 global nexthop must be included. */ memcpy (&attr->extra->mp_nexthop_global, &rsclient->nexthop.v6_global, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 16; } } if (p->family == AF_INET6) { struct attr_extra *attre = attr->extra; /* Left nexthop_local unchanged if so configured. */ if ( CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) { if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) ) attre->mp_nexthop_len=32; else attre->mp_nexthop_len=16; } /* Default nexthop_local treatment for RS-Clients */ else { /* Announcer and RS-Client are both in the same network */ if (rsclient->shared_network && from->shared_network && (rsclient->ifindex == from->ifindex)) { if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) ) attre->mp_nexthop_len=32; else attre->mp_nexthop_len=16; } /* Set link-local address for shared network peer. */ else if (rsclient->shared_network && IN6_IS_ADDR_LINKLOCAL (&rsclient->nexthop.v6_local)) { memcpy (&attre->mp_nexthop_local, &rsclient->nexthop.v6_local, IPV6_MAX_BYTELEN); attre->mp_nexthop_len = 32; } else attre->mp_nexthop_len = 16; } } /* If this is EBGP peer and remove-private-AS is set. */ if (rsclient->sort == BGP_PEER_EBGP && peer_af_flag_check (rsclient, 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->extra && ri->extra->suppress) ) { info.peer = rsclient; info.attr = attr; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_OUT); if (ri->extra && ri->extra->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); rsclient->rmap_type = 0; if (ret == RMAP_DENYMATCH) { bgp_attr_flush (attr); return 0; } } return 1; } struct bgp_info_pair { struct bgp_info *old; struct bgp_info *new; }; static void bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *result, afi_t afi, safi_t safi) { struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info *ri; struct bgp_info *ri1; struct bgp_info *ri2; struct bgp_info *nextri = NULL; int cmpret, do_mpath; struct list mp_list; result->old = result->new = NULL; if (rn->info == NULL) { char buf[PREFIX_STRLEN]; zlog_warn ("%s: Called for route_node %s with no routing entries!", __func__, prefix2str (&(bgp_node_to_rnode (rn)->p), buf, sizeof(buf))); return; } bgp_mp_list_init (&mp_list); do_mpath = bgp_mpath_is_configured (bgp, afi, safi); /* 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; if (ri1->peer && ri1->peer != bgp->peer_self) if (ri1->peer->status != Established) continue; new_select = ri1; if (do_mpath) bgp_mp_list_add (&mp_list, ri1); old_select = CHECK_FLAG (ri1->flags, BGP_INFO_SELECTED) ? ri1 : NULL; 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 (ri2->peer && ri2->peer != bgp->peer_self && !CHECK_FLAG (ri2->peer->sflags, PEER_STATUS_NSF_WAIT)) if (ri2->peer->status != Established) continue; if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath) || aspath_cmp_left_confed (ri1->attr->aspath, ri2->attr->aspath)) { if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED)) old_select = ri2; if ((cmpret = bgp_info_cmp (bgp, ri2, new_select, afi, safi)) == -1) { bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED); new_select = ri2; } if (do_mpath) { if (cmpret != 0) bgp_mp_list_clear (&mp_list); if (cmpret == 0 || cmpret == -1) bgp_mp_list_add (&mp_list, ri2); } bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK); } } bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK); bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED); bgp_info_mpath_update (rn, new_select, old_select, &mp_list, afi, safi); bgp_mp_list_clear (&mp_list); } /* Check old selected route and new selected route. */ old_select = NULL; new_select = NULL; for (ri = rn->info; (ri != NULL) && (nextri = ri->next, 1); ri = nextri) { if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) old_select = ri; if (BGP_INFO_HOLDDOWN (ri)) { /* reap REMOVED routes, if needs be * selected route must stay for a while longer though */ if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) && (ri != old_select)) bgp_info_reap (rn, ri); continue; } if (ri->peer && ri->peer != bgp->peer_self && !CHECK_FLAG (ri->peer->sflags, PEER_STATUS_NSF_WAIT)) if (ri->peer->status != Established) continue; if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED) && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED))) { bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); continue; } bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_SELECTED); if ((cmpret = bgp_info_cmp (bgp, ri, new_select, afi, safi)) == -1) { if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_mp_dmed_deselect (new_select); new_select = ri; } else if (cmpret == 1 && do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_mp_dmed_deselect (ri); if (do_mpath) { if (cmpret != 0) bgp_mp_list_clear (&mp_list); if (cmpret == 0 || cmpret == -1) bgp_mp_list_add (&mp_list, ri); } } if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_info_mpath_update (rn, new_select, old_select, &mp_list, afi, safi); bgp_info_mpath_aggregate_update (new_select, old_select); bgp_mp_list_clear (&mp_list); result->old = old_select; result->new = new_select; return; } static int bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, struct bgp_node *rn, afi_t afi, safi_t safi) { struct prefix *p; struct attr attr; struct attr_extra extra; memset (&attr, 0, sizeof(struct attr)); memset (&extra, 0, sizeof(struct attr_extra)); p = &rn->p; /* Announce route to Established peer. */ if (peer->status != Established) return 0; /* Address family configuration check. */ if (! peer->afc_nego[afi][safi]) return 0; /* 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 0; /* It's initialized in bgp_announce_[check|check_rsclient]() */ attr.extra = &extra; switch (bgp_node_table (rn)->type) { case BGP_TABLE_MAIN: /* Announcement to peer->conf. If the route is filtered, withdraw it. */ if (selected && bgp_announce_check (selected, peer, p, &attr, afi, safi)) bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected); else bgp_adj_out_unset (rn, peer, p, afi, safi); break; case BGP_TABLE_RSCLIENT: /* Announcement to peer->conf. If the route is filtered, withdraw it. */ if (selected && bgp_announce_check_rsclient (selected, peer, p, &attr, afi, safi)) bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected); else bgp_adj_out_unset (rn, peer, p, afi, safi); break; } bgp_attr_flush (&attr); return 0; } struct bgp_process_queue { struct bgp *bgp; struct bgp_node *rn; afi_t afi; safi_t safi; }; static wq_item_status bgp_process_rsclient (struct work_queue *wq, void *data) { struct bgp_process_queue *pq = data; struct bgp *bgp = pq->bgp; struct bgp_node *rn = pq->rn; afi_t afi = pq->afi; safi_t safi = pq->safi; struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info_pair old_and_new; struct listnode *node, *nnode; struct peer *rsclient = bgp_node_table (rn)->owner; /* Best path selection. */ bgp_best_selection (bgp, rn, &old_and_new, afi, safi); new_select = old_and_new.new; old_select = old_and_new.old; if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_GROUP)) { if (rsclient->group) for (ALL_LIST_ELEMENTS (rsclient->group->peer, node, nnode, rsclient)) { /* Nothing to do. */ if (old_select && old_select == new_select) if (!CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) continue; if (old_select) bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } bgp_process_announce_selected (rsclient, new_select, rn, afi, safi); } } else { if (old_select) bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } bgp_process_announce_selected (rsclient, new_select, rn, afi, safi); } if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } static wq_item_status bgp_process_main (struct work_queue *wq, void *data) { struct bgp_process_queue *pq = data; struct bgp *bgp = pq->bgp; struct bgp_node *rn = pq->rn; afi_t afi = pq->afi; safi_t safi = pq->safi; struct prefix *p = &rn->p; struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info_pair old_and_new; struct listnode *node, *nnode; struct peer *peer; /* Best path selection. */ bgp_best_selection (bgp, rn, &old_and_new, afi, safi); old_select = old_and_new.old; new_select = old_and_new.new; /* Nothing to do. */ if (old_select && old_select == new_select && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)) { if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) { if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) || CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG)) bgp_zebra_announce (p, old_select, bgp, safi); UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } } /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set */ UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR); if (old_select) bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } /* Check each BGP peer. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { bgp_process_announce_selected (peer, new_select, rn, afi, safi); } /* FIB update. */ if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && (! 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, safi); 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, safi); } } /* Reap old select bgp_info, if it has been removed */ if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } static void bgp_processq_del (struct work_queue *wq, void *data) { struct bgp_process_queue *pq = data; struct bgp_table *table = bgp_node_table (pq->rn); bgp_unlock (pq->bgp); bgp_unlock_node (pq->rn); bgp_table_unlock (table); XFREE (MTYPE_BGP_PROCESS_QUEUE, pq); } static void bgp_process_queue_init (void) { bm->process_main_queue = work_queue_new (bm->master, "process_main_queue"); bm->process_rsclient_queue = work_queue_new (bm->master, "process_rsclient_queue"); if ( !(bm->process_main_queue && bm->process_rsclient_queue) ) { zlog_err ("%s: Failed to allocate work queue", __func__); exit (1); } bm->process_main_queue->spec.workfunc = &bgp_process_main; bm->process_main_queue->spec.del_item_data = &bgp_processq_del; bm->process_main_queue->spec.max_retries = 0; bm->process_main_queue->spec.hold = 50; bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient; bm->process_rsclient_queue->spec.del_item_data = &bgp_processq_del; bm->process_rsclient_queue->spec.max_retries = 0; bm->process_rsclient_queue->spec.hold = 50; } void bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) { struct bgp_process_queue *pqnode; /* already scheduled for processing? */ if (CHECK_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED)) return; if (rn->info == NULL) { /* XXX: Perhaps remove before next release, after we've flushed out * any obvious cases */ assert (rn->info != NULL); char buf[PREFIX_STRLEN]; zlog_warn ("%s: Called for route_node %s with no routing entries!", __func__, prefix2str (&(bgp_node_to_rnode (rn)->p), buf, sizeof(buf))); return; } if ( (bm->process_main_queue == NULL) || (bm->process_rsclient_queue == NULL) ) bgp_process_queue_init (); pqnode = XCALLOC (MTYPE_BGP_PROCESS_QUEUE, sizeof (struct bgp_process_queue)); if (!pqnode) return; /* all unlocked in bgp_processq_del */ bgp_table_lock (bgp_node_table (rn)); pqnode->rn = bgp_lock_node (rn); pqnode->bgp = bgp; bgp_lock (bgp); pqnode->afi = afi; pqnode->safi = safi; switch (bgp_node_table (rn)->type) { case BGP_TABLE_MAIN: work_queue_add (bm->process_main_queue, pqnode); break; case BGP_TABLE_RSCLIENT: work_queue_add (bm->process_rsclient_queue, pqnode); break; } SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return; } static 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_debug ("%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; { u_int8_t ndata[7]; if (safi == SAFI_MPLS_VPN) safi = SAFI_MPLS_LABELED_VPN; ndata[0] = (afi >> 8); ndata[1] = afi; ndata[2] = safi; ndata[3] = (peer->pmax[afi][safi] >> 24); ndata[4] = (peer->pmax[afi][safi] >> 16); ndata[5] = (peer->pmax[afi][safi] >> 8); ndata[6] = (peer->pmax[afi][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_debug ("%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; } /* Unconditionally remove the route from the RIB, without taking * damping into consideration (eg, because the session went down) */ static void bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, afi_t afi, safi_t safi) { bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); if (!CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_info_delete (rn, ri); /* keep historical info */ bgp_process (peer->bgp, rn, afi, safi); } static void bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, afi_t afi, safi_t safi, struct prefix_rd *prd) { int status = BGP_DAMP_NONE; /* apply dampening, if result is suppressed, we'll be retaining * the bgp_info in the RIB for historical reference. */ if (CHECK_FLAG (peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP) if ( (status = bgp_damp_withdraw (ri, rn, afi, safi, 0)) == BGP_DAMP_SUPPRESSED) { bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); return; } bgp_rib_remove (rn, ri, peer, afi, safi); } static struct bgp_info * info_make (int type, int sub_type, struct peer *peer, struct attr *attr, struct bgp_node *rn) { struct bgp_info *new; /* Make new BGP info. */ new = XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info)); new->type = type; new->sub_type = sub_type; new->peer = peer; new->attr = attr; new->uptime = bgp_clock (); new->net = rn; return new; } static void bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct attr *attr, struct peer *peer, struct prefix *p, int type, int sub_type, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp *bgp; struct attr new_attr; struct attr_extra new_extra; struct attr *attr_new; struct attr *attr_new2; struct bgp_info *ri; struct bgp_info *new; const char *reason; char buf[SU_ADDRSTRLEN]; /* Do not insert announces from a rsclient into its own 'bgp_table'. */ if (peer == rsclient) return; bgp = peer->bgp; rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); /* 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 loop check. */ if (aspath_loop_check (attr->aspath, rsclient->as) > rsclient->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 (&rsclient->remote_id, &attr->extra->originator_id)) { reason = "originator is us;"; goto filtered; } new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, attr); /* Apply export policy. */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && bgp_export_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) { reason = "export-policy;"; goto filtered; } attr_new2 = bgp_attr_intern (&new_attr); /* Apply import policy. */ if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) { bgp_attr_unintern (&attr_new2); reason = "import-policy;"; goto filtered; } attr_new = bgp_attr_intern (&new_attr); bgp_attr_unintern (&attr_new2); /* IPv4 unicast next hop check. */ if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST)) { /* Next hop must not be 0.0.0.0 nor Class D/E address. */ if (new_attr.nexthop.s_addr == 0 || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr))) { bgp_attr_unintern (&attr_new); reason = "martian next-hop;"; goto filtered; } } /* If the update is implicit withdraw. */ if (ri) { ri->uptime = bgp_clock (); /* Same attribute comes in. */ if (!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) && attrhash_cmp (ri->attr, attr_new)) { if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s...duplicate ignored", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); bgp_attr_flush(&new_attr); return; } /* Withdraw/Announce before we fully processed the withdraw */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore (rn, ri); /* Received Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Update to new attribute. */ bgp_attr_unintern (&ri->attr); ri->attr = attr_new; /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); bgp_info_set_flag (rn, ri, BGP_INFO_VALID); /* Process change. */ bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); return; } /* Received Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) { zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); } new = info_make(type, sub_type, peer, attr_new, rn); /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (new))->tag, tag, 3); bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); return; filtered: /* This BGP update is filtered. Log the reason then update BGP entry. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE about %s/%d -- DENIED for RS-client %s due to: %s", peer->host, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host, reason); if (ri) bgp_rib_remove (rn, ri, peer, afi, safi); bgp_unlock_node (rn); return; } static void bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct peer *peer, struct prefix *p, int type, int sub_type, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp_info *ri; char buf[SU_ADDRSTRLEN]; if (rsclient == peer) return; rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); /* 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, prd); else if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%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); } static int bgp_update_main (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_extra new_extra; struct attr *attr_new; struct bgp_info *ri; struct bgp_info *new; const char *reason; char buf[SU_ADDRSTRLEN]; int connected = 0; memset (&new_attr, 0, sizeof(struct attr)); memset (&new_extra, 0, sizeof(struct attr_extra)); bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ if (! soft_reconfig && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) && peer != bgp->peer_self) 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->extra->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; } new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, attr); /* Apply incoming route-map. * NB: new_attr may now contain newly allocated values from route-map "set" * commands, so we need bgp_attr_flush in the error paths, until we intern * the attr (which takes over the memory references) */ if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY) { reason = "route-map;"; bgp_attr_flush (&new_attr); goto filtered; } /* IPv4 unicast next hop check. */ if (afi == AFI_IP && safi == SAFI_UNICAST) { /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop must not be my own address. */ if (new_attr.nexthop.s_addr == 0 || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)) || bgp_nexthop_self (&new_attr)) { reason = "martian next-hop;"; bgp_attr_flush (&new_attr); goto filtered; } } attr_new = bgp_attr_intern (&new_attr); /* If the update is implicit withdraw. */ if (ri) { ri->uptime = bgp_clock (); /* Same attribute comes in. */ if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) && attrhash_cmp (ri->attr, attr_new)) { if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED) { bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); } } else /* Duplicate - odd */ { if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%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)) { bgp_info_unset_flag (rn, ri, BGP_INFO_STALE); bgp_process (bgp, rn, afi, safi); } } bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); bgp_attr_flush (&new_attr); return 0; } /* Withdraw/Announce before we fully processed the withdraw */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d, flapped quicker than processing", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); bgp_info_restore (rn, ri); } /* Received Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%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)) bgp_info_unset_flag (rn, ri, BGP_INFO_STALE); /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* implicit withdraw, decrement aggregate and pcount here. * only if update is accepted, they'll increment below. */ bgp_aggregate_decrement (bgp, p, ri, afi, safi); /* Update bgp route dampening information. */ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == 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); } /* Update to new attribute. */ bgp_attr_unintern (&ri->attr); ri->attr = attr_new; /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); bgp_attr_flush (&new_attr); /* Update bgp route dampening information. */ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == 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) { if (peer->sort == BGP_PEER_EBGP && peer_ttl (peer) == 1 && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) connected = 1; else connected = 0; if (bgp_ensure_nexthop (ri, NULL, connected)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else { if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); } bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); } } else bgp_info_set_flag (rn, ri, BGP_INFO_VALID); bgp_attr_flush (&new_attr); /* 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_DEBUG, "%s rcvd %s/%d", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); } /* Make new BGP info. */ new = info_make(type, sub_type, peer, attr_new, rn); /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (new))->tag, tag, 3); /* Nexthop reachability check. */ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) { if (peer->sort == BGP_PEER_EBGP && peer_ttl (peer) == 1 && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) connected = 1; else connected = 0; if (bgp_ensure_nexthop (new, NULL, connected)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else { if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); } bgp_info_unset_flag (rn, new, BGP_INFO_VALID); } } else bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Increment prefix */ bgp_aggregate_increment (bgp, p, new, afi, safi); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); bgp_attr_flush (&new_attr); /* 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_DEBUG, "%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_remove (rn, ri, peer, afi, safi); bgp_unlock_node (rn); bgp_attr_flush (&new_attr); return 0; } 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) { struct peer *rsclient; struct listnode *node, *nnode; struct bgp *bgp; int ret; ret = bgp_update_main (peer, p, attr, afi, safi, type, sub_type, prd, tag, soft_reconfig); bgp = peer->bgp; /* Process the update for each RS-client. */ for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) { if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_update_rsclient (rsclient, afi, safi, attr, peer, p, type, sub_type, prd, tag); } return ret; } int bgp_withdraw (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) { struct bgp *bgp; char buf[SU_ADDRSTRLEN]; struct bgp_node *rn; struct bgp_info *ri; struct peer *rsclient; struct listnode *node, *nnode; bgp = peer->bgp; /* Lookup node. */ rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* Cisco IOS 12.4(24)T4 on session establishment sends withdraws for all * routes that are filtered. This tanks out Quagga RS pretty badly due to * the iteration over all RS clients. * Since we need to remove the entry from adj_in anyway, do that first and * if there was no entry, we don't need to do anything more. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) && peer != bgp->peer_self) if (!bgp_adj_in_unset (rn, peer)) { if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s withdrawing route %s/%d " "not in adj-in", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); bgp_unlock_node (rn); return 0; } /* Process the withdraw for each RS-client. */ for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) { if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_withdraw_rsclient (rsclient, afi, safi, peer, p, type, sub_type, prd, tag); } /* Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE about %s/%d -- withdrawn", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); /* 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, prd); else if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%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 peer *from; struct bgp_node *rn; struct bgp_info *ri; int ret = RMAP_DENYMATCH; if (!(afi == AFI_IP || afi == AFI_IP6)) return; 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); else if (afi == AFI_IP6) { struct attr_extra *ae = attr.extra; str2prefix ("::/0", &p); /* IPv6 global nexthop must be included. */ memcpy (&ae->mp_nexthop_global, &peer->nexthop.v6_global, IPV6_MAX_BYTELEN); ae->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 (&ae->mp_nexthop_local, &peer->nexthop.v6_local, IPV6_MAX_BYTELEN); ae->mp_nexthop_len = 32; } } if (peer->default_rmap[afi][safi].name) { SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT); for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { for (ri = rn->info; ri; ri = ri->next) { struct attr dummy_attr; struct attr_extra dummy_extra; struct bgp_info info; /* Provide dummy so the route-map can't modify the attributes */ dummy_attr.extra = &dummy_extra; bgp_attr_dup(&dummy_attr, ri->attr); info.peer = ri->peer; info.attr = &dummy_attr; ret = route_map_apply(peer->default_rmap[afi][safi].map, &rn->p, RMAP_BGP, &info); /* The route map might have set attributes. If we don't flush them * here, they will be leaked. */ bgp_attr_flush(&dummy_attr); if (ret != RMAP_DENYMATCH) break; } if (ret != RMAP_DENYMATCH) break; } bgp->peer_self->rmap_type = 0; if (ret == RMAP_DENYMATCH) 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 { if (! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); bgp_default_update_send (peer, &attr, afi, safi, from); } } bgp_attr_extra_free (&attr); aspath_unintern (&aspath); } static void bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, int rsclient) { struct bgp_node *rn; struct bgp_info *ri; struct attr attr; struct attr_extra extra; memset(&extra, 0, sizeof(extra)); if (! table) table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi]; if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP) && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) bgp_default_originate (peer, afi, safi, 0); /* It's initialized in bgp_announce_[check|check_rsclient]() */ attr.extra = &extra; 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 ( (rsclient) ? (bgp_announce_check_rsclient (ri, peer, &rn->p, &attr, afi, safi)) : (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); } bgp_attr_flush_encap(&attr); } 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) && (safi != SAFI_ENCAP)) bgp_announce_table (peer, afi, safi, NULL, 0); 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, 0); if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_announce_table (peer, afi, safi, NULL, 1); } 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_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd) { struct bgp_node *rn; struct bgp_adj_in *ain; if (! table) table = rsclient->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) { struct bgp_info *ri = rn->info; u_char *tag = (ri && ri->extra) ? ri->extra->tag : NULL; bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer, &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, tag); } } void bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) { struct bgp_table *table; struct bgp_node *rn; if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)) bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL, NULL); else for (rn = bgp_table_top (rsclient->bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) if ((table = rn->info) != NULL) { struct prefix_rd prd; prd.family = AF_UNSPEC; prd.prefixlen = 64; memcpy(&prd.val, rn->p.u.val, 8); bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table, &prd); } } static void bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd) { 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) { struct bgp_info *ri = rn->info; u_char *tag = (ri && ri->extra) ? ri->extra->tag : NULL; ret = bgp_update (peer, &rn->p, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, tag, 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) && (safi != SAFI_ENCAP)) bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) if ((table = rn->info) != NULL) { struct prefix_rd prd; prd.family = AF_UNSPEC; prd.prefixlen = 64; memcpy(&prd.val, rn->p.u.val, 8); bgp_soft_reconfig_table (peer, afi, safi, table, &prd); } } struct bgp_clear_node_queue { struct bgp_node *rn; enum bgp_clear_route_type purpose; }; static wq_item_status bgp_clear_route_node (struct work_queue *wq, void *data) { struct bgp_clear_node_queue *cnq = data; struct bgp_node *rn = cnq->rn; struct peer *peer = wq->spec.data; struct bgp_info *ri; afi_t afi = bgp_node_table (rn)->afi; safi_t safi = bgp_node_table (rn)->safi; assert (rn && peer); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer || cnq->purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { /* 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_UNUSEABLE)) bgp_info_set_flag (rn, ri, BGP_INFO_STALE); else bgp_rib_remove (rn, ri, peer, afi, safi); break; } return WQ_SUCCESS; } static void bgp_clear_node_queue_del (struct work_queue *wq, void *data) { struct bgp_clear_node_queue *cnq = data; struct bgp_node *rn = cnq->rn; struct bgp_table *table = bgp_node_table (rn); bgp_unlock_node (rn); bgp_table_unlock (table); XFREE (MTYPE_BGP_CLEAR_NODE_QUEUE, cnq); } static void bgp_clear_node_complete (struct work_queue *wq) { struct peer *peer = wq->spec.data; /* Tickle FSM to start moving again */ BGP_EVENT_ADD (peer, Clearing_Completed); peer_unlock (peer); /* bgp_clear_route */ } static void bgp_clear_node_queue_init (struct peer *peer) { char wname[sizeof("clear xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx")]; snprintf (wname, sizeof(wname), "clear %s", peer->host); #undef CLEAR_QUEUE_NAME_LEN if ( (peer->clear_node_queue = work_queue_new (bm->master, wname)) == NULL) { zlog_err ("%s: Failed to allocate work queue", __func__); exit (1); } peer->clear_node_queue->spec.hold = 10; peer->clear_node_queue->spec.workfunc = &bgp_clear_route_node; peer->clear_node_queue->spec.del_item_data = &bgp_clear_node_queue_del; peer->clear_node_queue->spec.completion_func = &bgp_clear_node_complete; peer->clear_node_queue->spec.max_retries = 0; /* we only 'lock' this peer reference when the queue is actually active */ peer->clear_node_queue->spec.data = peer; } static void bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, struct peer *rsclient, enum bgp_clear_route_type purpose) { struct bgp_node *rn; if (! table) table = (rsclient) ? rsclient->rib[afi][safi] : peer->bgp->rib[afi][safi]; /* If still no table => afi/safi isn't configured at all or smth. */ if (! table) return; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { struct bgp_info *ri; struct bgp_adj_in *ain; struct bgp_adj_out *aout; /* XXX:TODO: This is suboptimal, every non-empty route_node is * queued for every clearing peer, regardless of whether it is * relevant to the peer at hand. * * Overview: There are 3 different indices which need to be * scrubbed, potentially, when a peer is removed: * * 1 peer's routes visible via the RIB (ie accepted routes) * 2 peer's routes visible by the (optional) peer's adj-in index * 3 other routes visible by the peer's adj-out index * * 3 there is no hurry in scrubbing, once the struct peer is * removed from bgp->peer, we could just GC such deleted peer's * adj-outs at our leisure. * * 1 and 2 must be 'scrubbed' in some way, at least made * invisible via RIB index before peer session is allowed to be * brought back up. So one needs to know when such a 'search' is * complete. * * Ideally: * * - there'd be a single global queue or a single RIB walker * - rather than tracking which route_nodes still need to be * examined on a peer basis, we'd track which peers still * aren't cleared * * Given that our per-peer prefix-counts now should be reliable, * this may actually be achievable. It doesn't seem to be a huge * problem at this time, */ for (ain = rn->adj_in; ain; ain = ain->next) if (ain->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { bgp_adj_in_remove (rn, ain); bgp_unlock_node (rn); break; } for (aout = rn->adj_out; aout; aout = aout->next) if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { bgp_adj_out_remove (rn, aout, peer, afi, safi); bgp_unlock_node (rn); break; } for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { struct bgp_clear_node_queue *cnq; /* both unlocked in bgp_clear_node_queue_del */ bgp_table_lock (bgp_node_table (rn)); bgp_lock_node (rn); cnq = XCALLOC (MTYPE_BGP_CLEAR_NODE_QUEUE, sizeof (struct bgp_clear_node_queue)); cnq->rn = rn; cnq->purpose = purpose; work_queue_add (peer->clear_node_queue, cnq); break; } } return; } void bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi, enum bgp_clear_route_type purpose) { struct bgp_node *rn; struct bgp_table *table; struct peer *rsclient; struct listnode *node, *nnode; if (peer->clear_node_queue == NULL) bgp_clear_node_queue_init (peer); /* bgp_fsm.c keeps sessions in state Clearing, not transitioning to * Idle until it receives a Clearing_Completed event. This protects * against peers which flap faster than we can we clear, which could * lead to: * * a) race with routes from the new session being installed before * clear_route_node visits the node (to delete the route of that * peer) * b) resource exhaustion, clear_route_node likely leads to an entry * on the process_main queue. Fast-flapping could cause that queue * to grow and grow. */ /* lock peer in assumption that clear-node-queue will get nodes; if so, * the unlock will happen upon work-queue completion; other wise, the * unlock happens at the end of this function. */ if (!peer->clear_node_queue->thread) peer_lock (peer); /* bgp_clear_node_complete */ switch (purpose) { case BGP_CLEAR_ROUTE_NORMAL: if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)) bgp_clear_route_table (peer, afi, safi, NULL, NULL, purpose); 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, NULL, purpose); for (ALL_LIST_ELEMENTS (peer->bgp->rsclient, node, nnode, rsclient)) if (CHECK_FLAG(rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_clear_route_table (peer, afi, safi, NULL, rsclient, purpose); break; case BGP_CLEAR_ROUTE_MY_RSCLIENT: /* * gpz 091009: TBD why don't we have special handling for * SAFI_MPLS_VPN here in the original quagga code? * (and, by extension, for SAFI_ENCAP) */ bgp_clear_route_table (peer, afi, safi, NULL, peer, purpose); break; default: assert (0); break; } /* unlock if no nodes got added to the clear-node-queue. */ if (!peer->clear_node_queue->thread) peer_unlock (peer); } 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, BGP_CLEAR_ROUTE_NORMAL); } /* * Finish freeing things when exiting */ static void bgp_drain_workqueue_immediate (struct work_queue *wq) { if (!wq) return; if (!wq->thread) { /* * no thread implies no queued items */ assert(!wq->items->count); return; } while (wq->items->count) { if (wq->thread) thread_cancel(wq->thread); work_queue_run(wq->thread); } } /* * Special function to process clear node queue when bgpd is exiting * and the thread scheduler is no longer running. */ void bgp_peer_clear_node_queue_drain_immediate(struct peer *peer) { if (!peer) return; bgp_drain_workqueue_immediate(peer->clear_node_queue); } /* * The work queues are not specific to a BGP instance, but the * items in them refer to BGP instances, so this should be called * before each BGP instance is deleted. */ void bgp_process_queues_drain_immediate(void) { bgp_drain_workqueue_immediate(bm->process_main_queue); bgp_drain_workqueue_immediate(bm->process_rsclient_queue); } 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; } } } static void bgp_cleanup_table(struct bgp_table *table, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; struct bgp_info *next; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ri = rn->info; ri; ri = next) { next = 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, safi); } } /* Delete all kernel routes. */ void bgp_cleanup_routes (void) { struct bgp *bgp; struct listnode *node, *nnode; afi_t afi; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { for (afi = AFI_IP; afi < AFI_MAX; ++afi) { struct bgp_node *rn; bgp_cleanup_table(bgp->rib[afi][SAFI_UNICAST], SAFI_UNICAST); /* * VPN and ENCAP tables are two-level (RD is top level) */ for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) { if (rn->info) { bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_MPLS_VPN); bgp_table_finish ((struct bgp_table **)&(rn->info)); rn->info = NULL; bgp_unlock_node(rn); } } for (rn = bgp_table_top(bgp->rib[afi][SAFI_ENCAP]); rn; rn = bgp_route_next (rn)) { if (rn->info) { bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_ENCAP); bgp_table_finish ((struct bgp_table **)&(rn->info)); rn->info = NULL; bgp_unlock_node(rn); } } } } } void bgp_reset (void) { 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_ip (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; /* RFC4771 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. */ for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ memset (&p, 0, sizeof (struct prefix)); /* Fetch prefix length. */ p.prefixlen = *pnt++; /* afi/safi validity already verified by caller, bgp_update_receive */ p.family = afi2family (packet->afi); /* Prefix length check. */ if (p.prefixlen > prefix_blen (&p) * 8) { plog_err (peer->log, "%s [Error] Update packet error" " (wrong prefix length %u for afi %u)", peer->host, p.prefixlen, packet->afi); return -1; } /* Packet size overflow check. */ psize = PSIZE (p.prefixlen); /* When packet overflow occur return immediately. */ if (pnt + psize > lim) { plog_err (peer->log, "%s [Error] Update packet error" " (prefix length %u overflows packet)", peer->host, p.prefixlen); return -1; } /* Defensive coding, double-check the psize fits in a struct prefix */ if (psize > (ssize_t) sizeof(p.u)) { plog_err (peer->log, "%s [Error] Update packet error" " (prefix length %u too large for prefix storage %zu!?!!", peer->host, p.prefixlen, sizeof(p.u)); 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))) { /* * From RFC4271 Section 6.3: * * If a prefix in the NLRI field is semantically incorrect * (e.g., an unexpected multicast IP address), an error SHOULD * be logged locally, and the prefix SHOULD be ignored. */ zlog (peer->log, LOG_ERR, "%s: IPv4 unicast NLRI is multicast address %s, ignoring", peer->host, inet_ntoa (p.u.prefix4)); continue; } } /* 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_ERR, "%s: IPv6 unicast NLRI is link-local address %s, ignoring", peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); continue; } if (IN6_IS_ADDR_MULTICAST (&p.u.prefix6)) { char buf[BUFSIZ]; zlog (peer->log, LOG_ERR, "%s: IPv6 unicast NLRI is multicast address %s, ignoring", peer->host, inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); continue; } } /* 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) { plog_err (peer->log, "%s [Error] Update packet error" " (prefix length mismatch with total length)", peer->host); return -1; } return 0; } static struct bgp_static * bgp_static_new (void) { return XCALLOC (MTYPE_BGP_STATIC, sizeof (struct bgp_static)); } static 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); } static void bgp_static_withdraw_rsclient (struct bgp *bgp, struct peer *rsclient, struct prefix *p, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; rn = bgp_afi_node_get (rsclient->rib[afi][safi], 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_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ bgp_unlock_node (rn); } static void bgp_static_update_rsclient (struct peer *rsclient, 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_new; struct attr attr; struct attr new_attr; struct attr_extra new_extra; struct bgp *bgp; int ret; char buf[SU_ADDRSTRLEN]; bgp = rsclient->bgp; assert (bgp_static); if (!bgp_static) return; rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, NULL); bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); attr.nexthop = bgp_static->igpnexthop; attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); if (bgp_static->atomic) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); /* Apply network route-map for export to this rsclient. */ if (bgp_static->rmap.name) { struct attr attr_tmp = attr; info.peer = rsclient; info.attr = &attr_tmp; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_NETWORK); ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); rsclient->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ bgp_attr_flush (&attr_tmp); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); bgp_attr_extra_free (&attr); return; } attr_new = bgp_attr_intern (&attr_tmp); } else attr_new = bgp_attr_intern (&attr); new_attr.extra = &new_extra; bgp_attr_dup(&new_attr, attr_new); SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi) == RMAP_DENY) { /* This BGP update is filtered. Log the reason then update BGP entry. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (rsclient->log, LOG_DEBUG, "Static UPDATE about %s/%d -- DENIED for RS-client %s due to: import-policy", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); bgp->peer_self->rmap_type = 0; bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); return; } bgp->peer_self->rmap_type = 0; bgp_attr_unintern (&attr_new); attr_new = bgp_attr_intern (&new_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) && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } else { /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore(rn, ri); bgp_attr_unintern (&ri->attr); ri->attr = attr_new; ri->uptime = bgp_clock (); /* Nexthop reachability check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { if (bgp_ensure_nexthop (ri, NULL, 0)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else { if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); } bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); } } /* Process change. */ bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } } /* Make new BGP info. */ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new, rn); /* Nexthop reachability check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { if (bgp_ensure_nexthop (new, NULL, 0)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else { if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); } bgp_info_unset_flag (rn, new, BGP_INFO_VALID); } } else bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } static void bgp_static_update_main (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_new; int ret; assert (bgp_static); if (!bgp_static) return; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL); bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); attr.nexthop = bgp_static->igpnexthop; attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); if (bgp_static->atomic) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); /* Apply route-map. */ if (bgp_static->rmap.name) { struct attr attr_tmp = attr; info.peer = bgp->peer_self; info.attr = &attr_tmp; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); bgp->peer_self->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ bgp_attr_flush (&attr_tmp); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); 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) && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } else { /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore(rn, ri); else bgp_aggregate_decrement (bgp, p, ri, afi, safi); bgp_attr_unintern (&ri->attr); ri->attr = attr_new; ri->uptime = bgp_clock (); /* Nexthop reachability check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { if (bgp_ensure_nexthop (ri, NULL, 0)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else { if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); } bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); } } /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } } /* Make new BGP info. */ new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new, rn); /* Nexthop reachability check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { if (bgp_ensure_nexthop (new, NULL, 0)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else { if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, (const void *)&attr_new->nexthop, buf1, INET6_ADDRSTRLEN); zlog_debug("%s(%s): NH unresolved", __FUNCTION__, buf1); } bgp_info_unset_flag (rn, new, BGP_INFO_VALID); } } else bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Aggregate address increment. */ bgp_aggregate_increment (bgp, p, new, afi, safi); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } void bgp_static_update (struct bgp *bgp, struct prefix *p, struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct peer *rsclient; struct listnode *node, *nnode; bgp_static_update_main (bgp, p, bgp_static, afi, safi); for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) { if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_static_update_rsclient (rsclient, p, bgp_static, 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; /* Make new BGP info. */ rn = bgp_node_get (bgp->rib[afi][safi], p); /* 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); bgp_unlink_nexthop(ri); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ bgp_unlock_node (rn); } void bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) { struct bgp_static *bgp_static; struct bgp *bgp; struct bgp_node *rn; struct prefix *p; bgp = rsclient->bgp; for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_static = rn->info) != NULL) { p = &rn->p; bgp_static_update_rsclient (rsclient, p, bgp_static, afi, safi); } } /* * Used for SAFI_MPLS_VPN and SAFI_ENCAP */ static void bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp_info *ri; rn = bgp_afi_node_get (bgp->rib[afi][safi], 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); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ bgp_unlock_node (rn); } static void bgp_static_update_safi (struct bgp *bgp, struct prefix *p, struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *new; struct attr *attr_new; struct attr attr = { 0 }; struct bgp_info *ri; assert (bgp_static); rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, &bgp_static->prd); bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); 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) { struct attr attr_tmp = attr; struct bgp_info info; int ret; info.peer = bgp->peer_self; info.attr = &attr_tmp; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); bgp->peer_self->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ bgp_attr_flush (&attr_tmp); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_static_withdraw_safi (bgp, p, afi, safi, &bgp_static->prd, bgp_static->tag); 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) && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } else { /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore(rn, ri); else bgp_aggregate_decrement (bgp, p, ri, afi, safi); bgp_attr_unintern (&ri->attr); ri->attr = attr_new; ri->uptime = bgp_clock (); /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } } /* Make new BGP info. */ new = info_make (ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, bgp->peer_self, attr_new, rn); SET_FLAG (new->flags, BGP_INFO_VALID); new->extra = bgp_info_extra_new(); memcpy (new->extra->tag, bgp_static->tag, 3); /* Aggregate address increment. */ bgp_aggregate_increment (bgp, p, new, afi, safi); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } /* Configure static BGP network. When user don't run zebra, static route should be installed as valid. */ static int bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, afi_t afi, safi_t safi, const char *rmap, int backdoor) { int ret; struct prefix p; struct bgp_static *bgp_static; struct bgp_node *rn; u_char 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; } 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; } 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->valid && bgp_static->backdoor != backdoor) 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; } 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. */ static int bgp_static_unset (struct vty *vty, struct bgp *bgp, const char *ip_str, afi_t afi, safi_t 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; } 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; } 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) || (safi == SAFI_ENCAP)) { table = rn->info; for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) { bgp_static = rn->info; bgp_static_withdraw_safi (bgp, &rm->p, AFI_IP, safi, (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); } } } /* * gpz 110624 * Currently this is used to set static routes for VPN and ENCAP. * I think it can probably be factored with bgp_static_set. */ int bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, const char *rd_str, const char *tag_str, const char *rmap_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], (struct prefix *)&prd); if (prn->info == NULL) prn->info = bgp_table_init (AFI_IP, safi); 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->backdoor = 0; bgp_static->valid = 0; bgp_static->igpmetric = 0; bgp_static->igpnexthop.s_addr = 0; memcpy(bgp_static->tag, tag, 3); bgp_static->prd = prd; if (rmap_str) { if (bgp_static->rmap.name) free (bgp_static->rmap.name); bgp_static->rmap.name = strdup (rmap_str); bgp_static->rmap.map = route_map_lookup_by_name (rmap_str); } rn->info = bgp_static; bgp_static->valid = 1; bgp_static_update_safi (bgp, &p, bgp_static, AFI_IP, safi); } return CMD_SUCCESS; } /* Configure static BGP network. */ int bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str, const char *rd_str, const 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], (struct prefix *)&prd); if (prn->info == NULL) prn->info = bgp_table_init (AFI_IP, safi); else bgp_unlock_node (prn); table = prn->info; rn = bgp_node_lookup (table, &p); if (rn) { bgp_static_withdraw_safi (bgp, &p, AFI_IP, safi, &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") 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, bgp_node_safi(vty), 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, bgp_node_safi(vty)); } 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") /* stubs for removed AS-Pathlimit commands, kept for config compatibility */ ALIAS_DEPRECATED (bgp_network, bgp_network_ttl_cmd, "network A.B.C.D/M pathlimit <0-255>", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_backdoor, bgp_network_backdoor_ttl_cmd, "network A.B.C.D/M backdoor pathlimit <0-255>", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask, bgp_network_mask_ttl_cmd, "network A.B.C.D mask A.B.C.D pathlimit <0-255>", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask_backdoor, bgp_network_mask_backdoor_ttl_cmd, "network A.B.C.D mask A.B.C.D backdoor pathlimit <0-255>", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask_natural, bgp_network_mask_natural_ttl_cmd, "network A.B.C.D pathlimit <0-255>", "Specify a network to announce via BGP\n" "Network number\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask_natural_backdoor, bgp_network_mask_natural_backdoor_ttl_cmd, "network A.B.C.D backdoor pathlimit <1-255>", "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network, no_bgp_network_ttl_cmd, "no network A.B.C.D/M pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network, no_bgp_network_backdoor_ttl_cmd, "no network A.B.C.D/M backdoor pathlimit <0-255>", 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" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network, no_bgp_network_mask_ttl_cmd, "no network A.B.C.D mask A.B.C.D pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network_mask, no_bgp_network_mask_backdoor_ttl_cmd, "no network A.B.C.D mask A.B.C.D backdoor pathlimit <0-255>", 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" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network_mask_natural, no_bgp_network_mask_natural_ttl_cmd, "no network A.B.C.D pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network_mask_natural, no_bgp_network_mask_natural_backdoor_ttl_cmd, "no network A.B.C.D backdoor pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (ipv6_bgp_network, ipv6_bgp_network_ttl_cmd, "network X:X::X:X/M pathlimit <0-255>", "Specify a network to announce via BGP\n" "IPv6 prefix /\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_ipv6_bgp_network, no_ipv6_bgp_network_ttl_cmd, "no network X:X::X:X/M pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "IPv6 prefix /\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") /* 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; }; static struct bgp_aggregate * bgp_aggregate_new (void) { return XCALLOC (MTYPE_BGP_AGGREGATE, sizeof (struct bgp_aggregate)); } static void bgp_aggregate_free (struct bgp_aggregate *aggregate) { XFREE (MTYPE_BGP_AGGREGATE, aggregate); } /* Update an aggregate as routes are added/removed from the BGP table */ static 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 bgp_info *ri; struct bgp_info *new; int first = 1; unsigned long match = 0; u_char atomic_aggregate = 0; /* 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) 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->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) atomic_aggregate = 1; if (ri->sub_type != BGP_ROUTE_AGGREGATE) { if (aggregate->summary_only) { (bgp_info_extra_get (ri))->suppress++; bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } aggregate->count++; if (origin < ri->attr->origin) origin = ri->attr->origin; if (aggregate->as_set) { 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) (bgp_info_extra_get (rinew))->suppress++; if (origin < rinew->attr->origin) origin = rinew->attr->origin; if (aggregate->as_set) { 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 = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self, bgp_attr_aggregate_intern(bgp, origin, aspath, community, aggregate->as_set, atomic_aggregate), rn); SET_FLAG (new->flags, BGP_INFO_VALID); bgp_info_add (rn, new); bgp_unlock_node (rn); 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; struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) return; table = bgp->aggregate[afi][safi]; /* No aggregates configured. */ if (bgp_table_top_nolock (table) == NULL) return; if (p->prefixlen == 0) return; if (BGP_INFO_HOLDDOWN (ri)) return; child = bgp_node_get (table, p); /* Aggregate address configuration check. */ for (rn = child; rn; rn = bgp_node_parent_nolock (rn)) 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; struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) return; table = bgp->aggregate[afi][safi]; /* No aggregates configured. */ if (bgp_table_top_nolock (table) == NULL) return; if (p->prefixlen == 0) return; child = bgp_node_get (table, p); /* Aggregate address configuration check. */ for (rn = child; rn; rn = bgp_node_parent_nolock (rn)) 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); } /* Called via bgp_aggregate_set when the user configures aggregate-address */ static 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; u_char atomic_aggregate = 0; 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->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) atomic_aggregate = 1; if (ri->sub_type != BGP_ROUTE_AGGREGATE) { /* summary-only aggregate route suppress aggregated route announcement. */ if (aggregate->summary_only) { (bgp_info_extra_get (ri))->suppress++; bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } /* 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. */ if (origin < ri->attr->origin) origin = ri->attr->origin; /* as-set aggregate route generate origin, as path, community aggregation. */ if (aggregate->as_set) { 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 = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, bgp->peer_self, bgp_attr_aggregate_intern(bgp, origin, aspath, community, aggregate->as_set, atomic_aggregate), rn); SET_FLAG (new->flags, BGP_INFO_VALID); bgp_info_add (rn, new); bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); } else { if (aspath) aspath_free (aspath); if (community) community_free (community); } } 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->extra) { ri->extra->suppress--; if (ri->extra->suppress == 0) { bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } } aggregate->count--; } } /* If this node was 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) { bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ bgp_unlock_node (rn); } /* Aggregate route attribute. */ #define AGGREGATE_SUMMARY_ONLY 1 #define AGGREGATE_AS_SET 1 static int bgp_aggregate_unset (struct vty *vty, const 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; } static int bgp_aggregate_set (struct vty *vty, const 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); /* try to remove the old entry */ ret = bgp_aggregate_unset (vty, prefix_str, afi, safi); if (ret) { vty_out (vty, "Error deleting aggregate.%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; } 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") 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") /* Redistribute route treatment. */ void bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, const struct in6_addr *nexthop6, u_int32_t metric, u_char type, route_tag_t tag) { struct bgp *bgp; struct listnode *node, *nnode; struct bgp_info *new; struct bgp_info *bi; struct bgp_info info; struct bgp_node *bn; struct attr attr; 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; if (nexthop6) { struct attr_extra *extra = bgp_attr_extra_get(&attr); extra->mp_nexthop_global = *nexthop6; extra->mp_nexthop_len = 16; } attr.med = metric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); attr.extra->tag = tag; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { afi = family2afi (p->family); if (bgp->redist[afi][type]) { struct attr attr_new; struct attr_extra extra_new; /* Copy attribute for modification. */ attr_new.extra = &extra_new; bgp_attr_dup (&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].name) { info.peer = bgp->peer_self; info.attr = &attr_new; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE); ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP, &info); bgp->peer_self->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ bgp_attr_flush (&attr_new); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_redistribute_delete (p, type); return; } } bn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], 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) && !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) { bgp_attr_unintern (&new_attr); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_unlock_node (bn); return; } else { /* The attribute is changed. */ bgp_info_set_flag (bn, bi, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) bgp_info_restore(bn, bi); else bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); bgp_attr_unintern (&bi->attr); bi->attr = new_attr; bi->uptime = bgp_clock (); /* 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); bgp_attr_extra_free (&attr); return; } } new = info_make(type, BGP_ROUTE_REDISTRIBUTE, bgp->peer_self, new_attr, bn); SET_FLAG (new->flags, BGP_INFO_VALID); bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST); bgp_info_add (bn, new); bgp_unlock_node (bn); bgp_process (bgp, bn, afi, SAFI_UNICAST); } } /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } void bgp_redistribute_delete (struct prefix *p, u_char type) { struct bgp *bgp; struct listnode *node, *nnode; afi_t afi; struct bgp_node *rn; struct bgp_info *ri; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { afi = family2afi (p->family); if (bgp->redist[afi][type]) { rn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], 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); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, SAFI_UNICAST); } 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); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, SAFI_UNICAST); } } } /* Static function to display route. */ static void 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, " "); } enum bgp_display_type { normal_list, }; /* Print the short form route status for a bgp_info */ static void route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo) { /* Route status display. */ if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED)) vty_out (vty, "R"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE)) vty_out (vty, "S"); else if (binfo->extra && binfo->extra->suppress) vty_out (vty, "s"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_VALID) && ! 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 if (CHECK_FLAG (binfo->flags, BGP_INFO_MULTIPATH)) 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, " "); } /* called from terminal list command */ void route_vty_out( struct vty *vty, struct prefix *p, struct bgp_info *binfo, int display, safi_t safi) { struct attr *attr; /* short status lead text */ route_vty_short_status_out (vty, binfo); /* print prefix and mask */ if (!display) route_vty_out_route (p, vty); else vty_out (vty, "%*s", 17, " "); /* Print attribute */ attr = binfo->attr; if (attr) { /* * NEXTHOP start */ /* * For ENCAP routes, nexthop address family is not * neccessarily the same as the prefix address family. * Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field */ if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) { if (attr->extra) { char buf[BUFSIZ]; int af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len); switch (af) { case AF_INET: vty_out (vty, "%s", inet_ntop(af, &attr->extra->mp_nexthop_global_in, buf, BUFSIZ)); break; case AF_INET6: vty_out (vty, "%s", inet_ntop(af, &attr->extra->mp_nexthop_global, buf, BUFSIZ)); break; default: vty_out(vty, "?"); } } else { vty_out(vty, "?"); } } else { if (p->family == AF_INET) { vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } else if (p->family == AF_INET6) { int len; char buf[BUFSIZ]; len = vty_out (vty, "%s", inet_ntop (AF_INET6, &attr->extra->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, " "); } else { vty_out(vty, "?"); } } /* * NEXTHOP end */ 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, "%7u ", (attr->extra ? attr->extra->weight : 0)); /* Print aspath */ if (attr->aspath) aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); } vty_out (vty, "%s", VTY_NEWLINE); } /* 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) || (safi == SAFI_ENCAP)) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } else if (p->family == AF_INET6) { int len; char buf[BUFSIZ]; assert (attr->extra); len = vty_out (vty, "%s", inet_ntop (AF_INET6, &attr->extra->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, " "); } 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, "%7u ", (attr->extra ? attr->extra->weight : 0)); /* Print aspath */ if (attr->aspath) aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); } vty_out (vty, "%s", VTY_NEWLINE); } void route_vty_out_tag (struct vty *vty, struct prefix *p, struct bgp_info *binfo, int display, safi_t safi) { struct attr *attr; u_int32_t label = 0; if (!binfo->extra) return; /* short status lead text */ route_vty_short_status_out (vty, binfo); /* print prefix and mask */ if (! display) 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) || (safi == SAFI_ENCAP)) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } else if (p->family == AF_INET6) { assert (attr->extra); char buf[BUFSIZ]; char buf1[BUFSIZ]; if (attr->extra->mp_nexthop_len == 16) vty_out (vty, "%s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, BUFSIZ)); else if (attr->extra->mp_nexthop_len == 32) vty_out (vty, "%s(%s)", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, BUFSIZ), inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, buf1, BUFSIZ)); } } label = decode_label (binfo->extra->tag); vty_out (vty, "notag/%d", label); vty_out (vty, "%s", VTY_NEWLINE); } /* dampening route */ static void damp_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo, int display, safi_t safi) { struct attr *attr; int len; char timebuf[BGP_UPTIME_LEN]; /* short status lead text */ route_vty_short_status_out (vty, binfo); /* print prefix and mask */ if (! display) 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, " "); else vty_out (vty, "%*s", len, " "); vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo, timebuf, BGP_UPTIME_LEN)); /* Print attribute */ attr = binfo->attr; if (attr) { /* Print aspath */ if (attr->aspath) aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); } vty_out (vty, "%s", VTY_NEWLINE); } /* flap route */ static void 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; char timebuf[BGP_UPTIME_LEN]; int len; if (!binfo->extra) return; bdi = binfo->extra->damp_info; /* short status lead text */ route_vty_short_status_out (vty, binfo); /* print prefix and mask */ if (! display) 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, " "); 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, timebuf, BGP_UPTIME_LEN)); else vty_out (vty, "%*s ", 8, " "); /* Print attribute */ attr = binfo->attr; if (attr) { /* Print aspath */ if (attr->aspath) aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); } vty_out (vty, "%s", VTY_NEWLINE); } static 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 *); #ifdef HAVE_CLOCK_MONOTONIC time_t tbuf; #endif attr = binfo->attr; if (attr) { /* Line1 display AS-path, Aggregator */ if (attr->aspath) { vty_out (vty, " "); if (aspath_count_hops (attr->aspath) == 0) vty_out (vty, "Local"); else aspath_print_vty (vty, "%s", attr->aspath, ""); } if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED)) vty_out (vty, ", (removed)"); 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 %u %s)", attr->extra->aggregator_as, inet_ntoa (attr->extra->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) || (safi == SAFI_ENCAP)) ? inet_ntoa (attr->extra->mp_nexthop_global_in) : inet_ntoa (attr->nexthop)); } else { assert (attr->extra); vty_out (vty, " %s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, INET6_ADDRSTRLEN)); } 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->extra && binfo->extra->igpmetric) vty_out (vty, " (metric %u)", binfo->extra->igpmetric); if (!sockunion2str (&binfo->peer->su, buf, sizeof(buf))) { buf[0] = '?'; buf[1] = 0; } vty_out (vty, " from %s", buf); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id)); else vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ)); } vty_out (vty, "%s", VTY_NEWLINE); /* display nexthop local */ if (attr->extra && attr->extra->mp_nexthop_len == 32) { vty_out (vty, " (%s)%s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } /* Line 3 display Origin, Med, Locpref, Weight, Tag, 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->extra && attr->extra->weight != 0) vty_out (vty, ", weight %u", attr->extra->weight); if (attr->extra && attr->extra->tag != 0) vty_out (vty, ", tag %d", attr->extra->tag); if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) vty_out (vty, ", invalid"); else 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_MULTIPATH) || (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED) && bgp_info_mpath_count (binfo))) vty_out (vty, ", multipath"); 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->extra->ecommunity->str, VTY_NEWLINE); /* Line 6 display Large community */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) vty_out (vty, " Large Community: %s%s", attr->extra->lcommunity->str, VTY_NEWLINE); /* Line 7 display Originator, Cluster-id */ if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { assert (attr->extra); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) vty_out (vty, " Originator: %s", inet_ntoa (attr->extra->originator_id)); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) { int i; vty_out (vty, ", Cluster list: "); for (i = 0; i < attr->extra->cluster->length / 4; i++) vty_out (vty, "%s ", inet_ntoa (attr->extra->cluster->list[i])); } vty_out (vty, "%s", VTY_NEWLINE); } if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo); /* Line 8 display Uptime */ #ifdef HAVE_CLOCK_MONOTONIC tbuf = time(NULL) - (bgp_clock() - binfo->uptime); vty_out (vty, " Last update: %s", ctime(&tbuf)); #else vty_out (vty, " Last update: %s", ctime(&binfo->uptime)); #endif /* HAVE_CLOCK_MONOTONIC */ } vty_out (vty, "%s", VTY_NEWLINE); } #define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, "\ "h history, * valid, > best, = multipath,%s"\ " i internal, r RIB-failure, S Stale, R Removed%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_lcommunity_all, bgp_show_type_lcommunity, bgp_show_type_lcommunity_list, 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 }; static int bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router_id, enum bgp_show_type type, void *output_arg) { struct bgp_info *ri; struct bgp_node *rn; int header = 1; int display; unsigned long output_count; unsigned long total_count; /* This is first entry point, so reset total line. */ output_count = 0; total_count = 0; /* 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) { total_count++; 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 || type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) { if (!(ri->extra && ri->extra->damp_info)) continue; } if (type == bgp_show_type_regexp || type == bgp_show_type_flap_regexp) { regex_t *regex = 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 = 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 = 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 = output_arg; struct bgp_info binfo; struct attr dummy_attr; struct attr_extra dummy_extra; int ret; dummy_attr.extra = &dummy_extra; bgp_attr_dup (&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 = 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 = 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 = output_arg; if (! ri->attr->community || ! community_match (ri->attr->community, com)) continue; } if (type == bgp_show_type_community_exact) { struct community *com = output_arg; if (! ri->attr->community || ! community_cmp (ri->attr->community, com)) continue; } if (type == bgp_show_type_community_list) { struct community_list *list = output_arg; if (! community_list_match (ri->attr->community, list)) continue; } if (type == bgp_show_type_community_list_exact) { struct community_list *list = output_arg; if (! community_list_exact_match (ri->attr->community, list)) continue; } if (type == bgp_show_type_community_all) { if (! ri->attr->community) continue; } if (type == bgp_show_type_lcommunity) { struct lcommunity *lcom = output_arg; if (! ri->attr->extra || ! ri->attr->extra->lcommunity || ! lcommunity_match (ri->attr->extra->lcommunity, lcom)) continue; } if (type == bgp_show_type_lcommunity_list) { struct community_list *list = output_arg; if (! ri->attr->extra || ! lcommunity_list_match (ri->attr->extra->lcommunity, list)) continue; } if (type == bgp_show_type_lcommunity_all) { if (! ri->attr->extra || ! ri->attr->extra->lcommunity) continue; } if (type == bgp_show_type_flap_address || type == bgp_show_type_flap_prefix) { struct prefix *p = 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 (*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); header = 0; } if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) 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) flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); else route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); display++; } if (display) output_count++; } /* No route is displayed */ if (output_count == 0) { if (type == bgp_show_type_normal) vty_out (vty, "No BGP prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); } else vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); return CMD_SUCCESS; } static int bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_show_type type, void *output_arg) { struct bgp_table *table; if (bgp == NULL) { bgp = bgp_get_default (); } if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } table = bgp->rib[afi][safi]; return bgp_show_table (vty, table, &bgp->router_id, type, output_arg); } /* Header of detailed BGP route information */ static 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 *node, *nnode; 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; int printrd = ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)); p = &rn->p; vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", (printrd ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), printrd ? ":" : "", 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->extra && ri->extra->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 */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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. */ static int bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, struct bgp_table *rib, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, int prefix_check, enum bgp_path_type pathtype) { int ret; int header; int display = 0; struct prefix match; struct bgp_node *rn; struct bgp_node *rm; struct bgp_info *ri; struct bgp_table *table; memset (&match, 0, sizeof (struct prefix)); /* keep valgrind happy */ /* 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) || (safi == SAFI_ENCAP)) { for (rn = bgp_table_top (rib); 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) { bgp_unlock_node (rm); 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); header = 0; } display++; if (pathtype == BGP_PATH_ALL || (pathtype == BGP_PATH_BESTPATH && CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) || (pathtype == BGP_PATH_MULTIPATH && (CHECK_FLAG (ri->flags, BGP_INFO_MULTIPATH) || CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)))) route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, safi); } bgp_unlock_node (rm); } } } } else { header = 1; if ((rn = bgp_node_match (rib, &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++; if (pathtype == BGP_PATH_ALL || (pathtype == BGP_PATH_BESTPATH && CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) || (pathtype == BGP_PATH_MULTIPATH && (CHECK_FLAG (ri->flags, BGP_INFO_MULTIPATH) || CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)))) route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi); } } bgp_unlock_node (rn); } } if (! display) { vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* Display specified route of Main RIB */ static int bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, int prefix_check, enum bgp_path_type pathtype) { struct bgp *bgp; /* 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; } } return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str, afi, safi, prd, prefix_check, pathtype); } /* 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, NULL); } 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, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } 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, BGP_PATH_ALL); } DEFUN (show_ip_bgp_route_pathtype, show_ip_bgp_route_pathtype_cmd, "show ip bgp A.B.C.D (bestpath|multipath)", SHOW_STR IP_STR BGP_STR "IP prefix /, e.g., 35.0.0.0/8\n" "Display only the bestpath\n" "Display only multipaths\n") { if (strncmp (argv[1], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH); } DEFUN (show_bgp_ipv4_safi_route_pathtype, show_bgp_ipv4_safi_route_pathtype_cmd, "show bgp ipv4 (unicast|multicast) A.B.C.D (bestpath|multipath)", SHOW_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 only the bestpath\n" "Display only multipaths\n") { if (strncmp (argv[0], "m", 1) == 0) if (strncmp (argv[2], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0, BGP_PATH_MULTIPATH); else if (strncmp (argv[2], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH); } 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, BGP_PATH_ALL); return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } 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, BGP_PATH_ALL); } 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, BGP_PATH_ALL); } 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, BGP_PATH_ALL); } DEFUN (show_ip_bgp_prefix_pathtype, show_ip_bgp_prefix_pathtype_cmd, "show ip bgp A.B.C.D/M (bestpath|multipath)", SHOW_STR IP_STR BGP_STR "IP prefix /, e.g., 35.0.0.0/8\n" "Display only the bestpath\n" "Display only multipaths\n") { if (strncmp (argv[1], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH); } 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, BGP_PATH_ALL); return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_ip_bgp_ipv4_prefix_pathtype, show_ip_bgp_ipv4_prefix_pathtype_cmd, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M (bestpath|multipath)", 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 only the bestpath\n" "Display only multipaths\n") { if (strncmp (argv[0], "m", 1) == 0) if (strncmp (argv[2], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1, BGP_PATH_MULTIPATH); else if (strncmp (argv[2], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH); } ALIAS (show_ip_bgp_ipv4_prefix_pathtype, show_bgp_ipv4_safi_prefix_pathtype_cmd, "show bgp ipv4 (unicast|multicast) A.B.C.D/M (bestpath|multipath)", SHOW_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 only the bestpath\n" "Display only multipaths\n") 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, BGP_PATH_ALL); } 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, BGP_PATH_ALL); } DEFUN (show_ip_bgp_view, show_ip_bgp_view_cmd, "show ip bgp view WORD", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n") { struct bgp *bgp; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, bgp, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } 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" "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, BGP_PATH_ALL); } 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" "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, BGP_PATH_ALL); } 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, NULL); } 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, NULL); } 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, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_safi, show_bgp_ipv4_safi_cmd, "show bgp ipv4 (unicast|multicast)", SHOW_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, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_bgp_ipv4_safi_route, show_bgp_ipv4_safi_route_cmd, "show bgp ipv4 (unicast|multicast) A.B.C.D", SHOW_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, BGP_PATH_ALL); return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_route_pathtype, show_bgp_route_pathtype_cmd, "show bgp X:X::X:X (bestpath|multipath)", SHOW_STR BGP_STR "Network in the BGP routing table to display\n" "Display only the bestpath\n" "Display only multipaths\n") { if (strncmp (argv[1], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH); } ALIAS (show_bgp_route_pathtype, show_bgp_ipv6_route_pathtype_cmd, "show bgp ipv6 X:X::X:X (bestpath|multipath)", SHOW_STR BGP_STR "Address family\n" "Network in the BGP routing table to display\n" "Display only the bestpath\n" "Display only multipaths\n") DEFUN (show_bgp_ipv6_safi_route_pathtype, show_bgp_ipv6_safi_route_pathtype_cmd, "show bgp ipv6 (unicast|multicast) X:X::X:X (bestpath|multipath)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Network in the BGP routing table to display\n" "Display only the bestpath\n" "Display only multipaths\n") { if (strncmp (argv[0], "m", 1) == 0) if (strncmp (argv[2], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_MULTIPATH); else if (strncmp (argv[2], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_MULTIPATH); } DEFUN (show_bgp_ipv4_vpn_route, show_bgp_ipv4_vpn_route_cmd, "show bgp ipv4 vpn A.B.C.D", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\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, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_vpn_route, show_bgp_ipv6_vpn_route_cmd, "show bgp ipv6 vpn X:X::X:X", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_vpn_rd_route, show_bgp_ipv4_vpn_rd_route_cmd, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn A.B.C.D", SHOW_STR BGP_STR IP_STR "Display VPN 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, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_vpn_rd_route, show_bgp_ipv6_vpn_rd_route_cmd, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn X:X::X:X", SHOW_STR BGP_STR "Address Family\n" "Display VPN 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_IP6, SAFI_MPLS_VPN, &prd, 0, BGP_PATH_ALL); } DEFUN (show_bgp_prefix_pathtype, show_bgp_prefix_pathtype_cmd, "show bgp X:X::X:X/M (bestpath|multipath)", SHOW_STR BGP_STR "IPv6 prefix /\n" "Display only the bestpath\n" "Display only multipaths\n") { if (strncmp (argv[1], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH); } ALIAS (show_bgp_prefix_pathtype, show_bgp_ipv6_prefix_pathtype_cmd, "show bgp ipv6 X:X::X:X/M (bestpath|multipath)", SHOW_STR BGP_STR "Address family\n" "IPv6 prefix /\n" "Display only the bestpath\n" "Display only multipaths\n") DEFUN (show_bgp_ipv6_safi_prefix_pathtype, show_bgp_ipv6_safi_prefix_pathtype_cmd, "show bgp ipv6 (unicast|multicast) X:X::X:X/M (bestpath|multipath)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Display only the bestpath\n" "Display only multipaths\n") { if (strncmp (argv[0], "m", 1) == 0) if (strncmp (argv[2], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_MULTIPATH); else if (strncmp (argv[2], "b", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_BESTPATH); else return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_MULTIPATH); } DEFUN (show_bgp_ipv4_encap_route, show_bgp_ipv4_encap_route_cmd, "show bgp ipv4 encap A.B.C.D", SHOW_STR BGP_STR IP_STR "Display ENCAP NLRI specific information\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_encap_route, show_bgp_ipv6_encap_route_cmd, "show bgp ipv6 encap X:X::X:X", SHOW_STR BGP_STR IP6_STR "Display ENCAP NLRI specific information\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_safi_rd_route, show_bgp_ipv4_safi_rd_route_cmd, "show bgp ipv4 (encap|vpn) rd ASN:nn_or_IP-address:nn A.B.C.D", SHOW_STR BGP_STR "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "Network in the BGP routing table to display\n") { int ret; struct prefix_rd prd; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2prefix_rd (argv[1], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_safi_rd_route, show_bgp_ipv6_safi_rd_route_cmd, "show bgp ipv6 (encap|vpn) rd ASN:nn_or_IP-address:nn X:X::X:X", SHOW_STR BGP_STR "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "Network in the BGP routing table to display\n") { int ret; struct prefix_rd prd; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2prefix_rd (argv[1], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, NULL, argv[2], AFI_IP6, SAFI_ENCAP, &prd, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_prefix, show_bgp_ipv4_prefix_cmd, "show bgp ipv4 A.B.C.D/M", SHOW_STR BGP_STR IP_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, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_safi_prefix, show_bgp_ipv4_safi_prefix_cmd, "show bgp ipv4 (unicast|multicast) A.B.C.D/M", SHOW_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, BGP_PATH_ALL); return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_vpn_prefix, show_bgp_ipv4_vpn_prefix_cmd, "show bgp ipv4 vpn A.B.C.D/M", SHOW_STR BGP_STR IP_STR "Display VPN NLRI specific information\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, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_vpn_prefix, show_bgp_ipv6_vpn_prefix_cmd, "show bgp ipv6 vpn X:X::X:X/M", SHOW_STR BGP_STR "Address Family\n" "Display VPN NLRI specific information\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MPLS_VPN, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_encap_prefix, show_bgp_ipv4_encap_prefix_cmd, "show bgp ipv4 encap A.B.C.D/M", SHOW_STR BGP_STR IP_STR "Display ENCAP NLRI specific information\n" "Display information about ENCAP NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_ENCAP, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_encap_prefix, show_bgp_ipv6_encap_prefix_cmd, "show bgp ipv6 encap X:X::X:X/M", SHOW_STR BGP_STR IP_STR "Display ENCAP NLRI specific information\n" "Display information about ENCAP NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_ENCAP, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv4_safi_rd_prefix, show_bgp_ipv4_safi_rd_prefix_cmd, "show bgp ipv4 (encap|vpn) rd ASN:nn_or_IP-address:nn A.B.C.D/M", SHOW_STR BGP_STR "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "IP prefix /, e.g., 35.0.0.0/8\n") { int ret; struct prefix_rd prd; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2prefix_rd (argv[1], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, NULL, argv[2], AFI_IP, safi, &prd, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_safi_rd_prefix, show_bgp_ipv6_safi_rd_prefix_cmd, "show bgp ipv6 (encap|vpn) rd ASN:nn_or_IP-address:nn X:X::X:X/M", SHOW_STR BGP_STR "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "IP prefix /, e.g., 35.0.0.0/8\n") { int ret; struct prefix_rd prd; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2prefix_rd (argv[1], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, NULL, argv[2], AFI_IP6, safi, &prd, 1, BGP_PATH_ALL); } DEFUN (show_bgp_afi_safi_view, show_bgp_afi_safi_view_cmd, "show bgp view WORD (ipv4|ipv6) (encap|mulicast|unicast|vpn)", SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "Address Family\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" ) { struct bgp *bgp; safi_t safi; afi_t afi; if (bgp_parse_afi(argv[1], &afi)) { vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } if (bgp_parse_safi(argv[2], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, bgp, afi, safi, bgp_show_type_normal, NULL); } DEFUN (show_bgp_view_afi_safi_route, show_bgp_view_afi_safi_route_cmd, "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) A.B.C.D", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address Family\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Network in the BGP routing table to display\n") { safi_t safi; afi_t afi; if (bgp_parse_afi(argv[1], &afi)) { vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } if (bgp_parse_safi(argv[2], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_view_afi_safi_prefix, show_bgp_view_afi_safi_prefix_cmd, "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) A.B.C.D/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address Family\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n") { safi_t safi; afi_t afi; if (bgp_parse_afi(argv[1], &afi)) { vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } if (bgp_parse_safi(argv[2], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, argv[0], argv[3], afi, safi, NULL, 1, BGP_PATH_ALL); } /* new001 */ DEFUN (show_bgp_afi, show_bgp_afi_cmd, "show bgp (ipv4|ipv6)", SHOW_STR BGP_STR "Address family\n" "Address family\n") { afi_t afi; if (bgp_parse_afi(argv[0], &afi)) { vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_bgp_ipv6_safi, show_bgp_ipv6_safi_cmd, "show bgp ipv6 (unicast|multicast)", SHOW_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_IP6, SAFI_MULTICAST, bgp_show_type_normal, NULL); return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_bgp_ipv6_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") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_safi_route, show_bgp_ipv6_safi_route_cmd, "show bgp ipv6 (unicast|multicast) X:X::X:X", SHOW_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_IP6, SAFI_MULTICAST, NULL, 0, BGP_PATH_ALL); return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } /* 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, BGP_PATH_ALL); } 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, BGP_PATH_ALL); } /* new002 */ DEFUN (show_bgp_ipv6_prefix, show_bgp_ipv6_prefix_cmd, "show bgp ipv6 X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "IPv6 prefix /, e.g., 3ffe::/16\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_ipv6_safi_prefix, show_bgp_ipv6_safi_prefix_cmd, "show bgp ipv6 (unicast|multicast) X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IPv6 prefix /, e.g., 3ffe::/16\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1, BGP_PATH_ALL); return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } /* 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, BGP_PATH_ALL); } DEFUN (show_bgp_view, show_bgp_view_cmd, "show bgp view WORD", SHOW_STR BGP_STR "BGP view\n" "View name\n") { struct bgp *bgp; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, bgp, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_bgp_view_ipv6, show_bgp_view_ipv6_cmd, "show bgp view WORD ipv6", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n") { struct bgp *bgp; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, bgp, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_bgp_view_route, show_bgp_view_route_cmd, "show bgp view WORD X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_view_ipv6_route, show_bgp_view_ipv6_route_cmd, "show bgp view WORD ipv6 X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } /* 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, NULL); } /* 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, BGP_PATH_ALL); } /* 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, BGP_PATH_ALL); } DEFUN (show_bgp_view_prefix, show_bgp_view_prefix_cmd, "show bgp view WORD X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "IPv6 prefix /\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_view_ipv6_prefix, show_bgp_view_ipv6_prefix_cmd, "show bgp view WORD ipv6 X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "IPv6 prefix /\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } static int bgp_show_regexp (struct vty *vty, int argc, const 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; int rc; 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); XFREE(MTYPE_TMP, regstr); if (! regex) { vty_out (vty, "Can't compile regexp %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } rc = bgp_show (vty, NULL, afi, safi, type, regex); bgp_regex_free (regex); return rc; } 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); } ALIAS (show_ip_bgp_flap_regexp, show_ip_bgp_damp_flap_regexp_cmd, "show ip bgp dampening flap-statistics regexp .LINE", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\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") 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); } 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); } /* 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); } DEFUN (show_bgp_ipv4_safi_flap_regexp, show_bgp_ipv4_safi_flap_regexp_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", SHOW_STR BGP_STR IP_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP, safi, bgp_show_type_flap_regexp); } ALIAS (show_bgp_ipv4_safi_flap_regexp, show_bgp_ipv4_safi_damp_flap_regexp_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics regexp .LINE", SHOW_STR BGP_STR IP_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\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") DEFUN (show_bgp_ipv6_safi_flap_regexp, show_bgp_ipv6_safi_flap_regexp_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", SHOW_STR BGP_STR IPV6_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP6, safi, bgp_show_type_flap_regexp); } ALIAS (show_bgp_ipv6_safi_flap_regexp, show_bgp_ipv6_safi_damp_flap_regexp_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics regexp .LINE", SHOW_STR BGP_STR IPV6_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\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") DEFUN (show_bgp_ipv4_safi_regexp, show_bgp_ipv4_safi_regexp_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) regexp .LINE", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP, safi, bgp_show_type_regexp); } DEFUN (show_bgp_ipv6_safi_regexp, show_bgp_ipv6_safi_regexp_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) regexp .LINE", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_regexp (vty, argc-1, argv+1, AFI_IP6, safi, bgp_show_type_regexp); } DEFUN (show_bgp_ipv6_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") { return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, bgp_show_type_regexp); } static int bgp_show_prefix_list (struct vty *vty, const 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; } return bgp_show (vty, NULL, afi, safi, type, plist); } 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); } ALIAS (show_ip_bgp_flap_prefix_list, show_ip_bgp_damp_flap_prefix_list_cmd, "show ip bgp dampening flap-statistics prefix-list WORD", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") 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); } 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); } DEFUN (show_bgp_ipv4_prefix_list, show_bgp_ipv4_prefix_list_cmd, "show bgp ipv4 prefix-list WORD", SHOW_STR BGP_STR IP_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_bgp_ipv4_safi_flap_prefix_list, show_bgp_ipv4_safi_flap_prefix_list_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics prefix-list WORD", SHOW_STR BGP_STR IP_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_list (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_prefix_list); } ALIAS (show_bgp_ipv4_safi_flap_prefix_list, show_bgp_ipv4_safi_damp_flap_prefix_list_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics prefix-list WORD", SHOW_STR BGP_STR IP_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFUN (show_bgp_ipv6_safi_flap_prefix_list, show_bgp_ipv6_safi_flap_prefix_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics prefix-list WORD", SHOW_STR BGP_STR IPV6_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_list (vty, argv[1], AFI_IP6, safi, bgp_show_type_flap_prefix_list); } ALIAS (show_bgp_ipv6_safi_flap_prefix_list, show_bgp_ipv6_safi_damp_flap_prefix_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics prefix-list WORD", SHOW_STR BGP_STR IPV6_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFUN (show_bgp_ipv4_safi_prefix_list, show_bgp_ipv4_safi_prefix_list_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) prefix-list WORD", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_list (vty, argv[1], AFI_IP, safi, bgp_show_type_prefix_list); } DEFUN (show_bgp_ipv6_safi_prefix_list, show_bgp_ipv6_safi_prefix_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) prefix-list WORD", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_list (vty, argv[1], AFI_IP6, safi, bgp_show_type_prefix_list); } static int bgp_show_filter_list (struct vty *vty, const 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; } return bgp_show (vty, NULL, afi, safi, type, as_list); } 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); } ALIAS (show_ip_bgp_flap_filter_list, show_ip_bgp_damp_flap_filter_list_cmd, "show ip bgp dampening flap-statistics filter-list WORD", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") 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); } 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); } /* 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); } DEFUN (show_ip_bgp_dampening_info, show_ip_bgp_dampening_params_cmd, "show ip bgp dampening parameters", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display detail of configured dampening parameters\n") { return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); } DEFUN (show_bgp_ipv4_filter_list, show_bgp_ipv4_filter_list_cmd, "show bgp ipv4 filter-list WORD", SHOW_STR BGP_STR IP_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_bgp_ipv4_safi_flap_filter_list, show_bgp_ipv4_safi_flap_filter_list_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics filter-list WORD", SHOW_STR BGP_STR IP_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_filter_list (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_filter_list); } ALIAS (show_bgp_ipv4_safi_flap_filter_list, show_bgp_ipv4_safi_damp_flap_filter_list_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics filter-list WORD", SHOW_STR BGP_STR IP_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFUN (show_bgp_ipv6_safi_flap_filter_list, show_bgp_ipv6_safi_flap_filter_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics filter-list WORD", SHOW_STR BGP_STR IPV6_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_filter_list (vty, argv[1], AFI_IP6, safi, bgp_show_type_flap_filter_list); } ALIAS (show_bgp_ipv6_safi_flap_filter_list, show_bgp_ipv6_safi_damp_flap_filter_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics filter-list WORD", SHOW_STR BGP_STR IPV6_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFUN (show_bgp_ipv4_safi_filter_list, show_bgp_ipv4_safi_filter_list_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) filter-list WORD", SHOW_STR BGP_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_filter_list (vty, argv[1], AFI_IP, safi, bgp_show_type_filter_list); } DEFUN (show_bgp_ipv6_safi_filter_list, show_bgp_ipv6_safi_filter_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) filter-list WORD", SHOW_STR BGP_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_filter_list (vty, argv[1], AFI_IP6, safi, bgp_show_type_filter_list); } DEFUN (show_bgp_ipv6_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") { return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_filter_list); } DEFUN (show_ip_bgp_ipv4_dampening_parameters, show_ip_bgp_ipv4_dampening_parameters_cmd, "show ip bgp ipv4 (unicast|multicast) dampening parameters", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display detail of configured dampening parameters\n") { if (strncmp(argv[0], "m", 1) == 0) return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_MULTICAST); return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_dampening_flap_stats, show_ip_bgp_ipv4_dampening_flap_stats_cmd, "show ip bgp ipv4 (unicast|multicast) dampening flap-statistics", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") { if (strncmp(argv[0], "m", 1) == 0) return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_flap_statistics, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_flap_statistics, NULL); } DEFUN (show_ip_bgp_ipv4_dampening_dampd_paths, show_ip_bgp_ipv4_dampening_dampd_paths_cmd, "show ip bgp ipv4 (unicast|multicast) dampening dampened-paths", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") { if (strncmp(argv[0], "m", 1) == 0) return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_dampend_paths, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_dampend_paths, NULL); } static int bgp_show_route_map (struct vty *vty, const 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; } return bgp_show (vty, NULL, afi, safi, type, rmap); } 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); } ALIAS (show_ip_bgp_flap_route_map, show_ip_bgp_damp_flap_route_map_cmd, "show ip bgp dampening flap-statistics route-map WORD", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") 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); } 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, NULL); } 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, NULL); } ALIAS (show_ip_bgp_flap_cidr_only, show_ip_bgp_damp_flap_cidr_only_cmd, "show ip bgp dampening flap-statistics cidr-only", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") 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, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_cidr_only, NULL); } 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, NULL); } 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, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_community_all, NULL); } 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, NULL); } 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, NULL); } /* 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, NULL); } /* large-community */ DEFUN (show_ip_bgp_lcommunity_all, show_ip_bgp_lcommunity_all_cmd, "show ip bgp large-community", SHOW_STR IP_STR BGP_STR "Display routes matching the large-communities\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_lcommunity_all, NULL); } DEFUN (show_ip_bgp_ipv4_lcommunity_all, show_ip_bgp_ipv4_lcommunity_all_cmd, "show ip bgp ipv4 (unicast|multicast) large-community", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_lcommunity_all, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_lcommunity_all, NULL); } DEFUN (show_bgp_lcommunity_all, show_bgp_lcommunity_all_cmd, "show bgp large-community", SHOW_STR BGP_STR "Display routes matching the large-communities\n") { return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_lcommunity_all, NULL); } ALIAS (show_bgp_lcommunity_all, show_bgp_ipv6_lcommunity_all_cmd, "show bgp ipv6 large-community", SHOW_STR BGP_STR "Address family\n" "Display routes matching the large-communities\n") /* old command */ DEFUN (show_ipv6_bgp_lcommunity_all, show_ipv6_bgp_lcommunity_all_cmd, "show ipv6 bgp large-community", SHOW_STR IPV6_STR BGP_STR "Display routes matching the large-communities\n") { return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_lcommunity_all, NULL); } /* old command */ DEFUN (show_ipv6_mbgp_lcommunity_all, show_ipv6_mbgp_lcommunity_all_cmd, "show ipv6 mbgp large-community", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the large-communities\n") { return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_lcommunity_all, NULL); } DEFUN (show_bgp_ipv4_route_map, show_bgp_ipv4_route_map_cmd, "show bgp ipv4 route-map WORD", SHOW_STR BGP_STR IP_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_bgp_ipv4_safi_flap_route_map, show_bgp_ipv4_safi_flap_route_map_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics route-map WORD", SHOW_STR BGP_STR IP_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_map (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_route_map); } ALIAS (show_bgp_ipv4_safi_flap_route_map, show_bgp_ipv4_safi_damp_flap_route_map_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics route-map WORD", SHOW_STR BGP_STR IP_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFUN (show_bgp_ipv6_safi_flap_route_map, show_bgp_ipv6_safi_flap_route_map_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics route-map WORD", SHOW_STR BGP_STR IPV6_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_map (vty, argv[1], AFI_IP6, safi, bgp_show_type_flap_route_map); } ALIAS (show_bgp_ipv6_safi_flap_route_map, show_bgp_ipv6_safi_damp_flap_route_map_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics route-map WORD", SHOW_STR BGP_STR IPV6_STR "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFUN (show_bgp_ipv4_safi_route_map, show_bgp_ipv4_safi_route_map_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) route-map WORD", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the route-map\n" "A route-map to match on\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_map (vty, argv[1], AFI_IP, safi, bgp_show_type_route_map); } DEFUN (show_bgp_ipv6_safi_route_map, show_bgp_ipv6_safi_route_map_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) route-map WORD", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the route-map\n" "A route-map to match on\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_map (vty, argv[1], AFI_IP6, safi, bgp_show_type_route_map); } DEFUN (show_bgp_ipv6_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") { return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_route_map); } DEFUN (show_bgp_ipv4_cidr_only, show_bgp_ipv4_cidr_only_cmd, "show bgp ipv4 cidr-only", SHOW_STR BGP_STR IP_STR "Display only routes with non-natural netmasks\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_cidr_only, NULL); } DEFUN (show_bgp_ipv4_safi_flap_cidr_only, show_bgp_ipv4_safi_flap_cidr_only_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics cidr-only", SHOW_STR BGP_STR "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, AFI_IP, safi, bgp_show_type_flap_cidr_only, NULL); } ALIAS (show_bgp_ipv4_safi_flap_cidr_only, show_bgp_ipv4_safi_damp_flap_cidr_only_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics cidr-only", SHOW_STR BGP_STR "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") DEFUN (show_bgp_ipv4_safi_cidr_only, show_bgp_ipv4_safi_cidr_only_cmd, "show bgp ipv4 (unicast|multicast) cidr-only", SHOW_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, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_cidr_only, NULL); } /* new046 */ DEFUN (show_bgp_afi_safi_community_all, show_bgp_afi_safi_community_all_cmd, "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) community", SHOW_STR BGP_STR "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") { safi_t safi; afi_t afi; if (bgp_parse_afi(argv[0], &afi)) { vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } if (bgp_parse_safi(argv[1], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_all, NULL); } DEFUN (show_bgp_afi_community_all, show_bgp_afi_community_all_cmd, "show bgp (ipv4|ipv6) community", SHOW_STR BGP_STR "Address family\n" "Address family\n" "Display routes matching the communities\n") { afi_t afi; safi_t safi = SAFI_UNICAST; if (bgp_parse_afi(argv[0], &afi)) { vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, safi, bgp_show_type_community_all, NULL); } static int bgp_show_community (struct vty *vty, const char *view_name, int argc, const char **argv, int exact, afi_t afi, safi_t safi) { struct community *com; struct buffer *b; struct bgp *bgp; int i, rv; char *str; int first = 0; /* 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; } } 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); XFREE (MTYPE_TMP, str); if (! com) { vty_out (vty, "%% Community malformed: %s", VTY_NEWLINE); return CMD_WARNING; } rv = bgp_show (vty, bgp, afi, safi, (exact ? bgp_show_type_community_exact : bgp_show_type_community), com); community_free(com); return rv; } 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, NULL, 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, NULL, argc, argv, 0, AFI_IP, SAFI_MULTICAST); return bgp_show_community (vty, NULL, 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, NULL, 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, NULL, argc, argv, 1, AFI_IP, SAFI_MULTICAST); return bgp_show_community (vty, NULL, 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") 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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") DEFUN (show_bgp_ipv4_community, show_bgp_ipv4_community_cmd, "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR IP_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, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } ALIAS (show_bgp_ipv4_community, show_bgp_ipv4_community2_cmd, "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR IP_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_ipv4_community, show_bgp_ipv4_community3_cmd, "show bgp ipv4 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 IP_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_ipv4_community, show_bgp_ipv4_community4_cmd, "show bgp ipv4 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 IP_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_ipv4_safi_community, show_bgp_ipv4_safi_community_cmd, "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", SHOW_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, NULL, argc, argv, 0, AFI_IP, SAFI_MULTICAST); return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } ALIAS (show_bgp_ipv4_safi_community, show_bgp_ipv4_safi_community2_cmd, "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_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_bgp_ipv4_safi_community, show_bgp_ipv4_safi_community3_cmd, "show 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 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_bgp_ipv4_safi_community, show_bgp_ipv4_safi_community4_cmd, "show 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 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_bgp_view_afi_safi_community_all, show_bgp_view_afi_safi_community_all_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") { int afi; int safi; struct bgp *bgp; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL); } DEFUN (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\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") { int afi; int safi; afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi); } ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community2_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\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") ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community3_cmd, "show bgp view WORD (ipv4|ipv6) (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 BGP_STR "BGP view\n" "View name\n" "Address family\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") ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community4_cmd, "show bgp view WORD (ipv4|ipv6) (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 BGP_STR "BGP view\n" "View name\n" "Address family\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") DEFUN (show_bgp_ipv4_community_exact, show_bgp_ipv4_community_exact_cmd, "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR IP_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, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } ALIAS (show_bgp_ipv4_community_exact, show_bgp_ipv4_community2_exact_cmd, "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR IP_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_ipv4_community_exact, show_bgp_ipv4_community3_exact_cmd, "show bgp ipv4 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 IP_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_ipv4_community_exact, show_bgp_ipv4_community4_exact_cmd, "show bgp ipv4 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 IP_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_bgp_ipv4_safi_community4_exact, show_bgp_ipv4_safi_community_exact_cmd, "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_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, NULL, argc, argv, 1, AFI_IP, SAFI_MULTICAST); return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } ALIAS (show_bgp_ipv4_safi_community4_exact, show_bgp_ipv4_safi_community2_exact_cmd, "show 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 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_bgp_ipv4_safi_community4_exact, show_bgp_ipv4_safi_community3_exact_cmd, "show 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 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_bgp_ipv4_safi_community4_exact, show_bgp_ipv4_safi_community4_exact_cmd, "show 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 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") DEFUN (show_bgp_ipv6_safi_community, show_bgp_ipv6_safi_community_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_community (vty, NULL, argc-1, argv+1, 0, AFI_IP6, safi); } ALIAS (show_bgp_ipv6_safi_community, show_bgp_ipv6_safi_community2_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\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_bgp_ipv6_safi_community, show_bgp_ipv6_safi_community3_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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_bgp_ipv6_safi_community, show_bgp_ipv6_safi_community4_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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_bgp_ipv6_safi_community_exact, show_bgp_ipv6_safi_community_exact_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_community (vty, NULL, argc-1, argv+1, 1, AFI_IP6, safi); } ALIAS (show_bgp_community_exact, show_bgp_ipv6_safi_community2_exact_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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_bgp_community_exact, show_bgp_ipv6_safi_community3_exact_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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_bgp_community_exact, show_bgp_ipv6_safi_community4_exact_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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") static int bgp_show_community_list (struct vty *vty, const char *com, int exact, afi_t afi, safi_t 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; } return bgp_show (vty, NULL, afi, safi, (exact ? bgp_show_type_community_list_exact : bgp_show_type_community_list), 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); } 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); } DEFUN (show_bgp_ipv4_community_list, show_bgp_ipv4_community_list_cmd, "show bgp ipv4 community-list (<1-500>|WORD)", SHOW_STR BGP_STR IP_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_bgp_ipv4_safi_community_list, show_bgp_ipv4_safi_community_list_cmd, "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", SHOW_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_bgp_ipv4_community_list_exact, show_bgp_ipv4_community_list_exact_cmd, "show bgp ipv4 community-list (<1-500>|WORD) exact-match", SHOW_STR BGP_STR IP_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_bgp_ipv4_safi_community_list_exact, show_bgp_ipv4_safi_community_list_exact_cmd, "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", SHOW_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); } DEFUN (show_bgp_ipv6_safi_community_list, show_bgp_ipv6_safi_community_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_community_list (vty, argv[1], 0, AFI_IP6, safi); } DEFUN (show_bgp_ipv6_safi_community_list_exact, show_bgp_ipv6_safi_community_list_exact_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD) exact-match", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_community_list (vty, argv[1], 1, AFI_IP6, safi); } /* * Large Community show commands. */ DEFUN (show_bgp_afi_lcommunity_all, show_bgp_afi_lcommunity_all_cmd, "show bgp (ipv4|ipv6) large-community", SHOW_STR BGP_STR "Address family\n" "Address family\n" "Display routes matching the large-communities\n") { afi_t afi; safi_t safi = SAFI_UNICAST; if (bgp_parse_afi(argv[0], &afi)) { vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, safi, bgp_show_type_lcommunity_all, NULL); } static int bgp_show_lcommunity (struct vty *vty, const char *view_name, int argc, const char **argv, afi_t afi, safi_t safi) { struct lcommunity *lcom; struct buffer *b; struct bgp *bgp; int i; char *str; int first = 0; /* 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; } } 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); lcom = lcommunity_str2com (str); XFREE (MTYPE_TMP, str); if (! lcom) { vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom); } DEFUN (show_ip_bgp_lcommunity, show_ip_bgp_lcommunity_cmd, "show ip bgp large-community (AA:BB:CC)", SHOW_STR IP_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n") { return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_lcommunity, show_ip_bgp_lcommunity2_cmd, "show ip bgp large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR IP_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") ALIAS (show_ip_bgp_lcommunity, show_ip_bgp_lcommunity3_cmd, "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR IP_STR BGP_STR "Display routes matching the large-communities\n" "largecommunity number\n" "largecommunity number\n" "largecommunity number\n") ALIAS (show_ip_bgp_lcommunity, show_ip_bgp_lcommunity4_cmd, "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR IP_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFUN (show_ip_bgp_ipv4_lcommunity, show_ip_bgp_ipv4_lcommunity_cmd, "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_MULTICAST); return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_ipv4_lcommunity, show_ip_bgp_ipv4_lcommunity2_cmd, "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") ALIAS (show_ip_bgp_ipv4_lcommunity, show_ip_bgp_ipv4_lcommunity3_cmd, "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") ALIAS (show_ip_bgp_ipv4_lcommunity, show_ip_bgp_ipv4_lcommunity4_cmd, "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFUN (show_bgp_lcommunity, show_bgp_lcommunity_cmd, "show bgp large-community (AA:BB:CC)", SHOW_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n") { return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_lcommunity, show_bgp_ipv6_lcommunity_cmd, "show bgp ipv6 large-community (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the large-communities\n" "large-community number\n") ALIAS (show_bgp_lcommunity, show_bgp_lcommunity2_cmd, "show bgp large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_lcommunity, show_bgp_ipv6_lcommunity2_cmd, "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_lcommunity, show_bgp_lcommunity3_cmd, "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_lcommunity, show_bgp_ipv6_lcommunity3_cmd, "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_lcommunity, show_bgp_lcommunity4_cmd, "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_lcommunity, show_bgp_ipv6_lcommunity4_cmd, "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") /* old command */ DEFUN (show_ipv6_bgp_lcommunity, show_ipv6_bgp_lcommunity_cmd, "show ipv6 bgp large-community (AA:BB:CC)", SHOW_STR IPV6_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n") { return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_UNICAST); } /* old command */ ALIAS (show_ipv6_bgp_lcommunity, show_ipv6_bgp_lcommunity2_cmd, "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR IPV6_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") /* old command */ ALIAS (show_ipv6_bgp_lcommunity, show_ipv6_bgp_lcommunity3_cmd, "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR IPV6_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") /* old command */ ALIAS (show_ipv6_bgp_lcommunity, show_ipv6_bgp_lcommunity4_cmd, "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR IPV6_STR BGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") /* old command */ DEFUN (show_ipv6_mbgp_lcommunity, show_ipv6_mbgp_lcommunity_cmd, "show ipv6 mbgp large-community (AA:BB:CC)", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the large-communities\n" "large-community number\n") { return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_MULTICAST); } /* old command */ ALIAS (show_ipv6_mbgp_lcommunity, show_ipv6_mbgp_lcommunity2_cmd, "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") /* old command */ ALIAS (show_ipv6_mbgp_lcommunity, show_ipv6_mbgp_lcommunity3_cmd, "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") /* old command */ ALIAS (show_ipv6_mbgp_lcommunity, show_ipv6_mbgp_lcommunity4_cmd, "show ipv6 mbgp laarge-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFUN (show_bgp_ipv4_lcommunity, show_bgp_ipv4_lcommunity_cmd, "show bgp ipv4 large-community (AA:BB:CC)", SHOW_STR BGP_STR IP_STR "Display routes matching the large-communities\n" "large-community number\n") { return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST); } ALIAS (show_bgp_ipv4_lcommunity, show_bgp_ipv4_lcommunity2_cmd, "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR IP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_ipv4_lcommunity, show_bgp_ipv4_lcommunity3_cmd, "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR IP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_ipv4_lcommunity, show_bgp_ipv4_lcommunity4_cmd, "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR IP_STR "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFUN (show_bgp_ipv4_safi_lcommunity, show_bgp_ipv4_safi_lcommunity_cmd, "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_MULTICAST); return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST); } ALIAS (show_bgp_ipv4_safi_lcommunity, show_bgp_ipv4_safi_lcommunity2_cmd, "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_ipv4_safi_lcommunity, show_bgp_ipv4_safi_lcommunity3_cmd, "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_ipv4_safi_lcommunity, show_bgp_ipv4_safi_lcommunity4_cmd, "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFUN (show_bgp_view_afi_safi_lcommunity_all, show_bgp_view_afi_safi_lcommunity_all_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n") { int afi; int safi; struct bgp *bgp; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL); } DEFUN (show_bgp_view_afi_safi_lcommunity, show_bgp_view_afi_safi_lcommunity_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n") { int afi; int safi; afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_lcommunity (vty, argv[0], argc-3, &argv[3], afi, safi); } ALIAS (show_bgp_view_afi_safi_lcommunity, show_bgp_view_afi_safi_lcommunity2_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_view_afi_safi_lcommunity, show_bgp_view_afi_safi_lcommunity3_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_view_afi_safi_lcommunity, show_bgp_view_afi_safi_lcommunity4_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFUN (show_bgp_ipv6_safi_lcommunity, show_bgp_ipv6_safi_lcommunity_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community AA:BB:CC", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_lcommunity (vty, NULL, argc-1, argv+1, AFI_IP6, safi); } ALIAS (show_bgp_ipv6_safi_lcommunity, show_bgp_ipv6_safi_lcommunity2_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_ipv6_safi_lcommunity, show_bgp_ipv6_safi_lcommunity3_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") ALIAS (show_bgp_ipv6_safi_lcommunity, show_bgp_ipv6_safi_lcommunity4_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") static int bgp_show_lcommunity_list (struct vty *vty, const char *lcom, afi_t afi, safi_t safi) { struct community_list *list; list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER); if (list == NULL) { vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom, VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, safi, bgp_show_type_lcommunity_list, list); } DEFUN (show_ip_bgp_lcommunity_list, show_ip_bgp_lcommunity_list_cmd, "show ip bgp large-community-list (<1-500>|WORD)", SHOW_STR IP_STR BGP_STR "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") { return bgp_show_lcommunity_list (vty, argv[0], AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_lcommunity_list, show_ip_bgp_ipv4_lcommunity_list_cmd, "show ip bgp ipv4 (unicast|multicast) large-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 large-community-list\n" "large-community-list number\n" "large-community-list name\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_MULTICAST); return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_UNICAST); } DEFUN (show_bgp_lcommunity_list, show_bgp_lcommunity_list_cmd, "show bgp large-community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") { return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_lcommunity_list, show_bgp_ipv6_lcommunity_list_cmd, "show bgp ipv6 large-community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") /* old command */ DEFUN (show_ipv6_bgp_lcommunity_list, show_ipv6_bgp_lcommunity_list_cmd, "show ipv6 bgp large-community-list WORD", SHOW_STR IPV6_STR BGP_STR "Display routes matching the large-community-list\n" "large-community-list name\n") { return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_mbgp_lcommunity_list, show_ipv6_mbgp_lcommunity_list_cmd, "show ipv6 mbgp large-community-list WORD", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the large-community-list\n" "large-community-list name\n") { return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST); } DEFUN (show_bgp_ipv4_lcommunity_list, show_bgp_ipv4_lcommunity_list_cmd, "show bgp ipv4 large-community-list (<1-500>|WORD)", SHOW_STR BGP_STR IP_STR "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") { return bgp_show_lcommunity_list (vty, argv[0], AFI_IP, SAFI_UNICAST); } DEFUN (show_bgp_ipv4_safi_lcommunity_list, show_bgp_ipv4_safi_lcommunity_list_cmd, "show bgp ipv4 (unicast|multicast) large-community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_MULTICAST); return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_UNICAST); } DEFUN (show_bgp_ipv6_safi_lcommunity_list, show_bgp_ipv6_safi_lcommunity_list_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_lcommunity_list (vty, argv[1], AFI_IP6, safi); } static int bgp_show_prefix_longer (struct vty *vty, const 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; } ret = bgp_show (vty, NULL, afi, safi, type, p); prefix_free(p); return ret; } 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); } ALIAS (show_ip_bgp_flap_prefix_longer, show_ip_bgp_damp_flap_prefix_longer_cmd, "show ip bgp dampening flap-statistics A.B.C.D/M longer-prefixes", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") 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); } ALIAS (show_ip_bgp_flap_address, show_ip_bgp_damp_flap_address_cmd, "show ip bgp dampening flap-statistics A.B.C.D", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") 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); } ALIAS (show_ip_bgp_flap_prefix, show_ip_bgp_damp_flap_prefix_cmd, "show ip bgp dampening flap-statistics A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") 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); } /* 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); } DEFUN (show_bgp_ipv4_prefix_longer, show_bgp_ipv4_prefix_longer_cmd, "show bgp ipv4 A.B.C.D/M longer-prefixes", SHOW_STR BGP_STR IP_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_bgp_ipv4_safi_flap_prefix_longer, show_bgp_ipv4_safi_flap_prefix_longer_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M longer-prefixes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_prefix_longer); } ALIAS (show_bgp_ipv4_safi_flap_prefix_longer, show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M longer-prefixes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") DEFUN (show_bgp_ipv6_safi_flap_prefix_longer, show_bgp_ipv6_safi_flap_prefix_longer_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M longer-prefixes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, bgp_show_type_flap_prefix_longer); } ALIAS (show_bgp_ipv6_safi_flap_prefix_longer, show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M longer-prefixes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") DEFUN (show_bgp_ipv4_safi_prefix_longer, show_bgp_ipv4_safi_prefix_longer_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) A.B.C.D/M longer-prefixes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, bgp_show_type_prefix_longer); } DEFUN (show_bgp_ipv6_safi_prefix_longer, show_bgp_ipv6_safi_prefix_longer_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) X:X::X:X/M longer-prefixes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\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") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_longer (vty, argv[1], AFI_IP6, safi, bgp_show_type_prefix_longer); } DEFUN (show_bgp_ipv4_safi_flap_address, show_bgp_ipv4_safi_flap_address_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_address); } ALIAS (show_bgp_ipv4_safi_flap_address, show_bgp_ipv4_safi_damp_flap_address_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") DEFUN (show_bgp_ipv6_flap_address, show_bgp_ipv6_flap_address_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_longer (vty, argv[1], AFI_IP, safi, bgp_show_type_flap_address); } ALIAS (show_bgp_ipv6_flap_address, show_bgp_ipv6_damp_flap_address_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") DEFUN (show_bgp_ipv4_safi_flap_prefix, show_bgp_ipv4_safi_flap_prefix_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_longer (vty, argv[0], AFI_IP, safi, bgp_show_type_flap_prefix); } ALIAS (show_bgp_ipv4_safi_flap_prefix, show_bgp_ipv4_safi_damp_flap_prefix_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFUN (show_bgp_ipv6_safi_flap_prefix, show_bgp_ipv6_safi_flap_prefix_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, safi, bgp_show_type_flap_prefix); } ALIAS (show_bgp_ipv6_safi_flap_prefix, show_bgp_ipv6_safi_damp_flap_prefix_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFUN (show_bgp_ipv6_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") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_longer); } static struct peer * peer_lookup_in_view (struct vty *vty, const char *view_name, const char *ip_str) { int ret; struct bgp *bgp; struct peer *peer; union sockunion su; /* BGP structure lookup. */ if (view_name) { bgp = bgp_lookup_by_name (view_name); if (! bgp) { vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); return NULL; } } else { bgp = bgp_get_default (); if (! bgp) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return NULL; } } /* Get peer sockunion. */ ret = str2sockunion (ip_str, &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); return NULL; } /* Peer structure lookup. */ peer = peer_lookup (bgp, &su); if (! peer) { vty_out (vty, "No such neighbor%s", VTY_NEWLINE); return NULL; } return peer; } enum bgp_stats { BGP_STATS_MAXBITLEN = 0, BGP_STATS_RIB, BGP_STATS_PREFIXES, BGP_STATS_TOTPLEN, BGP_STATS_UNAGGREGATEABLE, BGP_STATS_MAX_AGGREGATEABLE, BGP_STATS_AGGREGATES, BGP_STATS_SPACE, BGP_STATS_ASPATH_COUNT, BGP_STATS_ASPATH_MAXHOPS, BGP_STATS_ASPATH_TOTHOPS, BGP_STATS_ASPATH_MAXSIZE, BGP_STATS_ASPATH_TOTSIZE, BGP_STATS_ASN_HIGHEST, BGP_STATS_MAX, }; static const char *table_stats_strs[] = { [BGP_STATS_PREFIXES] = "Total Prefixes", [BGP_STATS_TOTPLEN] = "Average prefix length", [BGP_STATS_RIB] = "Total Advertisements", [BGP_STATS_UNAGGREGATEABLE] = "Unaggregateable prefixes", [BGP_STATS_MAX_AGGREGATEABLE] = "Maximum aggregateable prefixes", [BGP_STATS_AGGREGATES] = "BGP Aggregate advertisements", [BGP_STATS_SPACE] = "Address space advertised", [BGP_STATS_ASPATH_COUNT] = "Advertisements with paths", [BGP_STATS_ASPATH_MAXHOPS] = "Longest AS-Path (hops)", [BGP_STATS_ASPATH_MAXSIZE] = "Largest AS-Path (bytes)", [BGP_STATS_ASPATH_TOTHOPS] = "Average AS-Path length (hops)", [BGP_STATS_ASPATH_TOTSIZE] = "Average AS-Path size (bytes)", [BGP_STATS_ASN_HIGHEST] = "Highest public ASN", [BGP_STATS_MAX] = NULL, }; struct bgp_table_stats { struct bgp_table *table; unsigned long long counts[BGP_STATS_MAX]; }; #if 0 #define TALLY_SIGFIG 100000 static unsigned long ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval) { unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG); unsigned long res = (newtot * TALLY_SIGFIG) / count; unsigned long ret = newtot / count; if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2)) return ret + 1; else return ret; } #endif static int bgp_table_stats_walker (struct thread *t) { struct bgp_node *rn; struct bgp_node *top; struct bgp_table_stats *ts = THREAD_ARG (t); unsigned int space = 0; if (!(top = bgp_table_top (ts->table))) return 0; switch (top->p.family) { case AF_INET: space = IPV4_MAX_BITLEN; break; case AF_INET6: space = IPV6_MAX_BITLEN; break; } ts->counts[BGP_STATS_MAXBITLEN] = space; for (rn = top; rn; rn = bgp_route_next (rn)) { struct bgp_info *ri; struct bgp_node *prn = bgp_node_parent_nolock (rn); unsigned int rinum = 0; if (rn == top) continue; if (!rn->info) continue; ts->counts[BGP_STATS_PREFIXES]++; ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen; #if 0 ts->counts[BGP_STATS_AVGPLEN] = ravg_tally (ts->counts[BGP_STATS_PREFIXES], ts->counts[BGP_STATS_AVGPLEN], rn->p.prefixlen); #endif /* check if the prefix is included by any other announcements */ while (prn && !prn->info) prn = bgp_node_parent_nolock (prn); if (prn == NULL || prn == top) { ts->counts[BGP_STATS_UNAGGREGATEABLE]++; /* announced address space */ if (space) ts->counts[BGP_STATS_SPACE] += 1 << (space - rn->p.prefixlen); } else if (prn->info) ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++; for (ri = rn->info; ri; ri = ri->next) { rinum++; ts->counts[BGP_STATS_RIB]++; if (ri->attr && (CHECK_FLAG (ri->attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)))) ts->counts[BGP_STATS_AGGREGATES]++; /* as-path stats */ if (ri->attr && ri->attr->aspath) { unsigned int hops = aspath_count_hops (ri->attr->aspath); unsigned int size = aspath_size (ri->attr->aspath); as_t highest = aspath_highest (ri->attr->aspath); ts->counts[BGP_STATS_ASPATH_COUNT]++; if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS]) ts->counts[BGP_STATS_ASPATH_MAXHOPS] = hops; if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE]) ts->counts[BGP_STATS_ASPATH_MAXSIZE] = size; ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops; ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size; #if 0 ts->counts[BGP_STATS_ASPATH_AVGHOPS] = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], ts->counts[BGP_STATS_ASPATH_AVGHOPS], hops); ts->counts[BGP_STATS_ASPATH_AVGSIZE] = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], ts->counts[BGP_STATS_ASPATH_AVGSIZE], size); #endif if (highest > ts->counts[BGP_STATS_ASN_HIGHEST]) ts->counts[BGP_STATS_ASN_HIGHEST] = highest; } } } return 0; } static int bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { struct bgp_table_stats ts; unsigned int i; if (!bgp->rib[afi][safi]) { vty_out (vty, "%% No RIB exists for the specified AFI(%d)/SAFI(%d) %s", afi, safi, VTY_NEWLINE); return CMD_WARNING; } memset (&ts, 0, sizeof (ts)); ts.table = bgp->rib[afi][safi]; thread_execute (bm->master, bgp_table_stats_walker, &ts, 0); vty_out (vty, "BGP %s RIB statistics%s%s", afi_safi_print (afi, safi), VTY_NEWLINE, VTY_NEWLINE); for (i = 0; i < BGP_STATS_MAX; i++) { if (!table_stats_strs[i]) continue; switch (i) { #if 0 case BGP_STATS_ASPATH_AVGHOPS: case BGP_STATS_ASPATH_AVGSIZE: case BGP_STATS_AVGPLEN: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12.2f", (float)ts.counts[i] / (float)TALLY_SIGFIG); break; #endif case BGP_STATS_ASPATH_TOTHOPS: case BGP_STATS_ASPATH_TOTSIZE: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12.2f", ts.counts[i] ? (float)ts.counts[i] / (float)ts.counts[BGP_STATS_ASPATH_COUNT] : 0); break; case BGP_STATS_TOTPLEN: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12.2f", ts.counts[i] ? (float)ts.counts[i] / (float)ts.counts[BGP_STATS_PREFIXES] : 0); break; case BGP_STATS_SPACE: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12llu%s", ts.counts[i], VTY_NEWLINE); if (ts.counts[BGP_STATS_MAXBITLEN] < 9) break; vty_out (vty, "%30s: ", "%% announced "); vty_out (vty, "%12.2f%s", 100 * (float)ts.counts[BGP_STATS_SPACE] / (float)((uint64_t)1UL << ts.counts[BGP_STATS_MAXBITLEN]), VTY_NEWLINE); vty_out (vty, "%30s: ", "/8 equivalent "); vty_out (vty, "%12.2f%s", (float)ts.counts[BGP_STATS_SPACE] / (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 8)), VTY_NEWLINE); if (ts.counts[BGP_STATS_MAXBITLEN] < 25) break; vty_out (vty, "%30s: ", "/24 equivalent "); vty_out (vty, "%12.2f", (float)ts.counts[BGP_STATS_SPACE] / (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 24))); break; default: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12llu", ts.counts[i]); } vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } static int bgp_table_stats_vty (struct vty *vty, const char *name, const char *afi_str, const char *safi_str) { struct bgp *bgp; afi_t afi; safi_t safi; if (name) bgp = bgp_lookup_by_name (name); else bgp = bgp_get_default (); if (!bgp) { vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); return CMD_WARNING; } if (strncmp (afi_str, "ipv", 3) == 0) { if (strncmp (afi_str, "ipv4", 4) == 0) afi = AFI_IP; else if (strncmp (afi_str, "ipv6", 4) == 0) afi = AFI_IP6; else { vty_out (vty, "%% Invalid address family %s%s", afi_str, VTY_NEWLINE); return CMD_WARNING; } switch (safi_str[0]) { case 'm': safi = SAFI_MULTICAST; break; case 'u': safi = SAFI_UNICAST; break; case 'v': safi = SAFI_MPLS_VPN; break; case 'e': safi = SAFI_ENCAP; break; default: vty_out (vty, "%% Invalid subsequent address family %s%s", safi_str, VTY_NEWLINE); return CMD_WARNING; } } else { vty_out (vty, "%% Invalid address family \"%s\"%s", afi_str, VTY_NEWLINE); return CMD_WARNING; } return bgp_table_stats (vty, bgp, afi, safi); } DEFUN (show_bgp_statistics, show_bgp_statistics_cmd, "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", SHOW_STR BGP_STR "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") { return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); } ALIAS (show_bgp_statistics, show_bgp_statistics_vpnv4_cmd, "show bgp (ipv4) (vpnv4) statistics", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFUN (show_bgp_statistics_view, show_bgp_statistics_view_cmd, "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", SHOW_STR BGP_STR "BGP view\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") { return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); } ALIAS (show_bgp_statistics_view, show_bgp_statistics_view_vpnv4_cmd, "show bgp view WORD (ipv4) (vpnv4) statistics", SHOW_STR BGP_STR "BGP view\n" "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") enum bgp_pcounts { PCOUNT_ADJ_IN = 0, PCOUNT_DAMPED, PCOUNT_REMOVED, PCOUNT_HISTORY, PCOUNT_STALE, PCOUNT_VALID, PCOUNT_ALL, PCOUNT_COUNTED, PCOUNT_PFCNT, /* the figure we display to users */ PCOUNT_MAX, }; static const char *pcount_strs[] = { [PCOUNT_ADJ_IN] = "Adj-in", [PCOUNT_DAMPED] = "Damped", [PCOUNT_REMOVED] = "Removed", [PCOUNT_HISTORY] = "History", [PCOUNT_STALE] = "Stale", [PCOUNT_VALID] = "Valid", [PCOUNT_ALL] = "All RIB", [PCOUNT_COUNTED] = "PfxCt counted", [PCOUNT_PFCNT] = "Useable", [PCOUNT_MAX] = NULL, }; struct peer_pcounts { unsigned int count[PCOUNT_MAX]; const struct peer *peer; const struct bgp_table *table; }; static int bgp_peer_count_walker (struct thread *t) { struct bgp_node *rn; struct peer_pcounts *pc = THREAD_ARG (t); const struct peer *peer = pc->peer; for (rn = bgp_table_top (pc->table); rn; rn = bgp_route_next (rn)) { struct bgp_adj_in *ain; struct bgp_info *ri; for (ain = rn->adj_in; ain; ain = ain->next) if (ain->peer == peer) pc->count[PCOUNT_ADJ_IN]++; for (ri = rn->info; ri; ri = ri->next) { char buf[SU_ADDRSTRLEN]; if (ri->peer != peer) continue; pc->count[PCOUNT_ALL]++; if (CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)) pc->count[PCOUNT_DAMPED]++; if (CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) pc->count[PCOUNT_HISTORY]++; if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)) pc->count[PCOUNT_REMOVED]++; if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) pc->count[PCOUNT_STALE]++; if (CHECK_FLAG (ri->flags, BGP_INFO_VALID)) pc->count[PCOUNT_VALID]++; if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) pc->count[PCOUNT_PFCNT]++; if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { pc->count[PCOUNT_COUNTED]++; if (CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) plog_warn (peer->log, "%s [pcount] %s/%d is counted but flags 0x%x", peer->host, inet_ntop(rn->p.family, &rn->p.u.prefix, buf, SU_ADDRSTRLEN), rn->p.prefixlen, ri->flags); } else { if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) plog_warn (peer->log, "%s [pcount] %s/%d not counted but flags 0x%x", peer->host, inet_ntop(rn->p.family, &rn->p.u.prefix, buf, SU_ADDRSTRLEN), rn->p.prefixlen, ri->flags); } } } return 0; } static int bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) { struct peer_pcounts pcounts = { .peer = peer }; unsigned int i; if (!peer || !peer->bgp || !peer->afc[afi][safi] || !peer->bgp->rib[afi][safi]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } memset (&pcounts, 0, sizeof(pcounts)); pcounts.peer = peer; pcounts.table = peer->bgp->rib[afi][safi]; /* in-place call via thread subsystem so as to record execution time * stats for the thread-walk (i.e. ensure this can't be blamed on * on just vty_read()). */ thread_execute (bm->master, bgp_peer_count_walker, &pcounts, 0); vty_out (vty, "Prefix counts for %s, %s%s", peer->host, afi_safi_print (afi, safi), VTY_NEWLINE); vty_out (vty, "PfxCt: %ld%s", peer->pcount[afi][safi], VTY_NEWLINE); vty_out (vty, "%sCounts from RIB table walk:%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (i = 0; i < PCOUNT_MAX; i++) vty_out (vty, "%20s: %-10d%s", pcount_strs[i], pcounts.count[i], VTY_NEWLINE); if (pcounts.count[PCOUNT_PFCNT] != peer->pcount[afi][safi]) { vty_out (vty, "%s [pcount] PfxCt drift!%s", peer->host, VTY_NEWLINE); vty_out (vty, "Please report this bug, with the above command output%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (show_ip_bgp_neighbor_prefix_counts, show_ip_bgp_neighbor_prefix_counts_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts", 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 detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); } DEFUN (show_bgp_ipv6_neighbor_prefix_counts, show_bgp_ipv6_neighbor_prefix_counts_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts", 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 detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts, show_ip_bgp_ipv4_neighbor_prefix_counts_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", 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 detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MULTICAST); return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts, show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd, "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts", 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 detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MPLS_VPN); } DEFUN (show_bgp_ipv4_safi_neighbor_prefix_counts, show_bgp_ipv4_safi_neighbor_prefix_counts_cmd, "show bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\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 detailed prefix count information\n") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP, safi); } DEFUN (show_bgp_ipv6_safi_neighbor_prefix_counts, show_bgp_ipv6_safi_neighbor_prefix_counts_cmd, "show bgp ipv6 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\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 detailed prefix count information\n") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP6, safi); } DEFUN (show_ip_bgp_encap_neighbor_prefix_counts, show_ip_bgp_encap_neighbor_prefix_counts_cmd, "show ip bgp encap all neighbors (A.B.C.D|X:X::X:X) prefix-counts", 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 detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP, SAFI_ENCAP); } static 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 = peer->bgp; 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); } static int peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int in) { 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_view_neighbor_advertised_route, show_ip_bgp_view_neighbor_advertised_route_cmd, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", 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" "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); } ALIAS (show_ip_bgp_view_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") 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 0); return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); } DEFUN (show_bgp_view_neighbor_advertised_route, show_bgp_view_neighbor_advertised_route_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_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" "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0); } DEFUN (show_bgp_view_neighbor_received_routes, show_bgp_view_neighbor_received_routes_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_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" "Display the received routes from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1); } ALIAS (show_bgp_view_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") ALIAS (show_bgp_view_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 */ ALIAS (show_bgp_view_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") /* 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 0); } DEFUN (show_ip_bgp_view_neighbor_received_routes, show_ip_bgp_view_neighbor_received_routes_cmd, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", 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" "Display the received routes from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); } ALIAS (show_ip_bgp_view_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") ALIAS (show_bgp_view_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, ret; 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) 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; } /* old command */ ALIAS (show_bgp_view_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") /* 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 1); } DEFUN (show_bgp_view_neighbor_received_prefix_filter, show_bgp_view_neighbor_received_prefix_filter_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_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" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") { char name[BUFSIZ]; union sockunion su; struct peer *peer; struct bgp *bgp; int count, ret; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (bgp, &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; } 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 1); return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); } DEFUN (show_bgp_ipv4_safi_neighbor_advertised_route, show_bgp_ipv4_safi_neighbor_advertised_route_cmd, "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "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") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP, safi, 0); } DEFUN (show_bgp_ipv6_safi_neighbor_advertised_route, show_bgp_ipv6_safi_neighbor_advertised_route_cmd, "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Address Family modifier\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") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, safi, 0); } DEFUN (show_bgp_view_ipv6_neighbor_advertised_route, show_bgp_view_ipv6_neighbor_advertised_route_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "BGP view\n" "View name\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") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0); } DEFUN (show_bgp_view_ipv6_neighbor_received_routes, show_bgp_view_ipv6_neighbor_received_routes_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR BGP_STR "BGP view\n" "View name\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") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1); } DEFUN (show_bgp_ipv4_safi_neighbor_received_routes, show_bgp_ipv4_safi_neighbor_received_routes_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\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") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP, safi, 1); } DEFUN (show_bgp_ipv6_safi_neighbor_received_routes, show_bgp_ipv6_safi_neighbor_received_routes_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\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") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, safi, 1); } DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\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 advertised routes to neighbor\n" "Display the received routes from neighbor\n") { int afi; int safi; int in; struct peer *peer; peer = peer_lookup_in_view (vty, argv[0], argv[3]); if (! peer) return CMD_WARNING; afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0; return peer_adj_routes (vty, peer, afi, safi, in); } 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, ret; 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) 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, ret; ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); 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; } ALIAS (show_bgp_view_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") DEFUN (show_bgp_ipv4_safi_neighbor_received_prefix_filter, show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR IP_STR "Address Family modifier\n" "Address Family modifier\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, ret; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; sprintf (name, "%s.%d.%d", peer->host, AFI_IP, safi); count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); if (count) { vty_out (vty, "Address family: IPv4 %s%s", safi2str(safi), VTY_NEWLINE); prefix_bgp_show_prefix_list (vty, AFI_IP, name); } return CMD_SUCCESS; } DEFUN (show_bgp_ipv6_safi_neighbor_received_prefix_filter, show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR IP_STR "Address Family modifier\n" "Address Family modifier\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, ret; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, safi); count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); if (count) { vty_out (vty, "Address family: IPv6 %s%s", safi2str(safi), VTY_NEWLINE); prefix_bgp_show_prefix_list (vty, AFI_IP6, name); } return CMD_SUCCESS; } DEFUN (show_bgp_ipv6_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") { char name[BUFSIZ]; union sockunion su; struct peer *peer; int count, ret; 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) 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; } DEFUN (show_bgp_view_ipv6_neighbor_received_prefix_filter, show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR "BGP view\n" "View name\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") { char name[BUFSIZ]; union sockunion su; struct peer *peer; struct bgp *bgp; int count, ret; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (bgp, &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; } static int bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, enum bgp_show_type type) { if (! peer || ! peer->afc[afi][safi]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, peer->bgp, afi, safi, type, &peer->su); } 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_MULTICAST, bgp_show_type_neighbor); return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, bgp_show_type_neighbor); } DEFUN (show_ip_bgp_view_rsclient, show_ip_bgp_view_rsclient_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { struct bgp_table *table; struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP][SAFI_UNICAST]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_ip_bgp_view_rsclient, show_ip_bgp_rsclient_cmd, "show ip bgp rsclient (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) DEFUN (show_bgp_view_ipv4_safi_rsclient, show_bgp_view_ipv4_safi_rsclient_cmd, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { struct bgp_table *table; struct peer *peer; safi_t safi; if (argc == 3) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP][safi]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_bgp_view_ipv4_safi_rsclient, show_bgp_ipv4_safi_rsclient_cmd, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) DEFUN (show_ip_bgp_view_rsclient_route, show_ip_bgp_view_rsclient_route_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } ALIAS (show_ip_bgp_view_rsclient_route, show_ip_bgp_rsclient_route_cmd, "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR IP_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") DEFUN (show_bgp_ipv4_safi_neighbor_flap, show_bgp_ipv4_safi_neighbor_flap_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR BGP_STR "Address Family Modifier\n" "Address Family Modifier\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 flap statistics of the routes learned from neighbor\n") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, bgp_show_type_flap_neighbor); } DEFUN (show_bgp_ipv6_safi_neighbor_flap, show_bgp_ipv6_safi_neighbor_flap_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR BGP_STR "Address Family Modifier\n" "Address Family Modifier\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 flap statistics of the routes learned from neighbor\n") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, bgp_show_type_flap_neighbor); } DEFUN (show_bgp_ipv4_safi_neighbor_damp, show_bgp_ipv4_safi_neighbor_damp_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR BGP_STR "Address Family Modifier\n" "Address Family Modifier\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 dampened routes received from neighbor\n") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, bgp_show_type_damp_neighbor); } DEFUN (show_bgp_ipv6_safi_neighbor_damp, show_bgp_ipv6_safi_neighbor_damp_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR BGP_STR "Address Family Modifier\n" "Address Family Modifier\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 dampened routes received from neighbor\n") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, bgp_show_type_damp_neighbor); } DEFUN (show_bgp_ipv4_safi_neighbor_routes, show_bgp_ipv4_safi_neighbor_routes_cmd, "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes", SHOW_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") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP, safi, bgp_show_type_neighbor); } DEFUN (show_bgp_ipv6_safi_neighbor_routes, show_bgp_ipv6_safi_neighbor_routes_cmd, "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" NEIGHBOR_ADDR_STR NEIGHBOR_ADDR_STR "Display routes learned from neighbor\n") { struct peer *peer; safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, safi, bgp_show_type_neighbor); } DEFUN (show_bgp_view_ipv4_safi_rsclient_route, show_bgp_view_ipv4_safi_rsclient_route_cmd, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; safi_t safi; /* BGP structure lookup. */ if (argc == 4) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 4) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], (argc == 4) ? argv[3] : argv[2], AFI_IP, safi, NULL, 0, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv4_safi_rsclient_route, show_bgp_ipv4_safi_rsclient_route_cmd, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix, show_bgp_view_ipv4_safi_rsclient_prefix_cmd, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") { struct bgp *bgp; struct peer *peer; safi_t safi; /* BGP structure lookup. */ if (argc == 4) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 4) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], (argc == 4) ? argv[3] : argv[2], AFI_IP, safi, NULL, 1, BGP_PATH_ALL); } DEFUN (show_ip_bgp_view_rsclient_prefix, show_ip_bgp_view_rsclient_prefix_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } ALIAS (show_ip_bgp_view_rsclient_prefix, show_ip_bgp_rsclient_prefix_cmd, "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix, show_bgp_ipv4_safi_rsclient_prefix_cmd, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") DEFUN (show_bgp_view_ipv6_neighbor_routes, show_bgp_view_ipv6_neighbor_routes_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "BGP view\n" "View name\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") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_neighbor); } DEFUN (show_bgp_view_neighbor_damp, show_bgp_view_neighbor_damp_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_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" "Display the dampened routes received from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_damp_neighbor); } DEFUN (show_bgp_view_ipv6_neighbor_damp, show_bgp_view_ipv6_neighbor_damp_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR BGP_STR "BGP view\n" "View name\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 dampened routes received from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_damp_neighbor); } DEFUN (show_bgp_view_ipv6_neighbor_flap, show_bgp_view_ipv6_neighbor_flap_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR BGP_STR "BGP view\n" "View name\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 dampened routes received from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_flap_neighbor); } DEFUN (show_bgp_view_neighbor_flap, show_bgp_view_neighbor_flap_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_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" "Display flap statistics of the routes learned from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_flap_neighbor); } ALIAS (show_bgp_view_neighbor_flap, show_bgp_neighbor_flap_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", 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 flap statistics of the routes learned from neighbor\n") ALIAS (show_bgp_view_neighbor_damp, show_bgp_neighbor_damp_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X) dampened-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 dampened routes received from neighbor\n") DEFUN (show_bgp_view_neighbor_routes, show_bgp_view_neighbor_routes_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) routes", SHOW_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" "Display routes learned from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_neighbor); } ALIAS (show_bgp_view_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") ALIAS (show_bgp_view_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 */ ALIAS (show_bgp_view_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") /* 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") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_MULTICAST, bgp_show_type_neighbor); } ALIAS (show_bgp_view_neighbor_flap, show_bgp_ipv6_neighbor_flap_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", 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 flap statistics of the routes learned from neighbor\n") ALIAS (show_bgp_view_neighbor_damp, show_bgp_ipv6_neighbor_damp_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-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 dampened routes received from neighbor\n") DEFUN (show_bgp_view_rsclient, show_bgp_view_rsclient_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { struct bgp_table *table; struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP6][SAFI_UNICAST]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_bgp_view_rsclient, show_bgp_rsclient_cmd, "show bgp rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) DEFUN (show_bgp_view_ipv4_rsclient, show_bgp_view_ipv4_rsclient_cmd, "show bgp view WORD ipv4 rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address Family\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR2) { struct bgp_table *table; struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP][SAFI_UNICAST]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } DEFUN (show_bgp_view_ipv6_rsclient, show_bgp_view_ipv6_rsclient_cmd, "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "Address Family\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR2) { struct bgp_table *table; struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP6][SAFI_UNICAST]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_bgp_view_ipv4_rsclient, show_bgp_ipv4_rsclient_cmd, "show bgp ipv4 rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Address Family\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR2) ALIAS (show_bgp_view_ipv6_rsclient, show_bgp_ipv6_rsclient_cmd, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Address Family\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR2) DEFUN (show_bgp_view_ipv6_safi_rsclient, show_bgp_view_ipv6_safi_rsclient_cmd, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { struct bgp_table *table; struct peer *peer; safi_t safi; if (argc == 3) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP6][safi]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_bgp_view_ipv6_safi_rsclient, show_bgp_ipv6_safi_rsclient_cmd, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) DEFUN (show_bgp_view_rsclient_route, show_bgp_view_rsclient_route_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } DEFUN (show_bgp_view_ipv6_rsclient_route, show_bgp_view_ipv6_rsclient_route_cmd, "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "IP6_STR" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv6_rsclient_route, show_bgp_rsclient_route_cmd, "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") ALIAS (show_bgp_view_ipv6_rsclient_route, show_bgp_ipv6_rsclient_route_cmd, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR IP6_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") DEFUN (show_bgp_view_ipv6_safi_rsclient_route, show_bgp_view_ipv6_safi_rsclient_route_cmd, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; safi_t safi; /* BGP structure lookup. */ if (argc == 4) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 4) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi], (argc == 4) ? argv[3] : argv[2], AFI_IP6, safi, NULL, 0, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv6_safi_rsclient_route, show_bgp_ipv6_safi_rsclient_route_cmd, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") DEFUN (show_bgp_view_rsclient_prefix, show_bgp_view_rsclient_prefix_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IPv6 prefix /, e.g., 3ffe::/16\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } DEFUN (show_bgp_view_ipv6_rsclient_prefix, show_bgp_view_ipv6_rsclient_prefix_cmd, "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" IP6_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IPv6 prefix /, e.g., 3ffe::/16\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv6_rsclient_prefix, show_bgp_rsclient_prefix_cmd, "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IPv6 prefix /, e.g., 3ffe::/16\n") ALIAS (show_bgp_view_ipv6_rsclient_prefix, show_bgp_ipv6_rsclient_prefix_cmd, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IPv6 prefix /, e.g., 3ffe::/16\n") DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix, show_bgp_view_ipv6_safi_rsclient_prefix_cmd, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 3ffe::/16\n") { struct bgp *bgp; struct peer *peer; safi_t safi; /* BGP structure lookup. */ if (argc == 4) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], 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; } } if (argc == 4) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi], (argc == 4) ? argv[3] : argv[2], AFI_IP6, safi, NULL, 1, BGP_PATH_ALL); } ALIAS (show_bgp_view_ipv6_safi_rsclient_prefix, show_bgp_ipv6_safi_rsclient_prefix_cmd, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 3ffe::/16\n") 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; }; static struct bgp_distance * bgp_distance_new (void) { return XCALLOC (MTYPE_BGP_DISTANCE, sizeof (struct bgp_distance)); } static void bgp_distance_free (struct bgp_distance *bdistance) { XFREE (MTYPE_BGP_DISTANCE, bdistance); } /* XXX: Ideally, this should re-announce affected routes to zebra. * See Bugzilla #949 */ static int bgp_distance_set (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix p; u_char distance; struct bgp_node *rn; struct bgp_distance *bdistance; ret = str2prefix (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; } static int bgp_distance_unset (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix p; u_char distance; struct bgp_node *rn; struct bgp_distance *bdistance; ret = str2prefix (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->distance != distance) { vty_out (vty, "Distance does not match configured%s", VTY_NEWLINE); return CMD_WARNING; } 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; } /* 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 == 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; } } #ifdef HAVE_IPV6 /* Apply BGP information to ipv6 distance method. */ u_char ipv6_bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp) { struct bgp_node *rn; struct prefix_ipv6 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_INET6) return 0; peer = rinfo->peer; if (peer->su.sa.sa_family != AF_INET6) return 0; memset (&q, 0, sizeof (struct prefix_ipv6)); q.family = AF_INET; q.prefix = peer->su.sin6.sin6_addr; q.prefixlen = IPV6_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_IP6, 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_IP6][SAFI_UNICAST], p); if (rn) { bgp_static = rn->info; bgp_unlock_node (rn); if (bgp_static->backdoor) { if (bgp->ipv6_distance_local) return bgp->ipv6_distance_local; else return ZEBRA_IBGP_DISTANCE_DEFAULT; } } if (peer_sort (peer) == BGP_PEER_EBGP) { if (bgp->ipv6_distance_ebgp) return bgp->ipv6_distance_ebgp; return ZEBRA_EBGP_DISTANCE_DEFAULT; } else { if (bgp->ipv6_distance_ibgp) return bgp->ipv6_distance_ibgp; return ZEBRA_IBGP_DISTANCE_DEFAULT; } } #endif /* HAVE_IPV6 */ 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; } #ifdef HAVE_IPV6 DEFUN (ipv6_bgp_distance, ipv6_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->ipv6_distance_ebgp = atoi (argv[0]); bgp->ipv6_distance_ibgp = atoi (argv[1]); bgp->ipv6_distance_local = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (no_ipv6_bgp_distance, no_ipv6_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->ipv6_distance_ebgp= 0; bgp->ipv6_distance_ibgp = 0; bgp->ipv6_distance_local = 0; return CMD_SUCCESS; } ALIAS (no_ipv6_bgp_distance, no_ipv6_bgp_distance2_cmd, "no distance bgp", NO_STR "Define an administrative distance\n" "BGP distance\n") DEFUN (ipv6_bgp_distance_source, ipv6_bgp_distance_source_cmd, "distance <1-255> X:X::X:X/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_ipv6_bgp_distance_source, no_ipv6_bgp_distance_source_cmd, "no distance <1-255> X:X::X:X/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 (ipv6_bgp_distance_source_access_list, ipv6_bgp_distance_source_access_list_cmd, "distance <1-255> X:X::X:X/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_ipv6_bgp_distance_source_access_list, no_ipv6_bgp_distance_source_access_list_cmd, "no distance <1-255> X:X::X:X/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; } #endif 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; if (suppress < reuse) { vty_out (vty, "Suppress value cannot be less than reuse value %s", VTY_NEWLINE); return 0; } 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, NULL); } ALIAS (show_ip_bgp_dampened_paths, show_ip_bgp_damp_dampened_paths_cmd, "show ip bgp dampening dampened-paths", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") 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, NULL); } ALIAS (show_ip_bgp_flap_statistics, show_ip_bgp_damp_flap_statistics_cmd, "show ip bgp dampening flap-statistics", SHOW_STR IP_STR BGP_STR "Display detailed information about dampening\n" "Display flap statistics of routes\n") DEFUN (show_bgp_ipv4_safi_dampened_paths, show_bgp_ipv4_safi_dampened_paths_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampened-paths", SHOW_STR BGP_STR IP_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display paths suppressed due to dampening\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, AFI_IP, safi, bgp_show_type_dampend_paths, NULL); } ALIAS (show_bgp_ipv4_safi_dampened_paths, show_bgp_ipv4_safi_damp_dampened_paths_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening dampened-paths", SHOW_STR BGP_STR IP_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") DEFUN (show_bgp_ipv6_safi_dampened_paths, show_bgp_ipv6_safi_dampened_paths_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampened-paths", SHOW_STR BGP_STR IPV6_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display paths suppressed due to dampening\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, AFI_IP6, safi, bgp_show_type_dampend_paths, NULL); } ALIAS (show_bgp_ipv6_safi_dampened_paths, show_bgp_ipv6_safi_damp_dampened_paths_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening dampened-paths", SHOW_STR BGP_STR IPV6_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") DEFUN (show_bgp_ipv4_safi_flap_statistics, show_bgp_ipv4_safi_flap_statistics_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics", SHOW_STR BGP_STR "Address Family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, AFI_IP, safi, bgp_show_type_flap_statistics, NULL); } ALIAS (show_bgp_ipv4_safi_flap_statistics, show_bgp_ipv4_safi_damp_flap_statistics_cmd, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics", SHOW_STR BGP_STR "Address Family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") DEFUN (show_bgp_ipv6_safi_flap_statistics, show_bgp_ipv6_safi_flap_statistics_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics", SHOW_STR BGP_STR "Address Family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n") { safi_t safi; if (bgp_parse_safi(argv[0], &safi)) { vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, AFI_IP6, safi, bgp_show_type_flap_statistics, NULL); } ALIAS (show_bgp_ipv6_safi_flap_statistics, show_bgp_ipv6_safi_damp_flap_statistics_cmd, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics", SHOW_STR BGP_STR "Address Family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") /* Display specified route of BGP table. */ static int bgp_clear_damp_route (struct vty *vty, const char *view_name, const 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) || (safi == SAFI_ENCAP)) { for (rn = bgp_table_top (bgp->rib[AFI_IP][safi]); 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->extra && ri->extra->damp_info) { ri_temp = ri->next; bgp_damp_info_free (ri->extra->damp_info, 1); ri = ri_temp; } else ri = ri->next; } } bgp_unlock_node (rm); } } } 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->extra && ri->extra->damp_info) { ri_temp = ri->next; bgp_damp_info_free (ri->extra->damp_info, 1); ri = ri_temp; } else ri = ri->next; } } bgp_unlock_node (rn); } } 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); } /* also used for encap safi */ static 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) || (safi == SAFI_ENCAP))) 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, afi_t afi, safi_t safi, int *write) { struct bgp_node *rn; struct bgp_distance *bdistance; if (afi == AFI_IP && safi == SAFI_UNICAST) { /* 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); } } #ifdef HAVE_IPV6 else if (afi == AFI_IP6 && safi == SAFI_UNICAST) { bgp_config_write_family_header (vty, afi, safi, write); if (bgp->ipv6_distance_ebgp && bgp->ipv6_distance_ibgp && bgp->ipv6_distance_local && (bgp->ipv6_distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT || bgp->ipv6_distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT || bgp->ipv6_distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) vty_out (vty, " distance bgp %d %d %d%s", bgp->ipv6_distance_ebgp, bgp->ipv6_distance_ibgp, bgp->ipv6_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, inet6_ntoa (rn->p.u.prefix6), rn->p.prefixlen, bdistance->access_list ? bdistance->access_list : "", VTY_NEWLINE); } } #endif /* HAVE_IPV6 */ return 0; } /* Allocate routing table structure and install commands. */ void bgp_route_init (void) { /* Init BGP distance table. */ bgp_distance_table = bgp_table_init (AFI_IP, SAFI_UNICAST); /* 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_bgp_ipv4_safi_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rd_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rd_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rd_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rd_prefix_cmd); install_element (VIEW_NODE, &show_bgp_afi_safi_view_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_route_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_cidr_only_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_cidr_only_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community2_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community3_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community4_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community2_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community3_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community4_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_exact_cmd); /* large-communities */ install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity2_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity3_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity4_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_dampened_paths_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_dampened_paths_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_dampened_paths_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_dampened_paths_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_statistics_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_statistics_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_statistics_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_statistics_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_address_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_flap_address_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_address_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_cidr_only_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_cidr_only_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); /* Restricted node: VIEW_NODE - (set of dangerous commands) */ install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_rd_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_rd_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rd_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rd_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_encap_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rd_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rd_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_exact_cmd); /* large-community */ install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_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); /* 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); install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd); install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_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_ipv6_safi_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community2_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_community_list_cmd); /* large-community */ install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd); install_element (VIEW_NODE, &show_bgp_lcommunity_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); /* Restricted: * VIEW_NODE - (set of dangerous commands) - (commands dependent on prev) */ install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); /* Statistics */ install_element (ENABLE_NODE, &show_bgp_statistics_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); 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); #ifdef HAVE_IPV6 install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance2_cmd); install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_source_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_source_cmd); install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_source_access_list_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_source_access_list_cmd); #endif /* HAVE_IPV6 */ 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); /* IPv4 Multicast Mode */ install_element (BGP_IPV4M_NODE, &bgp_damp_set_cmd); install_element (BGP_IPV4M_NODE, &bgp_damp_set2_cmd); install_element (BGP_IPV4M_NODE, &bgp_damp_set3_cmd); install_element (BGP_IPV4M_NODE, &bgp_damp_unset_cmd); install_element (BGP_IPV4M_NODE, &bgp_damp_unset2_cmd); /* Deprecated AS-Pathlimit commands */ install_element (BGP_NODE, &bgp_network_ttl_cmd); install_element (BGP_NODE, &bgp_network_mask_ttl_cmd); install_element (BGP_NODE, &bgp_network_mask_natural_ttl_cmd); install_element (BGP_NODE, &bgp_network_backdoor_ttl_cmd); install_element (BGP_NODE, &bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_mask_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_backdoor_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_ttl_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_ttl_cmd); /* old style commands */ 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_route_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_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_ipv4_prefix_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_pathtype_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_lcommunity_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_lcommunity_cmd); install_element (VIEW_NODE, &show_ip_bgp_lcommunity2_cmd); install_element (VIEW_NODE, &show_ip_bgp_lcommunity3_cmd); install_element (VIEW_NODE, &show_ip_bgp_lcommunity4_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd); install_element (VIEW_NODE, &show_ip_bgp_lcommunity_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_list_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_dampening_params_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd); install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_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_damp_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_damp_flap_filter_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_damp_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 (VIEW_NODE, &show_ip_bgp_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_pathtype_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community4_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity2_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity3_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_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_prefix_cmd); install_element (VIEW_NODE, &show_bgp_route_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_prefix_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd); install_element (VIEW_NODE, &show_bgp_regexp_cmd); install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_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_community2_cmd); install_element (VIEW_NODE, &show_bgp_community3_cmd); install_element (VIEW_NODE, &show_bgp_community4_cmd); install_element (VIEW_NODE, &show_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_cmd); install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_lcommunity_all_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_all_cmd); install_element (VIEW_NODE, &show_bgp_lcommunity_cmd); install_element (VIEW_NODE, &show_bgp_lcommunity2_cmd); install_element (VIEW_NODE, &show_bgp_lcommunity3_cmd); install_element (VIEW_NODE, &show_bgp_lcommunity4_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_list_cmd); install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_cmd); install_element (VIEW_NODE, &show_bgp_view_route_cmd); install_element (VIEW_NODE, &show_bgp_view_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); install_element (RESTRICTED_NODE, &show_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_route_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_prefix_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd); install_element (RESTRICTED_NODE, &show_bgp_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_lcommunity_cmd); install_element (RESTRICTED_NODE, &show_bgp_lcommunity2_cmd); install_element (RESTRICTED_NODE, &show_bgp_lcommunity3_cmd); install_element (RESTRICTED_NODE, &show_bgp_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); 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_lcommunity_all_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity2_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity3_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity4_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_list_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_lcommunity_all_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity2_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity3_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity4_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); /* old with name safi collision */ install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity2_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity3_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity4_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_list_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); } void bgp_route_finish (void) { bgp_table_unlock (bgp_distance_table); bgp_distance_table = NULL; } quagga-1.2.4/bgpd/bgp_route.h000066400000000000000000000221341325323223500160400ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_ROUTE_H #define _QUAGGA_BGP_ROUTE_H #include "queue.h" #include "bgp_table.h" struct bgp_nexthop_cache; /* Ancillary information to struct bgp_info, * used for uncommonly used data (aggregation, MPLS, etc.) * and lazily allocated to save memory. */ struct bgp_info_extra { /* Pointer to dampening structure. */ struct bgp_damp_info *damp_info; /* This route is suppressed with aggregation. */ int suppress; /* Nexthop reachability check. */ u_int32_t igpmetric; /* MPLS label. */ u_char tag[3]; }; struct bgp_info { /* For linked list. */ struct bgp_info *next; struct bgp_info *prev; /* For nexthop linked list */ LIST_ENTRY(bgp_info) nh_thread; /* Back pointer to the prefix node */ struct bgp_node *net; /* Back pointer to the nexthop structure */ struct bgp_nexthop_cache *nexthop; /* Peer structure. */ struct peer *peer; /* Attribute structure. */ struct attr *attr; /* Extra information */ struct bgp_info_extra *extra; /* Multipath information */ struct bgp_info_mpath *mpath; /* Uptime. */ time_t uptime; /* reference count */ int lock; /* 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) #define BGP_INFO_REMOVED (1 << 9) #define BGP_INFO_COUNTED (1 << 10) #define BGP_INFO_MULTIPATH (1 << 11) #define BGP_INFO_MULTIPATH_CHG (1 << 12) /* 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 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; /* Atomic set reference count (ie cause of pathlimit) */ u_int32_t atomic; /* BGP redistribute route-map. */ struct { char *name; struct route_map *map; } rmap; /* Route Distinguisher */ struct prefix_rd prd; /* MPLS label. */ u_char tag[3]; }; #define BGP_INFO_COUNTABLE(BI) \ (! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \ && ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED)) /* Flags which indicate a route is unuseable in some form */ #define BGP_INFO_UNUSEABLE \ (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED) /* Macro to check BGP information is alive or not. Sadly, * not equivalent to just checking previous, because of the * sense of the additional VALID flag. */ #define BGP_INFO_HOLDDOWN(BI) \ (! CHECK_FLAG ((BI)->flags, BGP_INFO_VALID) \ || CHECK_FLAG ((BI)->flags, BGP_INFO_UNUSEABLE)) #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[RMAP_IN].name) #define ROUTE_MAP_IN(F) ((F)->map[RMAP_IN].map) #define ROUTE_MAP_OUT_NAME(F) ((F)->map[RMAP_OUT].name) #define ROUTE_MAP_OUT(F) ((F)->map[RMAP_OUT].map) #define ROUTE_MAP_IMPORT_NAME(F) ((F)->map[RMAP_IMPORT].name) #define ROUTE_MAP_IMPORT(F) ((F)->map[RMAP_IMPORT].map) #define ROUTE_MAP_EXPORT_NAME(F) ((F)->map[RMAP_EXPORT].name) #define ROUTE_MAP_EXPORT(F) ((F)->map[RMAP_EXPORT].map) #define UNSUPPRESS_MAP_NAME(F) ((F)->usmap.name) #define UNSUPPRESS_MAP(F) ((F)->usmap.map) enum bgp_clear_route_type { BGP_CLEAR_ROUTE_NORMAL, BGP_CLEAR_ROUTE_MY_RSCLIENT }; enum bgp_path_type { BGP_PATH_ALL, BGP_PATH_BESTPATH, BGP_PATH_MULTIPATH }; /* Prototypes. */ extern void bgp_route_init (void); extern void bgp_route_finish (void); extern void bgp_cleanup_routes (void); extern void bgp_announce_route (struct peer *, afi_t, safi_t); extern void bgp_announce_route_all (struct peer *); extern void bgp_default_originate (struct peer *, afi_t, safi_t, int); extern void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t); extern void bgp_soft_reconfig_rsclient (struct peer *, afi_t, safi_t); extern void bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi); extern void bgp_clear_route (struct peer *, afi_t, safi_t, enum bgp_clear_route_type); extern void bgp_clear_route_all (struct peer *); extern void bgp_clear_adj_in (struct peer *, afi_t, safi_t); extern void bgp_clear_stale_route (struct peer *, afi_t, safi_t); extern struct bgp_info *bgp_info_lock (struct bgp_info *); extern struct bgp_info *bgp_info_unlock (struct bgp_info *); extern void bgp_info_add (struct bgp_node *rn, struct bgp_info *ri); extern void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri); extern struct bgp_info_extra *bgp_info_extra_get (struct bgp_info *); extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern int bgp_nlri_parse_ip (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); extern void bgp_redistribute_add (struct prefix *, const struct in_addr *, const struct in6_addr *, u_int32_t, u_char, route_tag_t); extern void bgp_redistribute_delete (struct prefix *, u_char); extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int); extern void bgp_static_delete (struct bgp *); extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *, afi_t, safi_t); extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t); extern int bgp_static_set_safi (safi_t safi, struct vty *vty, const char *, const char *, const char *, const char *); extern int bgp_static_unset_safi (safi_t safi, struct vty *, const char *, const char *, const char *); /* this is primarily for MPLS-VPN */ extern int bgp_update (struct peer *, struct prefix *, struct attr *, afi_t, safi_t, int, int, struct prefix_rd *, u_char *, int); extern int bgp_withdraw (struct peer *, struct prefix *, struct attr *, afi_t, safi_t, int, int, struct prefix_rd *, u_char *); /* for bgp_nexthop and bgp_damp */ extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); extern int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *); extern int bgp_config_write_distance (struct vty *, struct bgp *, afi_t, safi_t, int *); extern void bgp_aggregate_increment (struct bgp *, struct prefix *, struct bgp_info *, afi_t, safi_t); extern void bgp_aggregate_decrement (struct bgp *, struct prefix *, struct bgp_info *, afi_t, safi_t); extern u_char bgp_distance_apply (struct prefix *, struct bgp_info *, struct bgp *); extern u_char ipv6_bgp_distance_apply (struct prefix *, struct bgp_info *, struct bgp *); extern afi_t bgp_node_afi (struct vty *); extern safi_t bgp_node_safi (struct vty *); extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t); extern void bgp_peer_clear_node_queue_drain_immediate (struct peer *peer); extern void bgp_process_queues_drain_immediate (void); #endif /* _QUAGGA_BGP_ROUTE_H */ quagga-1.2.4/bgpd/bgp_routemap.c000066400000000000000000003515621325323223500165430ustar00rootroot00000000000000/* 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_LIBPCREPOSIX # include #else # ifdef HAVE_GNU_REGEX # include # else # include "regex-gnu.h" # endif /* HAVE_GNU_REGEX */ #endif /* HAVE_LIBPCREPOSIX */ #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" #include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_vty.h" /* Memo of route-map commands. o Cisco route-map match as-path : Done community : Done lcommunity : Done interface : Not yet ip address : Done ip next-hop : Done ip route-source : Done 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 : Done local-preference : Done set as-path prepend : Done as-path tag : Not yet automatic-tag : (This will not be implemented by bgpd) community : Done large-community : Done large-comm-list : 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 : Done weight : Done o Local extensions set ipv6 next-hop global: Done set ipv6 next-hop local : Done set as-path exclude : Done */ /* generic value manipulation to be shared in multiple rules */ #define RMAP_VALUE_SET 0 #define RMAP_VALUE_ADD 1 #define RMAP_VALUE_SUB 2 struct rmap_value { u_int8_t action; u_int8_t variable; u_int32_t value; }; static int route_value_match (struct rmap_value *rv, u_int32_t value) { if (rv->variable == 0 && value == rv->value) return RMAP_MATCH; return RMAP_NOMATCH; } static u_int32_t route_value_adjust (struct rmap_value *rv, u_int32_t current, struct peer *peer) { u_int32_t value; switch (rv->variable) { case 1: value = peer->rtt; break; default: value = rv->value; break; } switch (rv->action) { case RMAP_VALUE_ADD: if (current > UINT32_MAX-value) return UINT32_MAX; return current + value; case RMAP_VALUE_SUB: if (current <= value) return 0; return current - value; default: return value; } } static void * route_value_compile (const char *arg) { u_int8_t action = RMAP_VALUE_SET, var = 0; unsigned long larg = 0; char *endptr = NULL; struct rmap_value *rv; if (arg[0] == '+') { action = RMAP_VALUE_ADD; arg++; } else if (arg[0] == '-') { action = RMAP_VALUE_SUB; arg++; } if (all_digit(arg)) { errno = 0; larg = strtoul (arg, &endptr, 10); if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX) return NULL; } else { if (strcmp(arg, "rtt") == 0) var = 1; else return NULL; } rv = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value)); if (!rv) return NULL; rv->action = action; rv->variable = var; rv->value = larg; return rv; } static void route_value_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* generic as path object to be shared in multiple rules */ static void * route_aspath_compile (const char *arg) { struct aspath *aspath; aspath = aspath_str2aspath (arg); if (! aspath) return NULL; return aspath; } static void route_aspath_free (void *rule) { struct aspath *aspath = rule; aspath_free (aspath); } /* 'match peer (A.B.C.D|X:X::X:X)' */ /* Compares the peer specified in the 'match peer' clause with the peer received in bgp_info->peer. If it is the same, or if the peer structure received is a peer_group containing it, returns RMAP_MATCH. */ static route_map_result_t route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { union sockunion *su; union sockunion su_def = { .sin = { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY } }; struct peer_group *group; struct peer *peer; struct listnode *node, *nnode; if (type == RMAP_BGP) { su = rule; peer = ((struct bgp_info *) object)->peer; if ( ! CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT) && ! CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_EXPORT) ) return RMAP_NOMATCH; /* If su='0.0.0.0' (command 'match peer local'), and it's a NETWORK, REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH */ if (sockunion_same (su, &su_def)) { int ret; if ( CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_NETWORK) || CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE) || CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_DEFAULT)) ret = RMAP_MATCH; else ret = RMAP_NOMATCH; return ret; } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (sockunion_same (su, &peer->su)) return RMAP_MATCH; return RMAP_NOMATCH; } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (sockunion_same (su, &peer->su)) return RMAP_MATCH; } return RMAP_NOMATCH; } } return RMAP_NOMATCH; } static void * route_match_peer_compile (const char *arg) { union sockunion *su; int ret; su = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union sockunion)); ret = str2sockunion (strcmp(arg, "local") ? arg : "0.0.0.0", su); if (ret < 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, su); return NULL; } return su; } /* Free route map's compiled `ip address' value. */ static void route_match_peer_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ struct route_map_rule_cmd route_match_peer_cmd = { "peer", route_match_peer, route_match_peer_compile, route_match_peer_free }; /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return zero. */ static 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. */ static void * route_match_ip_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static 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. */ static 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. */ static void * route_match_ip_next_hop_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static 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. */ static 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. */ static void * route_match_ip_route_source_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static 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' */ static 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; } static void * route_match_ip_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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' */ static 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; } static void * route_match_ip_next_hop_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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' */ static 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; } static void * route_match_ip_route_source_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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 local-preference LOCAL-PREF' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_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) { local_pref = rule; bgp_info = object; if (bgp_info->attr->local_pref == *local_pref) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match local-preference' match statement. `arg' is local-pref value */ static void * route_match_local_pref_compile (const char *arg) { u_int32_t *local_pref; char *endptr = NULL; unsigned long tmpval; /* Locpref value shoud be integer. */ if (! all_digit (arg)) return NULL; errno = 0; tmpval = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || tmpval > UINT32_MAX) return NULL; local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); if (!local_pref) return local_pref; *local_pref = tmpval; return local_pref; } /* Free route map's compiled `match local-preference' value. */ static void route_match_local_pref_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for metric matching. */ struct route_map_rule_cmd route_match_local_pref_cmd = { "local-preference", route_match_local_pref, route_match_local_pref_compile, route_match_local_pref_free }; /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_info *bgp_info; if (type == RMAP_BGP) { rv = rule; bgp_info = object; return route_value_match(rv, bgp_info->attr->med); } return RMAP_NOMATCH; } /* Route map commands for metric matching. */ struct route_map_rule_cmd route_match_metric_cmd = { "metric", route_match_metric, route_value_compile, route_value_free, }; /* `match as-path ASPATH' */ /* Match function for as-path match. I assume given object is */ static 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. */ static void * route_match_aspath_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Compile function for as-path match. */ static 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 }; /* `match community COMMUNIY' */ struct rmap_community { char *name; int exact; }; /* Match function for community match. */ static 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. */ static void * route_match_community_compile (const 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. */ static 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 lcommunity match. */ static route_map_result_t route_match_lcommunity (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, LARGE_COMMUNITY_LIST_MASTER); if (! list) return RMAP_NOMATCH; if (bgp_info->attr->extra && lcommunity_list_match (bgp_info->attr->extra->lcommunity, list)) return RMAP_MATCH; } return RMAP_NOMATCH; } /* Compile function for community match. */ static void * route_match_lcommunity_compile (const 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); } else { rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); rcom->exact = 0; } return rcom; } /* Compile function for community match. */ static void route_match_lcommunity_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_lcommunity_cmd = { "large-community", route_match_lcommunity, route_match_lcommunity_compile, route_match_lcommunity_free }; /* Match function for extcommunity match. */ static 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; if (!bgp_info->attr->extra) return RMAP_NOMATCH; list = community_list_lookup (bgp_clist, (char *) rule, EXTCOMMUNITY_LIST_MASTER); if (! list) return RMAP_NOMATCH; if (ecommunity_list_match (bgp_info->attr->extra->ecommunity, list)) return RMAP_MATCH; } return RMAP_NOMATCH; } /* Compile function for extcommunity match. */ static void * route_match_ecommunity_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Compile function for extcommunity match. */ static 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' */ static 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; } static void * route_match_origin_compile (const 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. */ static 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 }; /* match probability { */ static route_map_result_t route_match_probability (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { long r = random(); switch (*(long *) rule) { case 0: break; case RAND_MAX: return RMAP_MATCH; default: if (r < *(long *) rule) { return RMAP_MATCH; } } return RMAP_NOMATCH; } static void * route_match_probability_compile (const char *arg) { long *lobule; unsigned perc; perc = atoi (arg); lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (long)); switch (perc) { case 0: *lobule = 0; break; case 100: *lobule = RAND_MAX; break; default: *lobule = RAND_MAX / 100 * perc; } return lobule; } static void route_match_probability_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_probability_cmd = { "probability", route_match_probability, route_match_probability_compile, route_match_probability_free }; /* } */ /* `set ip next-hop IP_ADDRESS' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; struct bgp_info *bgp_info; if (type == RMAP_BGP) { tag = rule; bgp_info = object; if (!bgp_info->attr->extra) return RMAP_NOMATCH; return ((bgp_info->attr->extra->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH); } return RMAP_NOMATCH; } /* Route map commands for tag matching. */ static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_map_rule_tag_compile, route_map_rule_tag_free, }; /* Set nexthop to object. ojbect must be pointer to struct attr. */ struct rmap_ip_nexthop_set { struct in_addr *address; int peer_address; }; static 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 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) || CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) && peer->su_remote && sockunion_family (peer->su_remote) == AF_INET) { bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_remote); 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) { bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_local); 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. */ static void * route_set_ip_nexthop_compile (const 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 = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_ip_nexthop_set)); rins->address = address; rins->peer_address = peer_address; return rins; } /* Free route map's compiled `ip nexthop' value. */ static 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. */ static route_map_result_t route_set_local_pref (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_info *bgp_info; u_int32_t locpref = 0; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ rv = rule; bgp_info = object; /* Set local preference value. */ if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) locpref = bgp_info->attr->local_pref; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); bgp_info->attr->local_pref = route_value_adjust(rv, locpref, bgp_info->peer); } return RMAP_OKAY; } /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_local_pref_cmd = { "local-preference", route_set_local_pref, route_value_compile, route_value_free, }; /* `set weight WEIGHT' */ /* Set weight. */ static route_map_result_t route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_info *bgp_info; u_int32_t weight; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ rv = rule; bgp_info = object; /* Set weight value. */ weight = route_value_adjust(rv, 0, bgp_info->peer); if (weight) (bgp_attr_extra_get (bgp_info->attr))->weight = weight; else if (bgp_info->attr->extra) bgp_info->attr->extra->weight = 0; } return RMAP_OKAY; } /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_weight_cmd = { "weight", route_set_weight, route_value_compile, route_value_free, }; /* `set metric METRIC' */ /* Set metric to attribute. */ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rmap_value *rv; struct bgp_info *bgp_info; u_int32_t med = 0; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ rv = rule; bgp_info = object; if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) med = bgp_info->attr->med; bgp_info->attr->med = route_value_adjust(rv, med, bgp_info->peer); bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); } return RMAP_OKAY; } /* Set metric rule structure. */ struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_value_compile, route_value_free, }; /* `set as-path prepend ASPATH' */ /* For AS path prepend mechanism. */ static 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) { binfo = object; if (binfo->attr->aspath->refcnt) new = aspath_dup (binfo->attr->aspath); else new = binfo->attr->aspath; if ((uintptr_t)rule > 10) { aspath = rule; aspath_prepend (aspath, new); } else { as_t as = aspath_leftmost(new); if (!as) as = binfo->peer->as; new = aspath_add_seq_n (new, as, (uintptr_t) rule); } binfo->attr->aspath = new; } return RMAP_OKAY; } static void * route_set_aspath_prepend_compile (const char *arg) { unsigned int num; if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10) return (void*)(uintptr_t)num; return route_aspath_compile(arg); } static void route_set_aspath_prepend_free (void *rule) { if ((uintptr_t)rule > 10) route_aspath_free(rule); } /* Set as-path prepend 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 as-path exclude ASn' */ /* For ASN exclude mechanism. * Iterate over ASns requested and filter them from the given AS_PATH one by one. * Make a deep copy of existing AS_PATH, but for the first ASn only. */ static route_map_result_t route_set_aspath_exclude (void *rule, struct prefix *dummy, route_map_object_t type, void *object) { struct aspath * new_path, * exclude_path; struct bgp_info *binfo; if (type == RMAP_BGP) { exclude_path = rule; binfo = object; if (binfo->attr->aspath->refcnt) new_path = aspath_dup (binfo->attr->aspath); else new_path = binfo->attr->aspath; binfo->attr->aspath = aspath_filter_exclude (new_path, exclude_path); } return RMAP_OKAY; } /* Set ASn exlude rule structure. */ struct route_map_rule_cmd route_set_aspath_exclude_cmd = { "as-path exclude", route_set_aspath_exclude, route_aspath_compile, route_aspath_free, }; /* `set community COMMUNITY' */ struct rmap_com_set { struct community *com; int additive; int none; }; /* For community set mechanism. */ static 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; /* See the longer comment down below. */ if (old && old->refcnt == 0) community_free(old); return RMAP_OKAY; } /* "additive" case. */ if (rcs->additive && old) { merge = community_merge (community_dup (old), rcs->com); /* HACK: if the old community is not intern'd, * we should free it here, or all reference to it may be lost. * Really need to cleanup attribute caching sometime. */ if (old->refcnt == 0) community_free (old); new = community_uniq_sort (merge); community_free (merge); } else new = community_dup (rcs->com); /* will be interned by caller if required */ attr->community = new; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); } return RMAP_OKAY; } /* Compile function for set community. */ static void * route_set_community_compile (const 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 = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); rcs->com = com; rcs->additive = additive; rcs->none = none; return rcs; } /* Free function for set community. */ static 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 community COMMUNITY' */ struct rmap_lcom_set { struct lcommunity *lcom; int additive; int none; }; /* For lcommunity set mechanism. */ static route_map_result_t route_set_lcommunity (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rmap_lcom_set *rcs; struct bgp_info *binfo; struct attr *attr; struct lcommunity *new = NULL; struct lcommunity *old; struct lcommunity *merge; if (type == RMAP_BGP) { rcs = rule; binfo = object; attr = binfo->attr; old = (attr->extra) ? attr->extra->lcommunity : NULL; /* "none" case. */ if (rcs->none) { attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); if (attr->extra) { attr->extra->lcommunity = NULL; } /* See the longer comment down below. */ if (old && old->refcnt == 0) lcommunity_free(&old); return RMAP_OKAY; } if (rcs->additive && old) { merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom); /* HACK: if the old large-community is not intern'd, * we should free it here, or all reference to it may be lost. * Really need to cleanup attribute caching sometime. */ if (old->refcnt == 0) lcommunity_free (&old); new = lcommunity_uniq_sort (merge); lcommunity_free (&merge); } else { new = lcommunity_dup (rcs->lcom); } /* will be interned by caller if required */ bgp_attr_extra_get (attr)->lcommunity = new; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); } return RMAP_OKAY; } /* Compile function for set community. */ static void * route_set_lcommunity_compile (const char *arg) { struct rmap_lcom_set *rcs; struct lcommunity *lcom = 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'; } lcom = lcommunity_str2com (arg); if (additive) *(sp - 1) = ' '; if (! lcom) return NULL; } rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); rcs->lcom = lcom; rcs->additive = additive; rcs->none = none; return rcs; } /* Free function for set lcommunity. */ static void route_set_lcommunity_free (void *rule) { struct rmap_lcom_set *rcs = rule; if (rcs->lcom) { lcommunity_free (&rcs->lcom); } XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); } /* Set community rule structure. */ struct route_map_rule_cmd route_set_lcommunity_cmd = { "large-community", route_set_lcommunity, route_set_lcommunity_compile, route_set_lcommunity_free, }; /* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */ /* For large community set mechanism. */ static route_map_result_t route_set_lcommunity_delete (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct community_list *list; struct lcommunity *merge; struct lcommunity *new; struct lcommunity *old; struct bgp_info *binfo; if (type == RMAP_BGP) { if (! rule) return RMAP_OKAY; binfo = object; list = community_list_lookup (bgp_clist, rule, LARGE_COMMUNITY_LIST_MASTER); old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL); if (list && old) { merge = lcommunity_list_match_delete (lcommunity_dup (old), list); new = lcommunity_uniq_sort (merge); lcommunity_free (&merge); /* HACK: if the old community is not intern'd, * we should free it here, or all reference to it may be lost. * Really need to cleanup attribute caching sometime. */ if (old->refcnt == 0) lcommunity_free (&old); if (new->size == 0) { binfo->attr->extra->lcommunity = NULL; binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); lcommunity_free (&new); } else { binfo->attr->extra->lcommunity = new; binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); } } } return RMAP_OKAY; } /* Compile function for set lcommunity. */ static void * route_set_lcommunity_delete_compile (const 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 lcommunity. */ static void route_set_lcommunity_delete_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set lcommunity rule structure. */ struct route_map_rule_cmd route_set_lcommunity_delete_cmd = { "large-comm-list", route_set_lcommunity_delete, route_set_lcommunity_delete_compile, route_set_lcommunity_delete_free, }; /* `set comm-list (<1-99>|<100-500>|WORD) delete' */ /* For community set mechanism. */ static 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 (community_dup (old), list); new = community_uniq_sort (merge); community_free (merge); /* HACK: if the old community is not intern'd, * we should free it here, or all reference to it may be lost. * Really need to cleanup attribute caching sometime. */ if (old->refcnt == 0) community_free (old); 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. */ static void * route_set_community_delete_compile (const 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. */ static 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. Used by _rt and _soo. */ static route_map_result_t route_set_ecommunity (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_attr_extra_get (bgp_info->attr))->ecommunity; if (old_ecom) { new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); /* old_ecom->refcnt = 1 => owned elsewhere, e.g. bgp_update_receive() * ->refcnt = 0 => set by a previous route-map statement */ if (!old_ecom->refcnt) ecommunity_free (&old_ecom); } else new_ecom = ecommunity_dup (ecom); /* will be intern()'d or attr_flush()'d by bgp_update_main() */ bgp_info->attr->extra->ecommunity = new_ecom; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } return RMAP_OKAY; } /* Compile function for set community. */ static void * route_set_ecommunity_rt_compile (const char *arg) { struct ecommunity *ecom; ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0); if (! ecom) return NULL; return ecommunity_intern (ecom); } /* Free function for set community. Used by _rt and _soo */ static void route_set_ecommunity_free (void *rule) { struct ecommunity *ecom = rule; ecommunity_unintern (&ecom); } /* Set community rule structure. */ struct route_map_rule_cmd route_set_ecommunity_rt_cmd = { "extcommunity rt", route_set_ecommunity, route_set_ecommunity_rt_compile, route_set_ecommunity_free, }; /* `set extcommunity soo COMMUNITY' */ /* Compile function for set community. */ static void * route_set_ecommunity_soo_compile (const char *arg) { struct ecommunity *ecom; ecom = ecommunity_str2com (arg, ECOMMUNITY_SITE_ORIGIN, 0); if (! ecom) return NULL; return ecommunity_intern (ecom); } /* Set community rule structure. */ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = { "extcommunity soo", route_set_ecommunity, route_set_ecommunity_soo_compile, route_set_ecommunity_free, }; /* `set origin ORIGIN' */ /* For origin set. */ static 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. */ static void * route_set_origin_compile (const 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. */ static void route_set_origin_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set origin 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. */ static 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. */ static void * route_set_atomic_aggregate_compile (const char *arg) { return (void *)1; } /* Compile function for atomic aggregate. */ static 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; }; static 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; struct attr_extra *ae; if (type == RMAP_BGP) { bgp_info = object; aggregator = rule; ae = bgp_attr_extra_get (bgp_info->attr); ae->aggregator_as = aggregator->as; ae->aggregator_addr = aggregator->address; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); } return RMAP_OKAY; } static void * route_set_aggregator_as_compile (const char *arg) { struct aggregator *aggregator; char as[10]; char address[20]; aggregator = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct aggregator)); sscanf (arg, "%s %s", as, address); aggregator->as = strtoul (as, NULL, 10); inet_aton (address, &aggregator->address); return aggregator; } static 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, }; /* Set tag to object. object must be pointer to struct bgp_info */ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; struct bgp_info *bgp_info; struct attr_extra *ae; if (type == RMAP_BGP) { tag = rule; bgp_info = object; ae = bgp_attr_extra_get (bgp_info->attr); /* Set tag value */ ae->tag=*tag; } return RMAP_OKAY; } /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, route_map_rule_tag_compile, route_map_rule_tag_free, }; /* `match ipv6 address IP_ACCESS_LIST' */ static 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; } static void * route_match_ipv6_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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' */ static 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 = rule; struct bgp_info *bgp_info; if (type == RMAP_BGP) { bgp_info = object; if (!bgp_info->attr->extra) return RMAP_NOMATCH; if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, addr)) return RMAP_MATCH; if (bgp_info->attr->extra->mp_nexthop_len == 32 && IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, addr)) return RMAP_MATCH; return RMAP_NOMATCH; } return RMAP_NOMATCH; } static void * route_match_ipv6_next_hop_compile (const 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; } static 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' */ static 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; } static void * route_match_ipv6_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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. */ static 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_attr_extra_get (bgp_info->attr))->mp_nexthop_global = *address; /* Set nexthop length. */ if (bgp_info->attr->extra->mp_nexthop_len == 0) bgp_info->attr->extra->mp_nexthop_len = 16; } return RMAP_OKAY; } /* Route map `ip next-hop' compile function. Given string is converted to struct in_addr structure. */ static void * route_set_ipv6_nexthop_global_compile (const 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. */ static 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. */ static 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_attr_extra_get (bgp_info->attr))->mp_nexthop_local = *address; /* Set nexthop length. */ if (bgp_info->attr->extra->mp_nexthop_len != 32) bgp_info->attr->extra->mp_nexthop_len = 32; } return RMAP_OKAY; } /* Route map `ip nexthop' compile function. Given string is converted to struct in_addr structure. */ static void * route_set_ipv6_nexthop_local_compile (const 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. */ static 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 }; /* `set ipv6 nexthop peer-address' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in6_addr peer_address; struct bgp_info *bgp_info; struct peer *peer; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ bgp_info = object; peer = bgp_info->peer; if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) || CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) && peer->su_remote && sockunion_family (peer->su_remote) == AF_INET6) { peer_address = peer->su_remote->sin6.sin6_addr; } else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) && peer->su_local && sockunion_family (peer->su_local) == AF_INET6) { peer_address = peer->su_local->sin6.sin6_addr; } if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) { /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = peer_address; /* Set nexthop length. */ if (bgp_info->attr->extra->mp_nexthop_len != 32) bgp_info->attr->extra->mp_nexthop_len = 32; } else { /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = peer_address; /* Set nexthop length. */ if (bgp_info->attr->extra->mp_nexthop_len == 0) bgp_info->attr->extra->mp_nexthop_len = 16; } } return RMAP_OKAY; } /* Route map `ip next-hop' compile function. Given string is converted to struct in_addr structure. */ static void * route_set_ipv6_nexthop_peer_compile (const char *arg) { int *rins = NULL; rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int)); *rins = 1; return rins; } /* Free route map's compiled `ip next-hop' value. */ static void route_set_ipv6_nexthop_peer_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_peer_cmd = { "ipv6 next-hop peer-address", route_set_ipv6_nexthop_peer, route_set_ipv6_nexthop_peer_compile, route_set_ipv6_nexthop_peer_free }; /* `set vpnv4 nexthop A.B.C.D' */ static 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_attr_extra_get (bgp_info->attr))->mp_nexthop_global_in = *address; (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_len = 4; } return RMAP_OKAY; } static void * route_set_vpnv4_nexthop_compile (const 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; } static 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. */ static 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_attr_extra_get (bgp_info->attr))->originator_id = *address; } return RMAP_OKAY; } /* Compile function for originator-id set. */ static void * route_set_originator_id_compile (const 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. */ static void route_set_originator_id_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set originator-id 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. */ static int bgp_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete bgp route map rule. */ static int bgp_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Add bgp route map rule. */ static int bgp_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete bgp route map rule. */ static int bgp_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% BGP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% BGP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Hook function for updating route_map assignment. */ static void bgp_route_map_update (const char *unused) { int i; afi_t afi; safi_t safi; int direct; struct listnode *node, *nnode; struct listnode *mnode, *mnnode; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct bgp_filter *filter; struct bgp_node *bn; struct bgp_static *bgp_static; if (bm->bgp == NULL) /* may be called during cleanup */ return; /* For neighbor route-map updates. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &peer->filter[afi][safi]; for (direct = RMAP_IN; direct < RMAP_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 (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &group->conf->filter[afi][safi]; for (direct = RMAP_IN; direct < RMAP_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. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { 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. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (bgp->rmap[AFI_IP][i].name) bgp->rmap[AFI_IP][i].map = route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name); if (bgp->rmap[AFI_IP6][i].name) bgp->rmap[AFI_IP6][i].map = route_map_lookup_by_name (bgp->rmap[AFI_IP6][i].name); } } } DEFUN (match_peer, match_peer_cmd, "match peer (A.B.C.D|X:X::X:X)", MATCH_STR "Match peer address\n" "IP address of peer\n" "IPv6 address of peer\n") { return bgp_route_match_add (vty, vty->index, "peer", argv[0]); } DEFUN (match_peer_local, match_peer_local_cmd, "match peer local", MATCH_STR "Match peer address\n" "Static or Redistributed routes\n") { return bgp_route_match_add (vty, vty->index, "peer", "local"); } DEFUN (no_match_peer, no_match_peer_cmd, "no match peer", NO_STR MATCH_STR "Match peer address\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "peer", NULL); return bgp_route_match_delete (vty, vty->index, "peer", argv[0]); } ALIAS (no_match_peer, no_match_peer_val_cmd, "no match peer (A.B.C.D|X:X::X:X)", NO_STR MATCH_STR "Match peer address\n" "IP address of peer\n" "IPv6 address of peer\n") ALIAS (no_match_peer, no_match_peer_local_cmd, "no match peer local", NO_STR MATCH_STR "Match peer address\n" "Static or Redistributed routes\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 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") /* match probability { */ DEFUN (match_probability, match_probability_cmd, "match probability <0-100>", MATCH_STR "Match portion of routes defined by percentage value\n" "Percentage of routes\n") { return bgp_route_match_add (vty, vty->index, "probability", argv[0]); } DEFUN (no_match_probability, no_match_probability_cmd, "no match probability", NO_STR MATCH_STR "Match portion of routes defined by percentage value\n") { return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL); } ALIAS (no_match_probability, no_match_probability_val_cmd, "no match probability <1-99>", NO_STR MATCH_STR "Match portion of routes defined by percentage value\n" "Percentage of routes\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_local_pref, match_local_pref_cmd, "match local-preference <0-4294967295>", MATCH_STR "Match local-preference of route\n" "Metric value\n") { return bgp_route_match_add (vty, vty->index, "local-preference", argv[0]); } DEFUN (no_match_local_pref, no_match_local_pref_cmd, "no match local-preference", NO_STR MATCH_STR "Match local preference of route\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "local-preference", NULL); return bgp_route_match_delete (vty, vty->index, "local-preference", argv[0]); } ALIAS (no_match_local_pref, no_match_local_pref_val_cmd, "no match local-preference <0-4294967295>", NO_STR MATCH_STR "Match local preference of route\n" "Local preference 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_lcommunity, match_lcommunity_cmd, "match large-community (<1-99>|<100-500>|WORD)", MATCH_STR "Match BGP large community list\n" "Large Community-list number (standard)\n" "Large Community-list number (expanded)\n" "Large Community-list name\n") { return bgp_route_match_add (vty, vty->index, "large-community", argv[0]); } DEFUN (no_match_lcommunity, no_match_lcommunity_cmd, "no match large-community (<1-99>|<100-500>|WORD)", NO_STR MATCH_STR "Match BGP large community list\n" "Large Community-list number (standard)\n" "Large Community-list number (expanded)\n" "Large Community-list name\n") { return bgp_route_match_delete (vty, vty->index, "large-community", NULL); } 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 (match_tag, match_tag_cmd, "match tag <1-4294967295>", MATCH_STR "Match tag of route\n" "Tag value\n") { return bgp_route_match_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_match_tag, no_match_tag_cmd, "no match tag", NO_STR MATCH_STR "Match tag of route\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "tag", NULL); return bgp_route_match_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_match_tag, no_match_tag_val_cmd, "no match tag <1-4294967295>", NO_STR MATCH_STR "Match tag of route\n" "Tag 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 bgp_route_set_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (set_ip_nexthop_peer, set_ip_nexthop_peer_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_DEPRECATED (no_set_ip_nexthop_peer, no_set_ip_nexthop_peer_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") { return bgp_route_set_delete (vty, vty->index, "ip next-hop", NULL); } DEFUN (no_set_ip_nexthop, no_set_ip_nexthop_cmd, "no set ip next-hop", NO_STR SET_STR "Next hop address\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "ip next-hop", NULL); return bgp_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") 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 metric\n") ALIAS (set_metric, set_metric_rtt_cmd, "set metric (rtt|+rtt|-rtt)", SET_STR "Metric value for destination routing protocol\n" "Assign round trip time\n" "Add round trip time\n" "Subtract round trip time\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-4294967295>", 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-4294967295>", 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 ." CMD_AS_RANGE, SET_STR "Transform 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; } ALIAS (set_aspath_prepend, set_aspath_prepend_lastas_cmd, "set as-path prepend (last-as) <1-10>", SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "Use the peer's AS-number\n" "Number of times to insert") DEFUN (no_set_aspath_prepend, no_set_aspath_prepend_cmd, "no set as-path prepend", NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n") { int ret; char *str; if (argc == 0) return bgp_route_set_delete (vty, vty->index, "as-path prepend", NULL); str = argv_concat (argv, argc, 0); ret = bgp_route_set_delete (vty, vty->index, "as-path prepend", str); XFREE (MTYPE_TMP, str); return ret; } ALIAS (no_set_aspath_prepend, no_set_aspath_prepend_val_cmd, "no set as-path prepend ." CMD_AS_RANGE, NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") DEFUN (set_aspath_exclude, set_aspath_exclude_cmd, "set as-path exclude ." CMD_AS_RANGE, SET_STR "Transform BGP AS-path attribute\n" "Exclude from 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 exclude", str); XFREE (MTYPE_TMP, str); return ret; } DEFUN (no_set_aspath_exclude, no_set_aspath_exclude_cmd, "no set as-path exclude", NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Exclude from the as-path\n") { int ret; char *str; if (argc == 0) return bgp_route_set_delete (vty, vty->index, "as-path exclude", NULL); str = argv_concat (argv, argc, 0); ret = bgp_route_set_delete (vty, vty->index, "as-path exclude", str); XFREE (MTYPE_TMP, str); return ret; } ALIAS (no_set_aspath_exclude, no_set_aspath_exclude_val_cmd, "no set as-path exclude ." CMD_AS_RANGE, NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Exclude from 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); XFREE (MTYPE_TMP, 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" "Community-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" "Community-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") DEFUN (set_lcommunity, set_lcommunity_cmd, "set large-community .AA:BB:CC", SET_STR "BGP large community attribute\n" "Large Community number in aa:bb:cc format or additive\n") { int ret; char *str; str = argv_concat (argv, argc, 0); ret = bgp_route_set_add (vty, vty->index, "large-community", str); XFREE (MTYPE_TMP, str); return ret; } DEFUN (set_lcommunity_none, set_lcommunity_none_cmd, "set large-community none", SET_STR "BGP large community attribute\n" "No large community attribute\n") { return bgp_route_set_add (vty, vty->index, "large-community", "none"); } DEFUN (no_set_lcommunity, no_set_lcommunity_cmd, "no set large-community", NO_STR SET_STR "BGP large community attribute\n" "Large community\n") { return bgp_route_set_delete (vty, vty->index, "large-community", NULL); } ALIAS (no_set_lcommunity, no_set_lcommunity_val_cmd, "no set large-community .AA:BB:CC", NO_STR SET_STR "BGP large community attribute\n" "Large community in .AA:BB:CC format or additive\n") ALIAS (no_set_lcommunity, no_set_lcommunity_none_cmd, "no set large-community none", NO_STR SET_STR "BGP community attribute\n" "No community attribute\n") DEFUN (set_lcommunity_delete, set_lcommunity_delete_cmd, "set large-comm-list (<1-99>|<100-500>|WORD) delete", SET_STR "set BGP large community list (for deletion)\n" "Large Community-list number (standard)\n" "Large Communitly-list number (expanded)\n" "Large Community-list name\n" "Delete matching large 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, "large-comm-list", str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; } DEFUN (no_set_lcommunity_delete, no_set_lcommunity_delete_cmd, "no set large-comm-list", NO_STR SET_STR "set BGP large community list (for deletion)\n") { return bgp_route_set_delete (vty, vty->index, "large-comm-list", NULL); } ALIAS (no_set_lcommunity_delete, no_set_lcommunity_delete_val_cmd, "no set large-comm-list (<1-99>|<100-500>|WORD) delete", NO_STR SET_STR "set BGP large community list (for deletion)\n" "Large Community-list number (standard)\n" "Large Communitly-list number (expanded)\n" "Large Community-list name\n" "Delete matching large 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 extended community\n" "VPN extended community\n") { int ret; char *str; str = argv_concat (argv, argc, 0); ret = bgp_route_set_add (vty, vty->index, "extcommunity rt", str); XFREE (MTYPE_TMP, str); 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 extended community\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 extended community\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") { int ret; char *str; str = argv_concat (argv, argc, 0); ret = bgp_route_set_add (vty, vty->index, "extcommunity soo", str); XFREE (MTYPE_TMP, str); 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_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 " CMD_AS_RANGE " 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 __attribute__((unused)); /* dummy for VTY_GET_INTEGER_RANGE */ struct in_addr address; char *argstr; VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); 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 __attribute__((unused)); /* dummy for VTY_GET_INTEGER_RANGE */ struct in_addr address; char *argstr; if (argv == 0) return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL); VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); 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 " CMD_AS_RANGE " 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") DEFUN (set_tag, set_tag_cmd, "set tag <1-4294967295>", SET_STR "Tag value for routing protocol\n" "Tag value\n") { return bgp_route_set_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_set_tag, no_set_tag_cmd, "no set tag", NO_STR SET_STR "Tag value for routing protocol\n") { if (argc == 0) bgp_route_set_delete(vty, vty->index, "tag", NULL); return bgp_route_set_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_set_tag, no_set_tag_val_cmd, "no set tag <1-4294967295>", NO_STR SET_STR "Tag value for routing protocol\n" "Tag value\n") 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_peer, set_ipv6_nexthop_peer_cmd, "set ipv6 next-hop peer-address", SET_STR IPV6_STR "Next hop address\n" "Use peer address (for BGP only)\n") { return bgp_route_set_add (vty, vty->index, "ipv6 next-hop peer-address", NULL); } DEFUN (no_set_ipv6_nexthop_peer, no_set_ipv6_nexthop_peer_cmd, "no set ipv6 next-hop peer-address", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" ) { return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop", 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") 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") DEFUN_DEPRECATED (set_pathlimit_ttl, set_pathlimit_ttl_cmd, "set pathlimit ttl <1-255>", SET_STR "BGP AS-Pathlimit attribute\n" "Set AS-Path Hop-count TTL\n") { return CMD_SUCCESS; } DEFUN_DEPRECATED (no_set_pathlimit_ttl, no_set_pathlimit_ttl_cmd, "no set pathlimit ttl", NO_STR SET_STR "BGP AS-Pathlimit attribute\n" "Set AS-Path Hop-count TTL\n") { return CMD_SUCCESS; } ALIAS (no_set_pathlimit_ttl, no_set_pathlimit_ttl_val_cmd, "no set pathlimit ttl <1-255>", NO_STR MATCH_STR "BGP AS-Pathlimit attribute\n" "Set AS-Path Hop-count TTL\n") DEFUN_DEPRECATED (match_pathlimit_as, match_pathlimit_as_cmd, "match pathlimit as <1-65535>", MATCH_STR "BGP AS-Pathlimit attribute\n" "Match Pathlimit AS number\n") { return CMD_SUCCESS; } DEFUN_DEPRECATED (no_match_pathlimit_as, no_match_pathlimit_as_cmd, "no match pathlimit as", NO_STR MATCH_STR "BGP AS-Pathlimit attribute\n" "Match Pathlimit AS number\n") { return CMD_SUCCESS; } ALIAS (no_match_pathlimit_as, no_match_pathlimit_as_val_cmd, "no match pathlimit as <1-65535>", NO_STR MATCH_STR "BGP AS-Pathlimit attribute\n" "Match Pathlimit ASN\n") /* Initialization of route map. */ void bgp_route_map_init (void) { 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_peer_cmd); route_map_install_match (&route_match_local_pref_cmd); 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_lcommunity_cmd); route_map_install_match (&route_match_ecommunity_cmd); route_map_install_match (&route_match_local_pref_cmd); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_origin_cmd); route_map_install_match (&route_match_probability_cmd); route_map_install_match (&route_match_tag_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_aspath_exclude_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_lcommunity_cmd); route_map_install_set (&route_set_lcommunity_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_tag_cmd); install_element (RMAP_NODE, &match_peer_cmd); install_element (RMAP_NODE, &match_peer_local_cmd); install_element (RMAP_NODE, &no_match_peer_cmd); install_element (RMAP_NODE, &no_match_peer_val_cmd); install_element (RMAP_NODE, &no_match_peer_local_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_local_pref_cmd); install_element (RMAP_NODE, &no_match_local_pref_cmd); install_element (RMAP_NODE, &no_match_local_pref_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_lcommunity_cmd); install_element (RMAP_NODE, &no_match_lcommunity_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, &match_probability_cmd); install_element (RMAP_NODE, &no_match_probability_cmd); install_element (RMAP_NODE, &no_match_probability_val_cmd); install_element (RMAP_NODE, &match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_val_cmd); install_element (RMAP_NODE, &set_ip_nexthop_cmd); install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_val_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, &set_metric_rtt_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, &set_aspath_prepend_lastas_cmd); install_element (RMAP_NODE, &set_aspath_exclude_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd); install_element (RMAP_NODE, &no_set_aspath_exclude_cmd); install_element (RMAP_NODE, &no_set_aspath_exclude_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_lcommunity_cmd); install_element (RMAP_NODE, &set_lcommunity_none_cmd); install_element (RMAP_NODE, &no_set_lcommunity_cmd); install_element (RMAP_NODE, &no_set_lcommunity_val_cmd); install_element (RMAP_NODE, &no_set_lcommunity_none_cmd); install_element (RMAP_NODE, &set_lcommunity_delete_cmd); install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd); install_element (RMAP_NODE, &no_set_lcommunity_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_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); install_element (RMAP_NODE, &set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_val_cmd); 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); route_map_install_set (&route_set_ipv6_nexthop_peer_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); install_element (RMAP_NODE, &set_ipv6_nexthop_peer_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd); /* AS-Pathlimit: functionality removed, commands kept for * compatibility. */ install_element (RMAP_NODE, &set_pathlimit_ttl_cmd); install_element (RMAP_NODE, &no_set_pathlimit_ttl_cmd); install_element (RMAP_NODE, &no_set_pathlimit_ttl_val_cmd); install_element (RMAP_NODE, &match_pathlimit_as_cmd); install_element (RMAP_NODE, &no_match_pathlimit_as_cmd); install_element (RMAP_NODE, &no_match_pathlimit_as_val_cmd); } quagga-1.2.4/bgpd/bgp_snmp.c000066400000000000000000000606621325323223500156620ustar00rootroot00000000000000/* 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 #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "command.h" #include "thread.h" #include "smux.h" #include "filter.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" #include "bgpd/bgp_snmp.h" /* BGP4-MIB described in RFC1657. */ #define BGP4MIB 1,3,6,1,2,1,15 /* BGP TRAP. */ #define BGPESTABLISHED 1 #define BGPBACKWARDTRANSITION 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 BGPPEERMINROUTEADVERTISEMENTINTERVAL 22 #define BGPPEERINUPDATEELAPSEDTIME 23 /* 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 bgp_trap_oid [] = { BGP4MIB, 0 }; /* IP address 0.0.0.0. */ static struct in_addr bgp_empty_addr = { .s_addr = 0 }; /* Hook functions. */ static u_char *bgpVersion (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgpLocalAs (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgpPeerTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgpRcvdPathAttrTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgpIdentifier (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgp4PathAttrTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); /* 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}}, {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); } static struct peer * peer_lookup_addr_ipv4 (struct in_addr *src) { struct bgp *bgp; struct peer *peer; struct listnode *node; struct in_addr addr; int ret; bgp = bgp_get_default (); if (! bgp) return NULL; for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { ret = inet_pton (AF_INET, peer->host, &addr); if (ret > 0) { if (IPV4_ADDR_SAME (&addr, src)) return peer; } } return NULL; } static struct peer * bgp_peer_lookup_next (struct in_addr *src) { struct bgp *bgp; struct peer *peer; struct listnode *node; struct in_addr *p; union sockunion su; int ret; memset (&su, 0, sizeof (union sockunion)); bgp = bgp_get_default (); if (! bgp) return NULL; for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { 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; } /* 1.3.6.1.2.1.15.3.1.x = 10 */ #define PEERTAB_NAMELEN 10 static struct peer * bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { struct peer *peer = NULL; size_t namelen = v ? v->namelen : PEERTAB_NAMELEN; int len; if (exact) { /* Check the length. */ if (*length - namelen != sizeof (struct in_addr)) return NULL; oid2in_addr (name + namelen, IN_ADDR_SIZE, addr); peer = peer_lookup_addr_ipv4 (addr); return peer; } else { len = *length - namelen; if (len > 4) len = 4; oid2in_addr (name + namelen, len, addr); peer = bgp_peer_lookup_next (addr); if (peer == NULL) return NULL; oid_copy_addr (name + namelen, addr, sizeof (struct in_addr)); *length = sizeof (struct in_addr) + namelen; return peer; } return NULL; } /* BGP write methods. */ static 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 in_addr addr; struct peer *peer; long intval; if (var_val_type != ASN_INTEGER) { return SNMP_ERR_WRONGTYPE; } if (var_val_len != sizeof (long)) { return SNMP_ERR_WRONGLENGTH; } intval = *(long *)var_val; memset (&addr, 0, sizeof (struct in_addr)); peer = bgpPeerTable_lookup (NULL, name, &length, &addr, 1); if (! peer) return SNMP_ERR_NOSUCHNAME; if (action != SNMP_MSG_INTERNAL_SET_COMMIT) return SNMP_ERR_NOERROR; zlog_info ("%s: SNMP write .%ld = %ld", peer->host, (long)name[PEERTAB_NAMELEN - 1], intval); switch (name[PEERTAB_NAMELEN - 1]) { 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 BGPPEERCONNECTRETRYINTERVAL: SET_FLAG (peer->config, PEER_CONFIG_CONNECT); peer->connect = intval; peer->v_connect = intval; 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 BGPPEERMINROUTEADVERTISEMENTINTERVAL: peer->v_routeadv = intval; break; } return SNMP_ERR_NOERROR; } static 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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return 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 (bgp_clock () - 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 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 (bgp_clock () - peer->update_time); break; default: return NULL; break; } return NULL; } static 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); } static 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; } static 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; unsigned 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; } static 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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) 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 */ return aspath_snmp_pathseg (binfo->attr->aspath, var_len); 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 */ if (binfo->attr->extra) return SNMP_INTEGER (binfo->attr->extra->aggregator_as); else return SNMP_INTEGER (0); break; case BGP4PATHATTRAGGREGATORADDR: /* 11 */ if (binfo->attr->extra) return SNMP_IPADDRESS (binfo->attr->extra->aggregator_addr); else return SNMP_INTEGER (0); 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[] = { {3, {3, 1, BGPPEERLASTERROR}}, {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_variables, sizeof bgp_variables / sizeof (struct variable), bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid), bgp_oid, sizeof bgp_oid / sizeof (oid), index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), 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_variables, sizeof bgp_variables / sizeof (struct variable), bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid), bgp_oid, sizeof bgp_oid / sizeof (oid), index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPBACKWARDTRANSITION); } void bgp_snmp_init (void) { smux_init (bm->master); REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid); } #endif /* HAVE_SNMP */ quagga-1.2.4/bgpd/bgp_snmp.h000066400000000000000000000017571325323223500156670ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_SNMP_H #define _QUAGGA_BGP_SNMP_H extern void bgp_snmp_init (void); extern void bgpTrapEstablished (struct peer *); extern void bgpTrapBackwardTransition (struct peer *); #endif /* _QUAGGA_BGP_SNMP_H */ quagga-1.2.4/bgpd/bgp_table.c000066400000000000000000000051171325323223500157660ustar00rootroot00000000000000/* 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 "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" void bgp_table_lock (struct bgp_table *rt) { rt->lock++; } void bgp_table_unlock (struct bgp_table *rt) { assert (rt->lock > 0); rt->lock--; if (rt->lock != 0) { return; } route_table_finish (rt->route_table); rt->route_table = NULL; if (rt->owner) { peer_unlock (rt->owner); rt->owner = NULL; } XFREE (MTYPE_BGP_TABLE, rt); } void bgp_table_finish (struct bgp_table **rt) { if (*rt != NULL) { bgp_table_unlock(*rt); *rt = NULL; } } /* * bgp_node_create */ static struct route_node * bgp_node_create (route_table_delegate_t *delegate, struct route_table *table) { struct bgp_node *node; node = XCALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); return bgp_node_to_rnode (node); } /* * bgp_node_destroy */ static void bgp_node_destroy (route_table_delegate_t *delegate, struct route_table *table, struct route_node *node) { struct bgp_node *bgp_node; bgp_node = bgp_node_from_rnode (node); XFREE (MTYPE_BGP_NODE, bgp_node); } /* * Function vector to customize the behavior of the route table * library for BGP route tables. */ route_table_delegate_t bgp_table_delegate = { .create_node = bgp_node_create, .destroy_node = bgp_node_destroy }; /* * bgp_table_init */ struct bgp_table * bgp_table_init (afi_t afi, safi_t safi) { struct bgp_table *rt; rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); rt->route_table = route_table_init_with_delegate (&bgp_table_delegate); /* * Set up back pointer to bgp_table. */ rt->route_table->info = rt; bgp_table_lock (rt); rt->type = BGP_TABLE_MAIN; rt->afi = afi; rt->safi = safi; return rt; } quagga-1.2.4/bgpd/bgp_table.h000066400000000000000000000147001325323223500157710ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_TABLE_H #define _QUAGGA_BGP_TABLE_H #include "table.h" typedef enum { BGP_TABLE_MAIN, BGP_TABLE_RSCLIENT, } bgp_table_t; struct bgp_table { bgp_table_t type; /* afi/safi of this table */ afi_t afi; safi_t safi; int lock; /* The owner of this 'bgp_table' structure. */ struct peer *owner; struct route_table *route_table; }; struct bgp_node { /* * CAUTION * * These fields must be the very first fields in this structure. * * @see bgp_node_to_rnode * @see bgp_node_from_rnode */ ROUTE_NODE_FIELDS struct bgp_adj_out *adj_out; struct bgp_adj_in *adj_in; struct bgp_node *prn; u_char flags; #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) #define BGP_NODE_USER_CLEAR (1 << 1) }; /* * bgp_table_iter_t * * Structure that holds state for iterating over a bgp table. */ typedef struct bgp_table_iter_t_ { struct bgp_table *table; route_table_iter_t rt_iter; } bgp_table_iter_t; extern struct bgp_table *bgp_table_init (afi_t, safi_t); extern void bgp_table_lock (struct bgp_table *); extern void bgp_table_unlock (struct bgp_table *); extern void bgp_table_finish (struct bgp_table **); /* * bgp_node_from_rnode * * Returns the bgp_node structure corresponding to a route_node. */ static inline struct bgp_node * bgp_node_from_rnode (struct route_node *rnode) { return (struct bgp_node *) rnode; } /* * bgp_node_to_rnode * * Returns the route_node structure corresponding to a bgp_node. */ static inline struct route_node * bgp_node_to_rnode (struct bgp_node *node) { return (struct route_node *) node; } /* * bgp_node_table * * Returns the bgp_table that the given node is in. */ static inline struct bgp_table * bgp_node_table (struct bgp_node *node) { return bgp_node_to_rnode (node)->table->info; } /* * bgp_node_parent_nolock * * Gets the parent node of the given node without locking it. */ static inline struct bgp_node * bgp_node_parent_nolock (struct bgp_node *node) { return bgp_node_from_rnode (node->parent); } /* * bgp_unlock_node */ static inline void bgp_unlock_node (struct bgp_node *node) { route_unlock_node (bgp_node_to_rnode (node)); } /* * bgp_table_top_nolock * * Gets the top node in the table without locking it. * * @see bgp_table_top */ static inline struct bgp_node * bgp_table_top_nolock (const struct bgp_table *const table) { return bgp_node_from_rnode (table->route_table->top); } /* * bgp_table_top */ static inline struct bgp_node * bgp_table_top (const struct bgp_table *const table) { return bgp_node_from_rnode (route_top (table->route_table)); } /* * bgp_route_next */ static inline struct bgp_node * bgp_route_next (struct bgp_node *node) { return bgp_node_from_rnode (route_next (bgp_node_to_rnode (node))); } /* * bgp_route_next_until */ static inline struct bgp_node * bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit) { struct route_node *rnode; rnode = route_next_until (bgp_node_to_rnode (node), bgp_node_to_rnode (limit)); return bgp_node_from_rnode (rnode); } /* * bgp_node_get */ static inline struct bgp_node * bgp_node_get (struct bgp_table *const table, struct prefix *p) { return bgp_node_from_rnode (route_node_get (table->route_table, p)); } /* * bgp_node_lookup */ static inline struct bgp_node * bgp_node_lookup (const struct bgp_table *const table, struct prefix *p) { return bgp_node_from_rnode (route_node_lookup (table->route_table, p)); } /* * bgp_lock_node */ static inline struct bgp_node * bgp_lock_node (struct bgp_node *node) { return bgp_node_from_rnode (route_lock_node (bgp_node_to_rnode (node))); } /* * bgp_node_match */ static inline struct bgp_node * bgp_node_match (const struct bgp_table *table, struct prefix *p) { return bgp_node_from_rnode (route_node_match (table->route_table, p)); } /* * bgp_node_match_ipv4 */ static inline struct bgp_node * bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr) { return bgp_node_from_rnode (route_node_match_ipv4 (table->route_table, addr)); } /* * bgp_node_match_ipv6 */ static inline struct bgp_node * bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr) { return bgp_node_from_rnode (route_node_match_ipv6 (table->route_table, addr)); } static inline unsigned long bgp_table_count (const struct bgp_table *const table) { return route_table_count (table->route_table); } /* * bgp_table_get_next */ static inline struct bgp_node * bgp_table_get_next (const struct bgp_table *table, struct prefix *p) { return bgp_node_from_rnode (route_table_get_next (table->route_table, p)); } /* * bgp_table_iter_init */ static inline void bgp_table_iter_init (bgp_table_iter_t * iter, struct bgp_table *table) { bgp_table_lock (table); iter->table = table; route_table_iter_init (&iter->rt_iter, table->route_table); } /* * bgp_table_iter_next */ static inline struct bgp_node * bgp_table_iter_next (bgp_table_iter_t * iter) { return bgp_node_from_rnode (route_table_iter_next (&iter->rt_iter)); } /* * bgp_table_iter_cleanup */ static inline void bgp_table_iter_cleanup (bgp_table_iter_t * iter) { route_table_iter_cleanup (&iter->rt_iter); bgp_table_unlock (iter->table); iter->table = NULL; } /* * bgp_table_iter_pause */ static inline void bgp_table_iter_pause (bgp_table_iter_t * iter) { route_table_iter_pause (&iter->rt_iter); } /* * bgp_table_iter_is_done */ static inline int bgp_table_iter_is_done (bgp_table_iter_t * iter) { return route_table_iter_is_done (&iter->rt_iter); } /* * bgp_table_iter_started */ static inline int bgp_table_iter_started (bgp_table_iter_t * iter) { return route_table_iter_started (&iter->rt_iter); } #endif /* _QUAGGA_BGP_TABLE_H */ quagga-1.2.4/bgpd/bgp_vty.c000066400000000000000000014337371325323223500155370ustar00rootroot00000000000000/* 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 "memory.h" #include "hash.h" #include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" /* Utility function to get address family from current node. */ afi_t bgp_node_afi (struct vty *vty) { afi_t afi; switch (vty->node) { case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_VPNV6_NODE: case BGP_ENCAPV6_NODE: afi = AFI_IP6; break; default: afi = AFI_IP; break; } return afi; } /* Utility function to get subsequent address family from current node. */ safi_t bgp_node_safi (struct vty *vty) { safi_t safi; switch (vty->node) { case BGP_ENCAP_NODE: case BGP_ENCAPV6_NODE: safi = SAFI_ENCAP; break; case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: safi = SAFI_MPLS_VPN; break; case BGP_IPV4M_NODE: case BGP_IPV6M_NODE: safi = SAFI_MULTICAST; break; default: safi = SAFI_UNICAST; break; } return safi; } int bgp_parse_afi(const char *str, afi_t *afi) { if (!strcmp(str, "ipv4")) { *afi = AFI_IP; return 0; } if (!strcmp(str, "ipv6")) { *afi = AFI_IP6; return 0; } return -1; } int bgp_parse_safi(const char *str, safi_t *safi) { if (!strcmp(str, "encap")) { *safi = SAFI_ENCAP; return 0; } if (!strcmp(str, "multicast")) { *safi = SAFI_MULTICAST; return 0; } if (!strcmp(str, "unicast")) { *safi = SAFI_UNICAST; return 0; } if (!strcmp(str, "vpn")) { *safi = SAFI_MPLS_VPN; return 0; } return -1; } static 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); else if (su->sa.sa_family == AF_INET6) ifp = if_lookup_by_ipv6_exact (&su->sin6.sin6_addr); if (ifp) return 1; return 0; } /* Utility function for looking up peer from VTY. */ static struct peer * peer_lookup_vty (struct vty *vty, const 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. */ static struct peer * peer_and_group_lookup_vty (struct vty *vty, const 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; } static int bgp_vty_return (struct vty *vty, int ret) { const 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; case BGP_ERR_TCPSIG_FAILED: str = "Error while applying TCP-Sig to session(s)"; break; case BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK: str = "ebgp-multihop and ttl-security cannot be configured together"; break; case BGP_ERR_NO_IBGP_WITH_TTLHACK: str = "ttl-security only allowed for EBGP peers"; 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_DEPRECATED (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 " CMD_AS_RANGE, ROUTER_STR BGP_STR AS_STR) { int ret; as_t as; struct bgp *bgp; const char *name = NULL; VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); 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; case BGP_ERR_AS_MISMATCH: vty_out (vty, "BGP is already running; AS is %u%s", as, VTY_NEWLINE); return CMD_WARNING; 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 %u%s", as, VTY_NEWLINE); return CMD_WARNING; } vty->node = BGP_NODE; vty->index = bgp; return CMD_SUCCESS; } ALIAS (router_bgp, router_bgp_view_cmd, "router bgp " CMD_AS_RANGE " 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 " CMD_AS_RANGE, NO_STR ROUTER_STR BGP_STR AS_STR) { as_t as; struct bgp *bgp; const char *name = NULL; VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); 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 " CMD_AS_RANGE " 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_static_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_static, &id)) { vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE); return CMD_WARNING; } } id.s_addr = 0; bgp_router_id_static_set (bgp, id); 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 " CMD_AS_RANGE, "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_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); 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 __attribute__((unused)); /* Dummy for VTY_GET_INTEGER_RANGE */ bgp = vty->index; if (argc == 1) VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); bgp_confederation_id_unset (bgp); return CMD_SUCCESS; } ALIAS (no_bgp_confederation_identifier, no_bgp_confederation_identifier_arg_cmd, "no bgp confederation identifier " CMD_AS_RANGE, 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 ." CMD_AS_RANGE, "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, BGP_AS4_MAX); 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 ." CMD_AS_RANGE, 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, BGP_AS4_MAX); bgp_confederation_peers_remove (bgp, as); } return CMD_SUCCESS; } /* Maximum-paths configuration */ DEFUN (bgp_maxpaths, bgp_maxpaths_cmd, "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM), "Forward packets over multiple paths\n" "Number of paths\n") { struct bgp *bgp; u_int16_t maxpaths; int ret; bgp = vty->index; VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, argv[0], 1, 255); ret = bgp_maximum_paths_set (bgp, bgp_node_afi (vty), bgp_node_safi(vty), BGP_PEER_EBGP, maxpaths); if (ret < 0) { vty_out (vty, "%% Failed to set maximum-paths %u for afi %u, safi %u%s", maxpaths, bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (bgp_maxpaths_ibgp, bgp_maxpaths_ibgp_cmd, "maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM), "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") { struct bgp *bgp; u_int16_t maxpaths; int ret; bgp = vty->index; VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, argv[0], 1, 255); ret = bgp_maximum_paths_set (bgp, bgp_node_afi (vty), bgp_node_safi(vty), BGP_PEER_IBGP, maxpaths); if (ret < 0) { vty_out (vty, "%% Failed to set maximum-paths ibgp %u for afi %u, safi %u%s", maxpaths, bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (no_bgp_maxpaths, no_bgp_maxpaths_cmd, "no maximum-paths", NO_STR "Forward packets over multiple paths\n" "Number of paths\n") { struct bgp *bgp; int ret; bgp = vty->index; ret = bgp_maximum_paths_unset (bgp, bgp_node_afi (vty), bgp_node_safi(vty), BGP_PEER_EBGP); if (ret < 0) { vty_out (vty, "%% Failed to unset maximum-paths for afi %u, safi %u%s", bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } ALIAS (no_bgp_maxpaths, no_bgp_maxpaths_arg_cmd, "no maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM), NO_STR "Forward packets over multiple paths\n" "Number of paths\n") DEFUN (no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_cmd, "no maximum-paths ibgp", NO_STR "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") { struct bgp *bgp; int ret; bgp = vty->index; ret = bgp_maximum_paths_unset (bgp, bgp_node_afi (vty), bgp_node_safi(vty), BGP_PEER_IBGP); if (ret < 0) { vty_out (vty, "%% Failed to unset maximum-paths ibgp for afi %u, safi %u%s", bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } ALIAS (no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_arg_cmd, "no maximum-paths ibgp " CMD_RANGE_STR(1, MULTIPATH_NUM), NO_STR "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") int bgp_config_write_maxpaths (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) { if (bgp->maxpaths[afi][safi].maxpaths_ebgp != BGP_DEFAULT_MAXPATHS) { bgp_config_write_family_header (vty, afi, safi, write); vty_out (vty, " maximum-paths %d%s", bgp->maxpaths[afi][safi].maxpaths_ebgp, VTY_NEWLINE); } if (bgp->maxpaths[afi][safi].maxpaths_ibgp != BGP_DEFAULT_MAXPATHS) { bgp_config_write_family_header (vty, afi, safi, write); vty_out (vty, " maximum-paths ibgp %d%s", bgp->maxpaths[afi][safi].maxpaths_ibgp, VTY_NEWLINE); } return 0; } /* 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 (bgp_graceful_restart_restart_time, bgp_graceful_restart_restart_time_cmd, "bgp graceful-restart restart-time <1-3600>", "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { struct bgp *bgp; u_int32_t restart; bgp = vty->index; if (! bgp) return CMD_WARNING; VTY_GET_INTEGER_RANGE ("restart-time", restart, argv[0], 1, 3600); bgp->restart_time = restart; 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; } DEFUN (no_bgp_graceful_restart_restart_time, no_bgp_graceful_restart_restart_time_cmd, "no bgp graceful-restart restart-time", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\n") { struct bgp *bgp; bgp = vty->index; if (! bgp) return CMD_WARNING; bgp->restart_time = BGP_DEFAULT_RESTART_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") ALIAS (no_bgp_graceful_restart_restart_time, no_bgp_graceful_restart_restart_time_val_cmd, "no bgp graceful-restart restart-time <1-3600>", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\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\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_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\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_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 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 bestpath as-path confed" configuration. */ DEFUN (bgp_bestpath_aspath_confed, bgp_bestpath_aspath_confed_cmd, "bgp bestpath as-path confed", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Compare path lengths including confederation sets & sequences in selecting a route\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_ASPATH_CONFED); return CMD_SUCCESS; } DEFUN (no_bgp_bestpath_aspath_confed, no_bgp_bestpath_aspath_confed_cmd, "no bgp bestpath as-path confed", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Compare path lengths including confederation sets & sequences in selecting a route\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_ASPATH_CONFED); return CMD_SUCCESS; } /* "bgp bestpath as-path multipath-relax" configuration. */ DEFUN (bgp_bestpath_aspath_multipath_relax, bgp_bestpath_aspath_multipath_relax_cmd, "bgp bestpath as-path multipath-relax", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Allow load sharing across routes that have different AS paths (but same length)\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX); return CMD_SUCCESS; } DEFUN (no_bgp_bestpath_aspath_multipath_relax, no_bgp_bestpath_aspath_multipath_relax_cmd, "no bgp bestpath as-path multipath-relax", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Allow load sharing across routes that have different AS paths (but same length)\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX); 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 void peer_announce_routes_if_rmap_out (struct bgp *bgp) { struct peer *peer; struct listnode *node, *nnode; struct bgp_filter *filter; afi_t afi; safi_t safi; /* Reannounce all routes to appropriate neighbors */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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_REFLECTOR_CLIENT)) { /* check if there's an out route-map on this client */ filter = &peer->filter[afi][safi]; if (ROUTE_MAP_OUT_NAME(filter)) { if (BGP_DEBUG(update, UPDATE_OUT)) zlog_debug("%s: Announcing routes again for peer %s" "(afi=%d, safi=%d", __func__, peer->host, afi, safi); bgp_announce_route_all(peer); } } } } } DEFUN (bgp_rr_allow_outbound_policy, bgp_rr_allow_outbound_policy_cmd, "bgp route-reflector allow-outbound-policy", "BGP specific commands\n" "Allow modifications made by out route-map\n" "on ibgp neighbors\n") { struct bgp *bgp; bgp = vty->index; if (!bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { bgp_flag_set(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY); peer_announce_routes_if_rmap_out(bgp); } return CMD_SUCCESS; } DEFUN (no_bgp_rr_allow_outbound_policy, no_bgp_rr_allow_outbound_policy_cmd, "no bgp route-reflector allow-outbound-policy", NO_STR "BGP specific commands\n" "Allow modifications made by out route-map\n" "on ibgp neighbors\n") { struct bgp *bgp; bgp = vty->index; if (bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { bgp_flag_unset(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY); peer_announce_routes_if_rmap_out(bgp); } return CMD_SUCCESS; } static int peer_remote_as_vty (struct vty *vty, const char *peer_str, const 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, BGP_AS4_MAX); /* 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 %u. Cannot configure remote-as for member%s", as, VTY_NEWLINE); return CMD_WARNING; case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: vty_out (vty, "%% The AS# can not be changed from %u to %s, peer-group members must be all internal or all external%s", as, as_str, VTY_NEWLINE); return CMD_WARNING; } return bgp_vty_return (vty, ret); } DEFUN (neighbor_remote_as, neighbor_remote_as_cmd, NEIGHBOR_CMD2 "remote-as " CMD_AS_RANGE, 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 " CMD_AS_RANGE, 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 " CMD_AS_RANGE, 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 " CMD_AS_RANGE, 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, 0); return bgp_vty_return (vty, ret); } DEFUN (neighbor_local_as_no_prepend, neighbor_local_as_no_prepend_cmd, NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " 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, 0); return bgp_vty_return (vty, ret); } DEFUN (neighbor_local_as_no_prepend_replace_as, neighbor_local_as_no_prepend_replace_as_cmd, NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend replace-as", 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" "Do not prepend local-as to updates from ibgp 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, 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 " CMD_AS_RANGE, 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 " CMD_AS_RANGE " 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") ALIAS (no_neighbor_local_as, no_neighbor_local_as_val3_cmd, NO_NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend replace-as", 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" "Do not prepend local-as to updates from ibgp peers\n") 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); } 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 %u 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); } static int peer_flag_modify_vty (struct vty *vty, const 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); } static int peer_flag_set_vty (struct vty *vty, const char *ip_str, u_int16_t flag) { return peer_flag_modify_vty (vty, ip_str, flag, 1); } static int peer_flag_unset_vty (struct vty *vty, const char *ip_str, u_int16_t flag) { return peer_flag_modify_vty (vty, ip_str, flag, 0); } /* neighbor passive. */ DEFUN (neighbor_passive, neighbor_passive_cmd, NEIGHBOR_CMD2 "passive", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Don't send open messages to this neighbor\n") { return peer_flag_set_vty (vty, argv[0], PEER_FLAG_PASSIVE); } DEFUN (no_neighbor_passive, no_neighbor_passive_cmd, NO_NEIGHBOR_CMD2 "passive", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Don't send open messages to this neighbor\n") { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_PASSIVE); } /* 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); } /* Deprecated neighbor capability route-refresh. */ DEFUN_DEPRECATED (neighbor_capability_route_refresh, neighbor_capability_route_refresh_cmd, NEIGHBOR_CMD2 "capability route-refresh", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Advertise capability to the peer\n" "Advertise route-refresh capability to this neighbor\n") { return CMD_SUCCESS; } DEFUN_DEPRECATED (no_neighbor_capability_route_refresh, no_neighbor_capability_route_refresh_cmd, NO_NEIGHBOR_CMD2 "capability route-refresh", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Advertise capability to the peer\n" "Advertise route-refresh capability to this neighbor\n") { return CMD_SUCCESS; } /* 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); } static int peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, u_int32_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); } static int peer_af_flag_set_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, u_int32_t flag) { return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1); } static int peer_af_flag_unset_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, u_int32_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 {all}", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Disable the next hop calculation for this neighbor\n" "Apply also to ibgp-learned routes when acting as a route reflector\n") { u_int32_t flags = PEER_FLAG_NEXTHOP_SELF, unset = 0; int rc; /* Check if "all" is specified */ if (argv[1] != NULL) flags |= PEER_FLAG_NEXTHOP_SELF_ALL; else unset |= PEER_FLAG_NEXTHOP_SELF_ALL; rc = peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); if ( rc == CMD_SUCCESS && unset ) rc = peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), unset); return rc; } DEFUN (no_neighbor_nexthop_self, no_neighbor_nexthop_self_cmd, NO_NEIGHBOR_CMD2 "next-hop-self {all}", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Disable the next hop calculation for this neighbor\n" "Apply also to ibgp-learned routes when acting as a route reflector\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF|PEER_FLAG_NEXTHOP_SELF_ALL); } /* 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|all|extended|standard|large)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" "Send Standard, Large and Extended Community attributes\n" "Send Standard, Large and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n" "Send Large 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); if (strncmp (argv[1], "l", 1) == 0) return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_LARGE_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| PEER_FLAG_SEND_LARGE_COMMUNITY)); } DEFUN (no_neighbor_send_community_type, no_neighbor_send_community_type_cmd, NO_NEIGHBOR_CMD2 "send-community (both|all|extended|standard|large)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" "Send Standard, Large and Extended Community attributes\n" "Send Standard, Large and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n" "Send Large 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); if (strncmp (argv[1], "l", 1) == 0) return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_LARGE_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| PEER_FLAG_SEND_LARGE_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); } static int peer_rsclient_set_vty (struct vty *vty, const char *peer_str, int afi, int safi) { int ret; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct listnode *node, *nnode; struct bgp_filter *pfilter; struct bgp_filter *gfilter; int locked_and_added = 0; bgp = vty->index; peer = peer_and_group_lookup_vty (vty, peer_str); if ( ! peer ) return CMD_WARNING; /* If it is already a RS-Client, don't do anything. */ if ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ) return CMD_SUCCESS; if ( ! peer_rsclient_active (peer) ) { peer = peer_lock (peer); /* rsclient peer list reference */ listnode_add_sort (bgp->rsclient, peer); locked_and_added = 1; } ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) { if (locked_and_added) { listnode_delete (bgp->rsclient, peer); peer_unlock (peer); /* rsclient peer list reference */ } return bgp_vty_return (vty, ret); } peer->rib[afi][safi] = bgp_table_init (afi, safi); peer->rib[afi][safi]->type = BGP_TABLE_RSCLIENT; /* RIB peer reference. Released when table is free'd in bgp_table_free. */ peer->rib[afi][safi]->owner = peer_lock (peer); /* Check for existing 'network' and 'redistribute' routes. */ bgp_check_local_routes_rsclient (peer, afi, safi); /* Check for routes for peers configured with 'soft-reconfiguration'. */ bgp_soft_reconfig_rsclient (peer, afi, safi); if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; gfilter = &peer->filter[afi][safi]; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { pfilter = &peer->filter[afi][safi]; /* Members of a non-RS-Client group should not be RS-Clients, as that is checked when the become part of the peer-group */ ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) return bgp_vty_return (vty, ret); /* Make peer's RIB point to group's RIB. */ peer->rib[afi][safi] = group->conf->rib[afi][safi]; /* Import policy. */ if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); if (gfilter->map[RMAP_IMPORT].name) { pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; } else { pfilter->map[RMAP_IMPORT].name = NULL; pfilter->map[RMAP_IMPORT].map =NULL; } /* Export policy. */ if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) { pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; } } } return CMD_SUCCESS; } static int peer_rsclient_unset_vty (struct vty *vty, const char *peer_str, int afi, int safi) { int ret; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct listnode *node, *nnode; bgp = vty->index; peer = peer_and_group_lookup_vty (vty, peer_str); if ( ! peer ) return CMD_WARNING; /* If it is not a RS-Client, don't do anything. */ if ( ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ) return CMD_SUCCESS; if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) return bgp_vty_return (vty, ret); peer->rib[afi][safi] = NULL; } peer = group->conf; } ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) return bgp_vty_return (vty, ret); if ( ! peer_rsclient_active (peer) ) { bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); listnode_delete (bgp->rsclient, peer); peer_unlock (peer); /* peer bgp rsclient reference */ } bgp_table_finish (&peer->rib[bgp_node_afi(vty)][bgp_node_safi(vty)]); return CMD_SUCCESS; } /* 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_rsclient_set_vty (vty, argv[0], bgp_node_afi(vty), bgp_node_safi(vty)); } 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_rsclient_unset_vty (vty, argv[0], bgp_node_afi(vty), bgp_node_safi(vty)); } DEFUN (neighbor_nexthop_local_unchanged, neighbor_nexthop_local_unchanged_cmd, NEIGHBOR_CMD2 "nexthop-local unchanged", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure treatment of outgoing link-local nexthop attribute\n" "Leave link-local nexthop unchanged for this peer\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); } DEFUN (no_neighbor_nexthop_local_unchanged, no_neighbor_nexthop_local_unchanged_cmd, NO_NEIGHBOR_CMD2 "nexthop-local unchanged", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure treatment of outgoing link-local-nexthop attribute\n" "Leave link-local nexthop unchanged for this peer\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); } 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") /* For old version Zebra compatibility. */ DEFUN_DEPRECATED (neighbor_transparent_as, neighbor_transparent_as_cmd, NEIGHBOR_CMD "transparent-as", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Do not append my AS number even peer is EBGP peer\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_AS_PATH_UNCHANGED); } DEFUN_DEPRECATED (neighbor_transparent_nexthop, neighbor_transparent_nexthop_cmd, NEIGHBOR_CMD "transparent-nexthop", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Do not change nexthop even peer is EBGP peer\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_UNCHANGED); } /* EBGP multihop configuration. */ static int peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str, const char *ttl_str) { struct peer *peer; unsigned 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); return bgp_vty_return (vty, peer_ebgp_multihop_set (peer, ttl)); } static int peer_ebgp_multihop_unset_vty (struct vty *vty, const char *ip_str) { struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; return bgp_vty_return (vty, peer_ebgp_multihop_set (peer, 0)); } /* 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") /* Enforce multihop. */ ALIAS (no_neighbor_disable_connected_check, no_neighbor_enforce_multihop_cmd, NO_NEIGHBOR_CMD2 "enforce-multihop", NO_STR 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; char *str; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; if (argc == 1) return CMD_SUCCESS; str = argv_concat(argv, argc, 1); peer_description_set (peer, str); XFREE (MTYPE_TMP, 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. */ static int peer_update_source_vty (struct vty *vty, const char *peer_str, const char *source_str) { struct peer *peer; peer = peer_and_group_lookup_vty (vty, peer_str); if (! peer) return CMD_WARNING; if (source_str) { union sockunion su; int ret = str2sockunion (source_str, &su); if (ret == 0) peer_update_source_addr_set (peer, &su); else peer_update_source_if_set (peer, source_str); } else peer_update_source_unset (peer); return CMD_SUCCESS; } #define BGP_UPDATE_SOURCE_STR "(A.B.C.D|X:X::X:X|WORD)" #define BGP_UPDATE_SOURCE_HELP_STR \ "IPv4 address\n" \ "IPv6 address\n" \ "Interface name (requires zebra to be running)\n" DEFUN (neighbor_update_source, neighbor_update_source_cmd, NEIGHBOR_CMD2 "update-source " BGP_UPDATE_SOURCE_STR, NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Source of routing updates\n" BGP_UPDATE_SOURCE_HELP_STR) { 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") { return peer_update_source_vty (vty, argv[0], NULL); } static int peer_default_originate_set_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, const 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. */ static int peer_port_vty (struct vty *vty, const char *ip_str, int afi, const 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. */ static int peer_weight_set_vty (struct vty *vty, const char *ip_str, const char *weight_str) { struct peer *peer; unsigned long 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); return bgp_vty_return (vty, peer_weight_set (peer, weight)); } static int peer_weight_unset_vty (struct vty *vty, const char *ip_str) { struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; return bgp_vty_return (vty, peer_weight_unset (peer)); } 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]); } 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]); } 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); } static int peer_timers_set_vty (struct vty *vty, const char *ip_str, const char *keep_str, const 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); } static int peer_timers_unset_vty (struct vty *vty, const 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]); } static int peer_timers_connect_set_vty (struct vty *vty, const char *ip_str, const char *time_str) { struct peer *peer; u_int32_t connect; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; VTY_GET_INTEGER_RANGE ("Connect time", connect, time_str, 0, 65535); return bgp_vty_return (vty, peer_timers_connect_set (peer, connect)); } static int peer_timers_connect_unset_vty (struct vty *vty, const char *ip_str) { struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; return bgp_vty_return (vty, peer_timers_connect_unset (peer)); } DEFUN (neighbor_timers_connect, neighbor_timers_connect_cmd, NEIGHBOR_CMD2 "timers connect <1-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") { return peer_timers_connect_set_vty (vty, argv[0], argv[1]); } DEFUN (no_neighbor_timers_connect, no_neighbor_timers_connect_cmd, NO_NEIGHBOR_CMD2 "timers connect", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP per neighbor timers\n" "BGP connect timer\n") { return peer_timers_connect_unset_vty (vty, argv[0]); } ALIAS (no_neighbor_timers_connect, no_neighbor_timers_connect_val_cmd, NO_NEIGHBOR_CMD2 "timers connect <1-65535>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") static int peer_advertise_interval_vty (struct vty *vty, const char *ip_str, const char *time_str, int set) { int ret; struct peer *peer; u_int32_t routeadv = 0; peer = peer_and_group_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 bgp_vty_return (vty, ret); } DEFUN (neighbor_advertise_interval, neighbor_advertise_interval_cmd, NEIGHBOR_CMD2 "advertisement-interval <0-600>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "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_CMD2 "advertisement-interval", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "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_CMD2 "advertisement-interval <0-600>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Minimum interval between sending BGP routing updates\n" "time in seconds\n") /* neighbor interface */ static int peer_interface_vty (struct vty *vty, const char *ip_str, const 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 bgp_vty_return (vty, ret); } 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. */ static int peer_distribute_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, const 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); } static int peer_distribute_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const 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. */ static int peer_prefix_list_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, const 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); } static int peer_prefix_list_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const 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]); } static int peer_aslist_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, const 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); } static int peer_aslist_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const 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. */ static int peer_route_map_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, const char *direct_str) { int ret; struct peer *peer; int direct = RMAP_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "in", 2) == 0) direct = RMAP_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RMAP_OUT; else if (strncmp (direct_str, "im", 2) == 0) direct = RMAP_IMPORT; else if (strncmp (direct_str, "e", 1) == 0) direct = RMAP_EXPORT; ret = peer_route_map_set (peer, afi, safi, direct, name_str); return bgp_vty_return (vty, ret); } static int peer_route_map_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *direct_str) { int ret; struct peer *peer; int direct = RMAP_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "in", 2) == 0) direct = RMAP_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RMAP_OUT; else if (strncmp (direct_str, "im", 2) == 0) direct = RMAP_IMPORT; else if (strncmp (direct_str, "e", 1) == 0) direct = RMAP_EXPORT; 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|import|export)", 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" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") { 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|import|export)", 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" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") { 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. */ static int peer_unsuppress_map_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const 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. */ static int peer_unsuppress_map_unset_vty (struct vty *vty, const 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)); } static int peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *num_str, const char *threshold_str, int warning, const 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 ("maximum 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); } static int peer_maximum_prefix_unset_vty (struct vty *vty, const 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; unsigned 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 occurrences 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); } DEFUN (neighbor_ttl_security, neighbor_ttl_security_cmd, NEIGHBOR_CMD2 "ttl-security hops <1-254>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify the maximum number of hops to the BGP peer\n") { struct peer *peer; int gtsm_hops; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; VTY_GET_INTEGER_RANGE ("", gtsm_hops, argv[1], 1, 254); return bgp_vty_return (vty, peer_ttl_security_hops_set (peer, gtsm_hops)); } DEFUN (no_neighbor_ttl_security, no_neighbor_ttl_security_cmd, NO_NEIGHBOR_CMD2 "ttl-security hops <1-254>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify the maximum number of hops to the BGP peer\n") { struct peer *peer; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; return bgp_vty_return (vty, peer_ttl_security_hops_set (peer, 0)); } /* 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, address_family_ipv6_cmd, "address-family ipv6", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_IPV6_NODE; return CMD_SUCCESS; } DEFUN (address_family_ipv6_safi, address_family_ipv6_safi_cmd, "address-family ipv6 (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_IPV6M_NODE; else vty->node = BGP_IPV6_NODE; return CMD_SUCCESS; } 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 (address_family_vpnv6, address_family_vpnv6_cmd, "address-family vpnv6", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } ALIAS (address_family_vpnv6, address_family_vpnv6_unicast_cmd, "address-family vpnv6 unicast", "Enter Address Family command mode\n" "Address family\n" "Address Family Modifier\n") DEFUN (address_family_encap, address_family_encap_cmd, "address-family encap", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_ENCAP_NODE; return CMD_SUCCESS; } ALIAS (address_family_encap, address_family_encapv4_cmd, "address-family encapv4", "Enter Address Family command mode\n" "Address family\n") DEFUN (address_family_encapv6, address_family_encapv6_cmd, "address-family encapv6", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_ENCAPV6_NODE; return CMD_SUCCESS; } DEFUN (exit_address_family, exit_address_family_cmd, "exit-address-family", "Exit from Address Family configuration mode\n") { /* should match list in command.c:config_exit */ if (vty->node == BGP_IPV4_NODE || vty->node == BGP_ENCAP_NODE || vty->node == BGP_ENCAPV6_NODE || vty->node == BGP_IPV4M_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } /* BGP clear sort. */ enum clear_sort { clear_all, clear_peer, clear_group, clear_external, clear_as }; static 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. */ static int bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, enum clear_sort sort,enum bgp_clear_type stype, const char *arg) { int ret; struct peer *peer; struct listnode *node, *nnode; /* Clear all neighbors. */ if (sort == clear_all) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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 CMD_SUCCESS; } /* 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 CMD_WARNING; } peer = peer_lookup (bgp, &su); if (! peer) { vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE); return CMD_WARNING; } 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 CMD_SUCCESS; } /* 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 CMD_WARNING; } for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (stype == BGP_CLEAR_SOFT_NONE) { ret = peer_clear (peer); continue; } if (! peer->af_group[afi][safi]) continue; ret = peer_clear_soft (peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error (vty, peer, afi, safi, ret); } return CMD_SUCCESS; } if (sort == clear_external) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->sort == 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 CMD_SUCCESS; } if (sort == clear_as) { as_t as; int find = 0; VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX); for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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 CMD_SUCCESS; } return CMD_SUCCESS; } /* Recalculate bestpath and re-advertise a prefix */ static int bgp_clear_prefix (struct vty *vty, char *view_name, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd) { int ret; struct prefix match; struct bgp_node *rn; struct bgp_node *rm; struct bgp *bgp; struct bgp_table *table; struct bgp_table *rib; /* 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); rib = bgp->rib[afi][safi]; if (safi == SAFI_MPLS_VPN) { for (rn = bgp_table_top (rib); 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 (rm->p.prefixlen == match.prefixlen) { SET_FLAG (rn->flags, BGP_NODE_USER_CLEAR); bgp_process (bgp, rm, afi, safi); } bgp_unlock_node (rm); } } } } else { if ((rn = bgp_node_match (rib, &match)) != NULL) { if (rn->p.prefixlen == match.prefixlen) { SET_FLAG (rn->flags, BGP_NODE_USER_CLEAR); bgp_process (bgp, rn, afi, safi); } bgp_unlock_node (rn); } } return CMD_SUCCESS; } static int bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi, enum clear_sort sort, enum bgp_clear_type stype, const char *arg) { 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; } } return bgp_clear (vty, bgp, afi, safi, sort, stype, arg); } 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_prefix, clear_ip_bgp_prefix_cmd, "clear ip bgp prefix A.B.C.D/M", CLEAR_STR IP_STR BGP_STR "Clear bestpath and re-advertise\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_clear_prefix (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL); } ALIAS (clear_ip_bgp_prefix, clear_bgp_prefix_cmd, "clear bgp prefix A.B.C.D/M", CLEAR_STR BGP_STR "Clear bestpath and re-advertise\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFUN (clear_ip_bgp_as, clear_ip_bgp_as_cmd, "clear ip bgp " CMD_AS_RANGE, 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 " CMD_AS_RANGE, CLEAR_STR BGP_STR "Clear peers with the AS number\n") ALIAS (clear_ip_bgp_as, clear_bgp_ipv6_as_cmd, "clear bgp ipv6 " CMD_AS_RANGE, 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_OUT_STR) { 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_all_encap_soft_out, clear_ip_bgp_all_encap_soft_out_cmd, "clear ip bgp * encap 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_ENCAP, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_all_encap_soft_out, clear_ip_bgp_all_encap_out_cmd, "clear ip bgp * encap 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) ALIAS (clear_bgp_all_soft_out, clear_bgp_all_out_cmd, "clear bgp * out", CLEAR_STR BGP_STR "Clear all peers\n" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) 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" BGP_SOFT_OUT_STR) DEFUN (clear_bgp_ipv6_safi_prefix, clear_bgp_ipv6_safi_prefix_cmd, "clear bgp ipv6 (unicast|multicast) prefix X:X::X:X/M", CLEAR_STR BGP_STR "Address family\n" "Address Family Modifier\n" "Clear bestpath and re-advertise\n" "IPv6 prefix /, e.g., 3ffe::/16\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_prefix (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL); else return bgp_clear_prefix (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL); } 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_peer_encap_soft_out, clear_ip_bgp_peer_encap_soft_out_cmd, "clear ip bgp A.B.C.D encap 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_ENCAP, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_encap_soft_out, clear_ip_bgp_peer_encap_out_cmd, "clear ip bgp A.B.C.D encap 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_OUT_STR) 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) ALIAS (clear_bgp_external_soft_out, clear_bgp_external_out_cmd, "clear bgp external out", CLEAR_STR BGP_STR "Clear all external peers\n" BGP_SOFT_OUT_STR) 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" BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_as_soft_out, clear_ip_bgp_as_soft_out_cmd, "clear ip bgp " CMD_AS_RANGE " soft out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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 " CMD_AS_RANGE " out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_as_ipv4_soft_out, clear_ip_bgp_as_ipv4_soft_out_cmd, "clear ip bgp " CMD_AS_RANGE " 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" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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 " CMD_AS_RANGE " 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" BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_as_vpnv4_soft_out, clear_ip_bgp_as_vpnv4_soft_out_cmd, "clear ip bgp " CMD_AS_RANGE " vpnv4 unicast soft out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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 " CMD_AS_RANGE " vpnv4 unicast out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" BGP_SOFT_OUT_STR) DEFUN (clear_ip_bgp_as_encap_soft_out, clear_ip_bgp_as_encap_soft_out_cmd, "clear ip bgp " CMD_AS_RANGE " encap 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_ENCAP, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_as_encap_soft_out, clear_ip_bgp_as_encap_out_cmd, "clear ip bgp " CMD_AS_RANGE " encap 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 " CMD_AS_RANGE " soft out", CLEAR_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_STR BGP_SOFT_OUT_STR) { 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 " CMD_AS_RANGE " soft out", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" BGP_SOFT_STR BGP_SOFT_OUT_STR) ALIAS (clear_bgp_as_soft_out, clear_bgp_as_out_cmd, "clear bgp " CMD_AS_RANGE " out", CLEAR_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_OUT_STR) ALIAS (clear_bgp_as_soft_out, clear_bgp_ipv6_as_out_cmd, "clear bgp ipv6 " CMD_AS_RANGE " out", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" BGP_SOFT_OUT_STR) /* 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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_STR BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR "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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_all_encap_soft_in, clear_ip_bgp_all_encap_soft_in_cmd, "clear ip bgp * encap 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_ENCAP, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_all_encap_soft_in, clear_ip_bgp_all_encap_in_cmd, "clear ip bgp * encap 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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_STR BGP_SOFT_IN_STR) 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" BGP_SOFT_STR BGP_SOFT_IN_STR) ALIAS (clear_bgp_all_soft_in, clear_bgp_all_in_cmd, "clear bgp * in", CLEAR_STR BGP_STR "Clear all peers\n" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_peer_encap_soft_in, clear_ip_bgp_peer_encap_soft_in_cmd, "clear ip bgp A.B.C.D encap 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_ENCAP, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_encap_soft_in, clear_ip_bgp_peer_encap_in_cmd, "clear ip bgp A.B.C.D encap 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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_STR BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_STR BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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" BGP_SOFT_STR BGP_SOFT_IN_STR) ALIAS (clear_bgp_external_soft_in, clear_bgp_external_in_cmd, "clear bgp external in", CLEAR_STR BGP_STR "Clear all external peers\n" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR) 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" BGP_SOFT_IN_STR "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" BGP_SOFT_IN_STR "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 " CMD_AS_RANGE " soft in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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 " CMD_AS_RANGE " in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_as_in_prefix_filter, clear_ip_bgp_as_in_prefix_filter_cmd, "clear ip bgp " CMD_AS_RANGE " in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_IN_STR "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 " CMD_AS_RANGE " 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" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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 " CMD_AS_RANGE " 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" BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, "clear ip bgp " CMD_AS_RANGE " 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" BGP_SOFT_IN_STR "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 " CMD_AS_RANGE " vpnv4 unicast soft in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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 " CMD_AS_RANGE " vpnv4 unicast in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" BGP_SOFT_IN_STR) DEFUN (clear_ip_bgp_as_encap_soft_in, clear_ip_bgp_as_encap_soft_in_cmd, "clear ip bgp " CMD_AS_RANGE " encap 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_ENCAP, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_as_encap_soft_in, clear_ip_bgp_as_encap_in_cmd, "clear ip bgp " CMD_AS_RANGE " encap 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 " CMD_AS_RANGE " soft in", CLEAR_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_STR BGP_SOFT_IN_STR) { 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 " CMD_AS_RANGE " soft in", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" BGP_SOFT_STR BGP_SOFT_IN_STR) ALIAS (clear_bgp_as_soft_in, clear_bgp_as_in_cmd, "clear bgp " CMD_AS_RANGE " in", CLEAR_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_IN_STR) ALIAS (clear_bgp_as_soft_in, clear_bgp_ipv6_as_in_cmd, "clear bgp ipv6 " CMD_AS_RANGE " in", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" BGP_SOFT_IN_STR) DEFUN (clear_bgp_as_in_prefix_filter, clear_bgp_as_in_prefix_filter_cmd, "clear bgp " CMD_AS_RANGE " in prefix-filter", CLEAR_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_IN_STR "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 " CMD_AS_RANGE " in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" BGP_SOFT_IN_STR "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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_all_encap_soft, clear_ip_bgp_all_encap_soft_cmd, "clear ip bgp * encap 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_ENCAP, 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) 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" BGP_SOFT_STR) 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_peer_encap_soft, clear_ip_bgp_peer_encap_soft_cmd, "clear ip bgp A.B.C.D encap 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_ENCAP, 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) { 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" BGP_SOFT_STR) DEFUN (clear_ip_bgp_as_soft, clear_ip_bgp_as_soft_cmd, "clear ip bgp " CMD_AS_RANGE " soft", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_STR) { 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 " CMD_AS_RANGE " 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" BGP_SOFT_STR) { 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 " CMD_AS_RANGE " vpnv4 unicast soft", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family Modifier\n" BGP_SOFT_STR) { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_as_encap_soft, clear_ip_bgp_as_encap_soft_cmd, "clear ip bgp " CMD_AS_RANGE " encap 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_ENCAP, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_as_soft, clear_bgp_as_soft_cmd, "clear bgp " CMD_AS_RANGE " soft", CLEAR_STR BGP_STR "Clear peers with the AS number\n" BGP_SOFT_STR) { 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 " CMD_AS_RANGE " soft", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" BGP_SOFT_STR) /* RS-client soft reconfiguration. */ DEFUN (clear_bgp_all_rsclient, clear_bgp_all_rsclient_cmd, "clear bgp * rsclient", CLEAR_STR BGP_STR "Clear all peers\n" BGP_SOFT_RSCLIENT_RIB_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_RSCLIENT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_RSCLIENT, NULL); } ALIAS (clear_bgp_all_rsclient, clear_bgp_ipv6_all_rsclient_cmd, "clear bgp ipv6 * rsclient", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" BGP_SOFT_RSCLIENT_RIB_STR) ALIAS (clear_bgp_all_rsclient, clear_bgp_instance_all_rsclient_cmd, "clear bgp view WORD * rsclient", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" BGP_SOFT_RSCLIENT_RIB_STR) ALIAS (clear_bgp_all_rsclient, clear_bgp_ipv6_instance_all_rsclient_cmd, "clear bgp ipv6 view WORD * rsclient", CLEAR_STR BGP_STR "Address family\n" "BGP view\n" "view name\n" "Clear all peers\n" BGP_SOFT_RSCLIENT_RIB_STR) DEFUN (clear_ip_bgp_all_rsclient, clear_ip_bgp_all_rsclient_cmd, "clear ip bgp * rsclient", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" BGP_SOFT_RSCLIENT_RIB_STR) { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_RSCLIENT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_RSCLIENT, NULL); } ALIAS (clear_ip_bgp_all_rsclient, clear_ip_bgp_instance_all_rsclient_cmd, "clear ip bgp view WORD * rsclient", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" BGP_SOFT_RSCLIENT_RIB_STR) DEFUN (clear_bgp_peer_rsclient, clear_bgp_peer_rsclient_cmd, "clear bgp (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR BGP_STR "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" BGP_SOFT_RSCLIENT_RIB_STR) { if (argc == 2) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_RSCLIENT, argv[1]); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_RSCLIENT, argv[0]); } ALIAS (clear_bgp_peer_rsclient, clear_bgp_ipv6_peer_rsclient_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" BGP_SOFT_RSCLIENT_RIB_STR) ALIAS (clear_bgp_peer_rsclient, clear_bgp_instance_peer_rsclient_cmd, "clear bgp view WORD (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" BGP_SOFT_RSCLIENT_RIB_STR) ALIAS (clear_bgp_peer_rsclient, clear_bgp_ipv6_instance_peer_rsclient_cmd, "clear bgp ipv6 view WORD (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR BGP_STR "Address family\n" "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" BGP_SOFT_RSCLIENT_RIB_STR) DEFUN (clear_ip_bgp_peer_rsclient, clear_ip_bgp_peer_rsclient_cmd, "clear ip bgp (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR IP_STR BGP_STR "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" BGP_SOFT_RSCLIENT_RIB_STR) { if (argc == 2) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_RSCLIENT, argv[1]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_RSCLIENT, argv[0]); } ALIAS (clear_ip_bgp_peer_rsclient, clear_ip_bgp_instance_peer_rsclient_cmd, "clear ip bgp view WORD (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" BGP_SOFT_RSCLIENT_RIB_STR) DEFUN (show_bgp_views, show_bgp_views_cmd, "show bgp views", SHOW_STR BGP_STR "Show the defined BGP views\n") { struct list *inst = bm->bgp; struct listnode *node; struct bgp *bgp; if (!bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) { vty_out (vty, "Multiple BGP views are not defined%s", VTY_NEWLINE); return CMD_WARNING; } vty_out (vty, "Defined BGP views:%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(inst, node, bgp)) vty_out (vty, "\t%s (AS%u)%s", bgp->name ? bgp->name : "(null)", bgp->as, VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (show_bgp_memory, show_bgp_memory_cmd, "show bgp memory", SHOW_STR BGP_STR "Global BGP memory statistics\n") { char memstrbuf[MTYPE_MEMSTR_LEN]; unsigned long count; /* RIB related usage stats */ count = mtype_stats_alloc (MTYPE_BGP_NODE); vty_out (vty, "%ld RIB nodes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_node)), VTY_NEWLINE); count = mtype_stats_alloc (MTYPE_BGP_ROUTE); vty_out (vty, "%ld BGP routes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_info)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_ROUTE_EXTRA))) vty_out (vty, "%ld BGP route ancillaries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_info_extra)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_STATIC))) vty_out (vty, "%ld Static routes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_static)), VTY_NEWLINE); /* Adj-In/Out */ if ((count = mtype_stats_alloc (MTYPE_BGP_ADJ_IN))) vty_out (vty, "%ld Adj-In entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_adj_in)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_ADJ_OUT))) vty_out (vty, "%ld Adj-Out entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_adj_out)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_NEXTHOP_CACHE))) vty_out (vty, "%ld Nexthop cache entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_nexthop_cache)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_DAMP_INFO))) vty_out (vty, "%ld Dampening entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_damp_info)), VTY_NEWLINE); /* Attributes */ count = attr_count(); vty_out (vty, "%ld BGP attributes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof(struct attr)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_ATTR_EXTRA))) vty_out (vty, "%ld BGP extra attributes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof(struct attr_extra)), VTY_NEWLINE); if ((count = attr_unknown_count())) vty_out (vty, "%ld unknown attributes%s", count, VTY_NEWLINE); /* AS_PATH attributes */ count = aspath_count (); vty_out (vty, "%ld BGP AS-PATH entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct aspath)), VTY_NEWLINE); count = mtype_stats_alloc (MTYPE_AS_SEG); vty_out (vty, "%ld BGP AS-PATH segments, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct assegment)), VTY_NEWLINE); /* Other attributes */ if ((count = community_count ())) vty_out (vty, "%ld BGP community entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct community)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_ECOMMUNITY))) vty_out (vty, "%ld BGP community entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct ecommunity)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_LCOMMUNITY))) vty_out (vty, "%ld BGP large-community entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct lcommunity)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_CLUSTER))) vty_out (vty, "%ld Cluster lists, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct cluster_list)), VTY_NEWLINE); /* Peer related usage */ count = mtype_stats_alloc (MTYPE_BGP_PEER); vty_out (vty, "%ld peers, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct peer)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_PEER_GROUP))) vty_out (vty, "%ld peer groups, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct peer_group)), VTY_NEWLINE); /* Other */ if ((count = mtype_stats_alloc (MTYPE_HASH))) vty_out (vty, "%ld hash tables, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct hash)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_HASH_BACKET))) vty_out (vty, "%ld hash buckets, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct hash_backet)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_REGEXP))) vty_out (vty, "%ld compiled regexes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (regex_t)), VTY_NEWLINE); return CMD_SUCCESS; } /* Show BGP peer's summary information. */ static int bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) { struct peer *peer; struct listnode *node, *nnode; unsigned int count = 0; unsigned int totrcount = 0; unsigned int totecount = 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"; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->afc[afi][safi]) { if (!count) { unsigned long ents; char memstrbuf[MTYPE_MEMSTR_LEN]; /* Usage summary and header */ vty_out (vty, "BGP router identifier %s, local AS number %u%s", inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE); ents = bgp_table_count (bgp->rib[afi][safi]); vty_out (vty, "RIB entries %ld, using %s of memory%s", ents, mtype_memstr (memstrbuf, sizeof (memstrbuf), ents * sizeof (struct bgp_node)), VTY_NEWLINE); /* Peer related usage */ ents = listcount (bgp->peer); vty_out (vty, "Peers %ld, using %s of memory%s", ents, mtype_memstr (memstrbuf, sizeof (memstrbuf), ents * sizeof (struct peer)), VTY_NEWLINE); if ((ents = listcount (bgp->rsclient))) vty_out (vty, "RS-Client peers %ld, using %s of memory%s", ents, mtype_memstr (memstrbuf, sizeof (memstrbuf), ents * sizeof (struct peer)), VTY_NEWLINE); if ((ents = listcount (bgp->group))) vty_out (vty, "Peer groups %ld, using %s of memory%s", ents, mtype_memstr (memstrbuf, sizeof (memstrbuf), ents * sizeof (struct peer_group)), 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, "%5u %7d %7d %8d %4d %4d ", 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->sync[afi][safi]->update.count + peer->sync[afi][safi]->withdraw.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]); totrcount += peer->pcount[afi][safi]; totecount++; } 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); vty_out (vty, "%sTotal num. Established sessions %d%s", VTY_NEWLINE, totecount, VTY_NEWLINE); vty_out (vty, "Total num. of routes received %d%s", totrcount, VTY_NEWLINE); } else vty_out (vty, "No %s neighbor is configured%s", afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); return CMD_SUCCESS; } static int bgp_show_summary_vty (struct vty *vty, const 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); } DEFUN (show_bgp_ipv4_safi_summary, show_bgp_ipv4_safi_summary_cmd, "show bgp ipv4 (unicast|multicast) summary", SHOW_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_bgp_instance_ipv4_safi_summary, show_bgp_instance_ipv4_safi_summary_cmd, "show bgp view WORD ipv4 (unicast|multicast) summary", SHOW_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_bgp_ipv4_vpn_summary, show_bgp_ipv4_vpn_summary_cmd, "show bgp ipv4 vpn summary", SHOW_STR BGP_STR "IPv4\n" "Display VPN NLRI specific information\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); } /* `show ip bgp summary' commands. */ DEFUN (show_bgp_ipv6_vpn_summary, show_bgp_ipv6_vpn_summary_cmd, "show bgp ipv6 vpn summary", SHOW_STR BGP_STR "IPv6\n" "Display VPN NLRI specific information\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); } DEFUN (show_bgp_ipv4_encap_summary, show_bgp_ipv4_encap_summary_cmd, "show bgp ipv4 encap summary", SHOW_STR BGP_STR "IPv4\n" "Display ENCAP NLRI specific information\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); } DEFUN (show_bgp_ipv6_encap_summary, show_bgp_ipv6_encap_summary_cmd, "show bgp ipv6 encap summary", SHOW_STR BGP_STR "IPv6\n" "Display ENCAP NLRI specific information\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); } 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") { vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MPLS_VPN); vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_ENCAP); vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MPLS_VPN); vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } DEFUN (show_bgp_instance_ipv4_summary, show_bgp_instance_ipv4_summary_cmd, "show bgp view WORD ipv4 summary", SHOW_STR BGP_STR IP_STR "Address Family modifier\n" "Address Family modifier\n" "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") { vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MPLS_VPN); vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_ENCAP); return CMD_SUCCESS; } DEFUN (show_bgp_instance_ipv6_summary, show_bgp_instance_ipv6_summary_cmd, "show bgp view WORD ipv6 summary", SHOW_STR BGP_STR IPV6_STR "Address Family modifier\n" "Address Family modifier\n" "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") { vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MPLS_VPN); vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } DEFUN (show_bgp_ipv6_safi_summary, show_bgp_ipv6_safi_summary_cmd, "show bgp ipv6 (unicast|multicast) summary", SHOW_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_IP6, SAFI_MULTICAST); return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); } DEFUN (show_bgp_instance_ipv6_safi_summary, show_bgp_instance_ipv6_safi_summary_cmd, "show bgp view WORD ipv6 (unicast|multicast) summary", SHOW_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_IP6, SAFI_MULTICAST); return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_bgp_summary, show_ipv6_bgp_summary_cmd, "show ipv6 bgp summary", SHOW_STR IPV6_STR BGP_STR "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_mbgp_summary, show_ipv6_mbgp_summary_cmd, "show ipv6 mbgp summary", SHOW_STR IPV6_STR MBGP_STR "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); } /* variations of show bgp [...] summary */ /* This one is for the 0-keyword variant */ DEFUN (show_bgp_summary, show_bgp_summary_cmd, "show bgp summary", SHOW_STR BGP_STR "Summary of BGP neighbor status\n") { vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } 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") DEFUN (show_bgp_summary_1w, show_bgp_summary_1w_cmd, "show bgp (ipv4|ipv6|unicast|multicast|vpn|encap) summary", SHOW_STR BGP_STR IP_STR IP6_STR "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") { if (strcmp (argv[0], "ipv4") == 0) { vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); return CMD_SUCCESS; } if (strcmp (argv[0], "ipv6") == 0) { vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } if (strcmp (argv[0], "unicast") == 0) { vty_out(vty, "IPv4 Unicast Summary:%s", VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "IPv6 Unicast Summary:%s", VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); return CMD_SUCCESS; } if (strcmp (argv[0], "multicast") == 0) { vty_out(vty, "IPv4 Multicast Summary:%s", VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "IPv6 Multicast Summary:%s", VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); return CMD_SUCCESS; } if (strcmp (argv[0], "vpn") == 0) { vty_out(vty, "IPv4 VPN Summary:%s", VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "IPv6 VPN Summary:%s", VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); return CMD_SUCCESS; } if (strcmp (argv[0], "encap") == 0) { vty_out(vty, "IPv4 Encap Summary:%s", VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "IPv6 Encap Summary:%s", VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } vty_out(vty, "Unknown keyword: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } const 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 "VPN-IPv4 Unicast"; else if (afi == AFI_IP && safi == SAFI_ENCAP) return "ENCAP-IPv4 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_UNICAST) return "IPv6 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) return "IPv6 Multicast"; else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) return "VPN-IPv6 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_ENCAP) return "ENCAP-IPv6 Unicast"; else return "Unknown"; } /* Show BGP peer's information. */ enum show_type { show_all, show_peer }; static 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); } } static 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); if (p->af_group[afi][safi]) vty_out (vty, " %s peer-group member%s", p->group->name, 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 (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) || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_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) && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)) vty_out (vty, "(all)%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 if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)) vty_out (vty, "(large)%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 (filter->plist[FILTER_IN].name || filter->dlist[FILTER_IN].name || filter->aslist[FILTER_IN].name || filter->map[RMAP_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[RMAP_OUT].name || filter->usmap.name) vty_out (vty, " Outbound path policy configured%s", VTY_NEWLINE); if (filter->map[RMAP_IMPORT].name) vty_out (vty, " Import policy for this RS-client configured%s", VTY_NEWLINE); if (filter->map[RMAP_EXPORT].name) vty_out (vty, " Export policy for this RS-client 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[RMAP_IN].name) vty_out (vty, " Route map for incoming advertisements is %s%s%s", filter->map[RMAP_IN].map ? "*" : "", filter->map[RMAP_IN].name, VTY_NEWLINE); if (filter->map[RMAP_OUT].name) vty_out (vty, " Route map for outgoing advertisements is %s%s%s", filter->map[RMAP_OUT].map ? "*" : "", filter->map[RMAP_OUT].name, VTY_NEWLINE); if (filter->map[RMAP_IMPORT].name) vty_out (vty, " Route map for advertisements going into this RS-client's table is %s%s%s", filter->map[RMAP_IMPORT].map ? "*" : "", filter->map[RMAP_IMPORT].name, VTY_NEWLINE); if (filter->map[RMAP_EXPORT].name) vty_out (vty, " Route map for advertisements coming from this RS-client is %s%s%s", filter->map[RMAP_EXPORT].map ? "*" : "", filter->map[RMAP_EXPORT].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); /* 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); } static 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; int ttl; bgp = p->bgp; /* Configured IP address. */ vty_out (vty, "BGP neighbor is %s, ", p->host); vty_out (vty, "remote AS %u, ", p->as); vty_out (vty, "local AS %u%s%s, ", p->change_local_as ? p->change_local_as : p->local_as, CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? " no-prepend" : "", CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ? " replace-as" : ""); 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)); else if (p->status == Active) { if (CHECK_FLAG (p->flags, PEER_FLAG_PASSIVE)) vty_out (vty, " (passive)"); else if (CHECK_FLAG (p->sflags, PEER_STATUS_NSF_WAIT)) vty_out (vty, " (NSF passive)"); } 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] || 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] || p->afc_adv[AFI_IP6][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP6][SAFI_MPLS_VPN] || p->afc_adv[AFI_IP6][SAFI_ENCAP] || p->afc_recv[AFI_IP6][SAFI_ENCAP] || p->afc_adv[AFI_IP][SAFI_ENCAP] || p->afc_recv[AFI_IP][SAFI_ENCAP] || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, " Neighbor capabilities:%s", VTY_NEWLINE); /* AS4 */ if (CHECK_FLAG (p->cap, PEER_CAP_AS4_RCV) || CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV)) { vty_out (vty, " 4 Byte AS:"); if (CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV)) vty_out (vty, " advertised"); if (CHECK_FLAG (p->cap, PEER_CAP_AS4_RCV)) vty_out (vty, " %sreceived", CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV) ? "and " : ""); vty_out (vty, "%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 by peer:%s ", VTY_NEWLINE); 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(%s)", restart_af_count ? ", " : "", afi_safi_print (afi, safi), CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV) ? "preserved" : "not preserved"); 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 %ld%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 %ld%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 %lu%s", (unsigned long) 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); } /* Default weight */ if (CHECK_FLAG (p->config, PEER_CONFIG_WEIGHT)) vty_out (vty, " Default weight %d%s", p->weight, 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 %ld seconds%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 and GTSM */ ttl = p->gtsm_hops; if (! ttl) ttl = peer_ttl (p); vty_out (vty, " %s BGP neighbor may be up to %d hops away.%s", p->sort == BGP_PEER_IBGP ? "Internal" : "External", ttl, 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); 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); } /* TCP metrics. */ if (p->status == Established && p->rtt) vty_out (vty, "Estimated round trip time: %d ms%s", p->rtt, VTY_NEWLINE); /* Timer information. */ if (p->t_start) vty_out (vty, "Next start timer due in %ld seconds%s", thread_timer_remain_second (p->t_start), VTY_NEWLINE); if (p->t_connect) vty_out (vty, "Next connect timer due in %ld seconds%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); } static int bgp_show_neighbor (struct vty *vty, struct bgp *bgp, enum show_type type, union sockunion *su) { struct listnode *node, *nnode; struct peer *peer; int find = 0; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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; } static int bgp_show_neighbor_vty (struct vty *vty, const char *name, enum show_type type, const 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_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_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); } ALIAS (show_ip_bgp_instance_neighbors, show_bgp_instance_ipv6_neighbors_cmd, "show bgp view WORD ipv6 neighbors", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n") 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; } DEFUN (show_bgp_neighbors, show_bgp_neighbors_cmd, "show bgp neighbors", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n") { return bgp_show_neighbor_vty (vty, NULL, show_all, NULL); } DEFUN (show_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") { return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]); } DEFUN (show_bgp_instance_neighbors, show_bgp_instance_neighbors_cmd, "show bgp view WORD neighbors", SHOW_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_bgp_instance_neighbors_peer, show_bgp_instance_neighbors_peer_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X)", SHOW_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]); } ALIAS (show_bgp_instance_neighbors_peer, show_bgp_instance_ipv6_neighbors_peer_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\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") /* 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_bgp_ipv4_paths, show_bgp_ipv4_paths_cmd, "show bgp paths", SHOW_STR BGP_STR "Path information\n") { vty_out (vty, "Address Refcnt Path%s", VTY_NEWLINE); aspath_print_all_vty (vty); return CMD_SUCCESS; } #include "hash.h" static 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", (void *)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; } static void lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty) { struct lcommunity *lcom; lcom = (struct lcommunity *) backet->data; vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt, lcommunity_str (lcom), VTY_NEWLINE); } /* Show BGP's community internal data. */ DEFUN (show_ip_bgp_lcommunity_info, show_ip_bgp_lcommunity_info_cmd, "show ip bgp large-community-info", SHOW_STR IP_STR BGP_STR "List all bgp large-community information\n") { vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE); hash_iterate (lcommunity_hash (), (void (*) (struct hash_backet *, void *)) lcommunity_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; } static int bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient, afi_t afi, safi_t safi) { char timebuf[BGP_UPTIME_LEN]; char rmbuf[14]; const char *rmname; struct peer *peer; struct listnode *node, *nnode; int len; int count = 0; if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_GROUP)) { for (ALL_LIST_ELEMENTS (rsclient->group->peer, node, nnode, peer)) { count++; bgp_write_rsclient_summary (vty, peer, afi, safi); } return count; } len = vty_out (vty, "%s", rsclient->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, "%10u ", rsclient->as); rmname = ROUTE_MAP_EXPORT_NAME(&rsclient->filter[afi][safi]); if ( rmname && strlen (rmname) > 13 ) { sprintf (rmbuf, "%13s", "..."); rmname = strncpy (rmbuf, rmname, 10); } else if (! rmname) rmname = ""; vty_out (vty, " %13s ", rmname); rmname = ROUTE_MAP_IMPORT_NAME(&rsclient->filter[afi][safi]); if ( rmname && strlen (rmname) > 13 ) { sprintf (rmbuf, "%13s", "..."); rmname = strncpy (rmbuf, rmname, 10); } else if (! rmname) rmname = ""; vty_out (vty, " %13s ", rmname); vty_out (vty, "%8s", peer_uptime (rsclient->uptime, timebuf, BGP_UPTIME_LEN)); if (CHECK_FLAG (rsclient->flags, PEER_FLAG_SHUTDOWN)) vty_out (vty, " Idle (Admin)"); else if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_PREFIX_OVERFLOW)) vty_out (vty, " Idle (PfxCt)"); else vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, rsclient->status)); vty_out (vty, "%s", VTY_NEWLINE); return 1; } static int bgp_show_rsclient_summary (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { struct peer *peer; struct listnode *node, *nnode; int count = 0; /* Header string for each address family. */ static char header[] = "Neighbor V AS Export-Policy Import-Policy Up/Down State"; for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, peer)) { if (peer->afc[afi][safi] && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) { if (! count) { vty_out (vty, "Route Server's BGP router identifier %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, "Route Server's local AS number %u%s", bgp->as, VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%s%s", header, VTY_NEWLINE); } count += bgp_write_rsclient_summary (vty, peer, afi, safi); } } if (count) vty_out (vty, "%sTotal number of Route Server Clients %d%s", VTY_NEWLINE, count, VTY_NEWLINE); else vty_out (vty, "No %s Route Server Client is configured%s", afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); return CMD_SUCCESS; } static int bgp_show_rsclient_summary_vty (struct vty *vty, const 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_rsclient_summary (vty, bgp, afi, safi); return CMD_SUCCESS; } bgp = bgp_get_default (); if (bgp) bgp_show_rsclient_summary (vty, bgp, afi, safi); return CMD_SUCCESS; } /* 'show bgp rsclient' commands. */ DEFUN (show_ip_bgp_rsclient_summary, show_ip_bgp_rsclient_summary_cmd, "show ip bgp rsclient summary", SHOW_STR IP_STR BGP_STR "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_instance_rsclient_summary, show_ip_bgp_instance_rsclient_summary_cmd, "show ip bgp view WORD rsclient summary", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_rsclient_summary, show_ip_bgp_ipv4_rsclient_summary_cmd, "show ip bgp ipv4 (unicast|multicast) rsclient summary", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_instance_ipv4_rsclient_summary, show_ip_bgp_instance_ipv4_rsclient_summary_cmd, "show ip bgp view WORD ipv4 (unicast|multicast) rsclient summary", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } DEFUN (show_bgp_instance_ipv4_safi_rsclient_summary, show_bgp_instance_ipv4_safi_rsclient_summary_cmd, "show bgp view WORD ipv4 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { safi_t safi; if (argc == 2) { safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, safi); } else { safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, safi); } } ALIAS (show_bgp_instance_ipv4_safi_rsclient_summary, show_bgp_ipv4_safi_rsclient_summary_cmd, "show bgp ipv4 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFUN (show_bgp_rsclient_summary, show_bgp_rsclient_summary_cmd, "show bgp rsclient summary", SHOW_STR BGP_STR "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_ENCAP); vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } DEFUN (show_bgp_instance_rsclient_summary, show_bgp_instance_rsclient_summary_cmd, "show bgp view WORD rsclient summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { vty_out(vty, "%sIPv4 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); vty_out(vty, "%sIPv4 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); vty_out(vty, "%sIPv4 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MPLS_VPN); vty_out(vty, "%sIPv4 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_ENCAP); vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_MPLS_VPN); vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } DEFUN (show_bgp_ipv6_rsclient_summary, show_bgp_ipv6_rsclient_summary_cmd, "show bgp ipv6 rsclient summary", SHOW_STR BGP_STR "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_MPLS_VPN); vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } DEFUN (show_bgp_instance_ipv6_rsclient_summary, show_bgp_instance_ipv6_rsclient_summary_cmd, "show bgp view WORD ipv6 rsclient summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { vty_out(vty, "%sIPv6 Unicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "---------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); vty_out(vty, "%sIPv6 Multicast Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); vty_out(vty, "%sIPv6 VPN Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-----------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_MPLS_VPN); vty_out(vty, "%sIPv6 Encap Summary:%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "-------------------%s", VTY_NEWLINE); bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_ENCAP); return CMD_SUCCESS; } DEFUN (show_bgp_instance_ipv6_safi_rsclient_summary, show_bgp_instance_ipv6_safi_rsclient_summary_cmd, "show bgp view WORD ipv6 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { safi_t safi; if (argc == 2) { safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, safi); } else { safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, safi); } } ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, show_bgp_ipv6_safi_rsclient_summary_cmd, "show bgp ipv6 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR IPV6_STR "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") /* Redistribute VTY commands. */ DEFUN (bgp_redistribute_ipv4, bgp_redistribute_ipv4_cmd, "redistribute " QUAGGA_IP_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD) { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "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 = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "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 = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD) { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_redistribute_unset (vty->index, AFI_IP, type); } ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_rmap_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_metric_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_rmap_metric_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") ALIAS (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_metric_rmap_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFUN (bgp_redistribute_ipv6, bgp_redistribute_ipv6_cmd, "redistribute " QUAGGA_IP6_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD) { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "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 = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "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 = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { 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 " QUAGGA_IP6_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD) { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_redistribute_unset (vty->index, AFI_IP6, type); } ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_rmap_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_metric_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_rmap_metric_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") ALIAS (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_metric_rmap_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") int bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) { int i; /* 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", zebra_route_string(i)); if (bgp->redist_metric_flag[afi][i]) vty_out (vty, " metric %u", 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. */ static struct cmd_node bgp_node = { BGP_NODE, "%s(config-router)# ", 1, }; static struct cmd_node bgp_ipv4_unicast_node = { BGP_IPV4_NODE, "%s(config-router-af)# ", 1, }; static struct cmd_node bgp_ipv4_multicast_node = { BGP_IPV4M_NODE, "%s(config-router-af)# ", 1, }; static struct cmd_node bgp_ipv6_unicast_node = { BGP_IPV6_NODE, "%s(config-router-af)# ", 1, }; static struct cmd_node bgp_ipv6_multicast_node = { BGP_IPV6M_NODE, "%s(config-router-af)# ", 1, }; static struct cmd_node bgp_vpnv4_node = { BGP_VPNV4_NODE, "%s(config-router-af)# ", 1 }; static struct cmd_node bgp_vpnv6_node = { BGP_VPNV6_NODE, "%s(config-router-af-vpnv6)# ", 1 }; static struct cmd_node bgp_encap_node = { BGP_ENCAP_NODE, "%s(config-router-af-encap)# ", 1 }; static struct cmd_node bgp_encapv6_node = { BGP_ENCAPV6_NODE, "%s(config-router-af-encapv6)# ", 1 }; static void community_list_vty (void); void bgp_vty_init (void) { /* 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_ipv6_multicast_node, NULL); install_node (&bgp_vpnv4_node, NULL); install_node (&bgp_vpnv6_node, NULL); install_node (&bgp_encap_node, NULL); install_node (&bgp_encapv6_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_IPV6M_NODE); install_default (BGP_VPNV4_NODE); install_default (BGP_VPNV6_NODE); install_default (BGP_ENCAP_NODE); install_default (BGP_ENCAPV6_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_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); /* "maximum-paths" commands. */ install_element (BGP_NODE, &bgp_maxpaths_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_arg_cmd); install_element (BGP_IPV4_NODE, &bgp_maxpaths_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_arg_cmd); install_element (BGP_IPV6_NODE, &bgp_maxpaths_cmd); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_cmd); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_arg_cmd); install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_arg_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); install_element (BGP_NODE, &bgp_graceful_restart_restart_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_restart_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_restart_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 as-path ignore" commands */ install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd); install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd); /* "bgp bestpath as-path confed" commands */ install_element (BGP_NODE, &bgp_bestpath_aspath_confed_cmd); install_element (BGP_NODE, &no_bgp_bestpath_aspath_confed_cmd); /* "bgp bestpath as-path multipath-relax" commands */ install_element (BGP_NODE, &bgp_bestpath_aspath_multipath_relax_cmd); install_element (BGP_NODE, &no_bgp_bestpath_aspath_multipath_relax_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); /* bgp ibgp-allow-policy-mods command */ install_element (BGP_NODE, &bgp_rr_allow_outbound_policy_cmd); install_element (BGP_NODE, &no_bgp_rr_allow_outbound_policy_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, &neighbor_local_as_no_prepend_replace_as_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); install_element (BGP_NODE, &no_neighbor_local_as_val3_cmd); /* "neighbor password" commands. */ install_element (BGP_NODE, &neighbor_password_cmd); install_element (BGP_NODE, &no_neighbor_password_cmd); /* "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_IPV6M_NODE, &neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd); install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd); install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &no_neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd); install_element (BGP_ENCAPV6_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); install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_ENCAP_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_ENCAPV6_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); install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_ENCAPV6_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); install_element (BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_ENCAP_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged10_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged10_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged10_cmd); /* "nexthop-local unchanged" commands */ install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd); /* "transparent-as" and "transparent-nexthop" for old version compatibility. */ install_element (BGP_NODE, &neighbor_transparent_as_cmd); install_element (BGP_NODE, &neighbor_transparent_nexthop_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_IPV6M_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_ENCAP_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_ENCAP_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_send_community_cmd); install_element (BGP_IPV6M_NODE, &neighbor_send_community_type_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_send_community_cmd); install_element (BGP_VPNV6_NODE, &neighbor_send_community_type_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_send_community_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_ENCAP_NODE, &neighbor_send_community_cmd); install_element (BGP_ENCAP_NODE, &neighbor_send_community_type_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_send_community_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_send_community_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_send_community_type_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_send_community_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_ENCAP_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_route_server_client_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_route_server_client_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_ENCAP_NODE, &neighbor_route_server_client_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_route_server_client_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_server_client_cmd); /* "neighbor passive" commands. */ install_element (BGP_NODE, &neighbor_passive_cmd); install_element (BGP_NODE, &no_neighbor_passive_cmd); /* "neighbor shutdown" commands. */ install_element (BGP_NODE, &neighbor_shutdown_cmd); install_element (BGP_NODE, &no_neighbor_shutdown_cmd); /* Deprecated "neighbor capability route-refresh" commands.*/ install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd); install_element (BGP_NODE, &no_neighbor_capability_route_refresh_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); install_element (BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6M_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); install_element (BGP_NODE, &no_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); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_cmd); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd); install_element (BGP_IPV6M_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_NODE, &no_neighbor_weight_cmd); install_element (BGP_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 timers connect" commands. */ install_element (BGP_NODE, &neighbor_timers_connect_cmd); install_element (BGP_NODE, &no_neighbor_timers_connect_cmd); install_element (BGP_NODE, &no_neighbor_timers_connect_val_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_IPV6M_NODE, &neighbor_distribute_list_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_distribute_list_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_ENCAP_NODE, &neighbor_distribute_list_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_distribute_list_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_prefix_list_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_prefix_list_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_ENCAP_NODE, &neighbor_prefix_list_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_prefix_list_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_filter_list_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_filter_list_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_ENCAP_NODE, &neighbor_filter_list_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_filter_list_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_route_map_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_route_map_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_route_map_cmd); install_element (BGP_ENCAP_NODE, &neighbor_route_map_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_route_map_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_route_map_cmd); install_element (BGP_ENCAPV6_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); install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_ENCAP_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_ENCAPV6_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_IPV6M_NODE, &neighbor_allowas_in_cmd); install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_IPV6M_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); install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd); install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_ENCAP_NODE, &neighbor_allowas_in_cmd); install_element (BGP_ENCAP_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_allowas_in_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_ENCAPV6_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); install_element (BGP_NODE, &address_family_ipv6_cmd); install_element (BGP_NODE, &address_family_ipv6_safi_cmd); install_element (BGP_NODE, &address_family_vpnv4_cmd); install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); install_element (BGP_NODE, &address_family_vpnv6_cmd); install_element (BGP_NODE, &address_family_vpnv6_unicast_cmd); install_element (BGP_NODE, &address_family_encap_cmd); install_element (BGP_NODE, &address_family_encapv4_cmd); install_element (BGP_NODE, &address_family_encapv6_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_IPV6M_NODE, &exit_address_family_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); install_element (BGP_ENCAP_NODE, &exit_address_family_cmd); install_element (BGP_ENCAPV6_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); 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); /* "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); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_in_cmd); 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); /* clear ip bgp prefix */ install_element (ENABLE_NODE, &clear_ip_bgp_prefix_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_safi_prefix_cmd); /* "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); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_out_cmd); 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); /* "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); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_cmd); 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); /* "clear ip bgp neighbor rsclient" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_peer_rsclient_cmd); /* "show ip bgp summary" commands. */ install_element (VIEW_NODE, &show_bgp_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_summary_cmd); install_element (VIEW_NODE, &show_bgp_summary_1w_cmd); install_element (RESTRICTED_NODE, &show_bgp_summary_1w_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv4_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_encap_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_encap_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_encap_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); /* "show ip bgp neighbors" commands. */ install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); /* "show ip bgp rsclient" commands. */ install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); /* "show ip bgp paths" commands. */ install_element (VIEW_NODE, &show_bgp_ipv4_paths_cmd); /* "show ip bgp community" commands. */ install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); /* "show ip bgp large-community" commands. */ install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd); /* "show ip bgp attribute-info" commands. */ install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd); /* "redistribute" commands. */ install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd); install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd); install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd); install_element (BGP_NODE, &no_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_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd); 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); /* ttl_security commands */ install_element (BGP_NODE, &neighbor_ttl_security_cmd); install_element (BGP_NODE, &no_neighbor_ttl_security_cmd); /* "show bgp memory" commands. */ install_element (VIEW_NODE, &show_bgp_memory_cmd); install_element (RESTRICTED_NODE, &show_bgp_memory_cmd); /* "show bgp views" commands. */ install_element (VIEW_NODE, &show_bgp_views_cmd); install_element (RESTRICTED_NODE, &show_bgp_views_cmd); /* non afi/safi forms of 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); install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd); 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 (RESTRICTED_NODE, &show_ip_bgp_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); /* 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. */ static const char * community_direct_str (int direct) { switch (direct) { case COMMUNITY_DENY: return "deny"; case COMMUNITY_PERMIT: return "permit"; default: return "unknown"; } } /* Display error string. */ static void community_list_perror (struct vty *vty, int ret) { switch (ret) { case COMMUNITY_LIST_ERR_CANT_FIND_LIST: vty_out (vty, "%% Can't find community-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. */ static int community_list_set_vty (struct vty *vty, int argc, const 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. */ static int community_list_unset_vty (struct vty *vty, int argc, const 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); } static 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 community-list%s", VTY_NEWLINE); return CMD_WARNING; } community_list_show (vty, list); return CMD_SUCCESS; } /* * Large Community code. */ static int lcommunity_list_set_vty (struct vty *vty, int argc, const 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 = lcommunity_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; } static int lcommunity_list_unset_vty (struct vty *vty, int argc, const 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 = lcommunity_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; } /* "large-community-list" keyword help string. */ #define LCOMMUNITY_LIST_STR "Add a large community list entry\n" #define LCOMMUNITY_VAL_STR "large community in 'aa:bb:cc' format\n" DEFUN (ip_lcommunity_list_standard, ip_lcommunity_list_standard_cmd, "ip large-community-list <1-99> (deny|permit) .AA:BB:CC", IP_STR LCOMMUNITY_LIST_STR "Large Community list number (standard)\n" "Specify large community to reject\n" "Specify large community to accept\n" LCOMMUNITY_VAL_STR) { return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0); } ALIAS (ip_lcommunity_list_standard, ip_lcommunity_list_standard2_cmd, "ip large-community-list <1-99> (deny|permit)", IP_STR LCOMMUNITY_LIST_STR "Large Community list number (standard)\n" "Specify large community to reject\n" "Specify large community to accept\n") DEFUN (ip_lcommunity_list_expanded, ip_lcommunity_list_expanded_cmd, "ip large-community-list <100-500> (deny|permit) .LINE", IP_STR LCOMMUNITY_LIST_STR "Large Community list number (expanded)\n" "Specify large community to reject\n" "Specify large community to accept\n" "An ordered list as a regular-expression\n") { return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 0); } DEFUN (ip_lcommunity_list_name_standard, ip_lcommunity_list_name_standard_cmd, "ip large-community-list standard WORD (deny|permit) .AA:BB.CC", IP_STR LCOMMUNITY_LIST_STR "Specify standard large-community-list\n" "Large Community list name\n" "Specify large community to reject\n" "Specify large community to accept\n" LCOMMUNITY_VAL_STR) { return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1); } ALIAS (ip_lcommunity_list_name_standard, ip_lcommunity_list_name_standard2_cmd, "ip large-community-list standard WORD (deny|permit)", IP_STR LCOMMUNITY_LIST_STR "Specify standard large-community-list\n" "Large Community list name\n" "Specify large community to reject\n" "Specify large community to accept\n") DEFUN (ip_lcommunity_list_name_expanded, ip_lcommunity_list_name_expanded_cmd, "ip large-community-list expanded WORD (deny|permit) .LINE", IP_STR LCOMMUNITY_LIST_STR "Specify expanded large-community-list\n" "Large Community list name\n" "Specify large community to reject\n" "Specify large community to accept\n" "An ordered list as a regular-expression\n") { return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 1); } DEFUN (no_ip_lcommunity_list_standard_all, no_ip_lcommunity_list_standard_all_cmd, "no ip large-community-list <1-99>", NO_STR IP_STR LCOMMUNITY_LIST_STR "Large Community list number (standard)\n") { return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); } DEFUN (no_ip_lcommunity_list_expanded_all, no_ip_lcommunity_list_expanded_all_cmd, "no ip large-community-list <100-500>", NO_STR IP_STR LCOMMUNITY_LIST_STR "Large Community list number (expanded)\n") { return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_lcommunity_list_name_standard_all, no_ip_lcommunity_list_name_standard_all_cmd, "no ip large-community-list standard WORD", NO_STR IP_STR LCOMMUNITY_LIST_STR "Specify standard large-community-list\n" "Large Community list name\n") { return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); } DEFUN (no_ip_lcommunity_list_name_expanded_all, no_ip_lcommunity_list_name_expanded_all_cmd, "no ip large-community-list expanded WORD", NO_STR IP_STR LCOMMUNITY_LIST_STR "Specify expanded large-community-list\n" "Large Community list name\n") { return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_lcommunity_list_standard, no_ip_lcommunity_list_standard_cmd, "no ip large-community-list <1-99> (deny|permit) .AA:.AA:NN", NO_STR IP_STR LCOMMUNITY_LIST_STR "Large Community list number (standard)\n" "Specify large community to reject\n" "Specify large community to accept\n" LCOMMUNITY_VAL_STR) { return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); } DEFUN (no_ip_lcommunity_list_expanded, no_ip_lcommunity_list_expanded_cmd, "no ip large-community-list <100-500> (deny|permit) .LINE", NO_STR IP_STR LCOMMUNITY_LIST_STR "Large Community list number (expanded)\n" "Specify large community to reject\n" "Specify large community to accept\n" "An ordered list as a regular-expression\n") { return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_lcommunity_list_name_standard, no_ip_lcommunity_list_name_standard_cmd, "no ip large-community-list standard WORD (deny|permit) .AA:.AA:NN", NO_STR IP_STR LCOMMUNITY_LIST_STR "Specify standard large-community-list\n" "Large Community list name\n" "Specify large community to reject\n" "Specify large community to accept\n" LCOMMUNITY_VAL_STR) { return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); } DEFUN (no_ip_lcommunity_list_name_expanded, no_ip_lcommunity_list_name_expanded_cmd, "no ip large-community-list expanded WORD (deny|permit) .LINE", NO_STR IP_STR LCOMMUNITY_LIST_STR "Specify expanded large-community-list\n" "Large community list name\n" "Specify large community to reject\n" "Specify large community to accept\n" "An ordered list as a regular-expression\n") { return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); } static void lcommunity_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, "Large community %s list %s%s", entry->style == EXTCOMMUNITY_LIST_STANDARD ? "standard" : "(expanded) access", list->name, VTY_NEWLINE); else vty_out (vty, "Named large 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_lcommunity_list, show_ip_lcommunity_list_cmd, "show ip large-community-list", SHOW_STR IP_STR "List large-community list\n") { struct community_list *list; struct community_list_master *cm; cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER); if (! cm) return CMD_SUCCESS; for (list = cm->num.head; list; list = list->next) lcommunity_list_show (vty, list); for (list = cm->str.head; list; list = list->next) lcommunity_list_show (vty, list); return CMD_SUCCESS; } DEFUN (show_ip_lcommunity_list_arg, show_ip_lcommunity_list_arg_cmd, "show ip large-community-list (<1-500>|WORD)", SHOW_STR IP_STR "List large-community list\n" "large-community-list number\n" "large-community-list name\n") { struct community_list *list; list = community_list_lookup (bgp_clist, argv[0], LARGE_COMMUNITY_LIST_MASTER); if (! list) { vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE); return CMD_WARNING; } lcommunity_list_show (vty, list); return CMD_SUCCESS; } static int extcommunity_list_set_vty (struct vty *vty, int argc, const 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; } static int extcommunity_list_unset_vty (struct vty *vty, int argc, const 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); } static 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 extcommunity-list%s", VTY_NEWLINE); return CMD_WARNING; } extcommunity_list_show (vty, list); return CMD_SUCCESS; } /* Return configuration string of community-list entry. */ static const char * community_list_config_str (struct community_entry *entry) { const 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. */ static 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++; } /* lcommunity-list. */ cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER); for (list = cm->num.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { vty_out (vty, "ip large-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 large-community-list %s %s %s %s%s", entry->style == LARGE_COMMUNITY_LIST_STANDARD ? "standard" : "expanded", list->name, community_direct_str (entry->direct), community_list_config_str (entry), VTY_NEWLINE); write++; } return write; } static struct cmd_node community_list_node = { COMMUNITY_LIST_NODE, "", 1 /* Export to vtysh. */ }; static void community_list_vty (void) { 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); /* 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); /* Large Community List */ install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd); install_element (CONFIG_NODE, &ip_lcommunity_list_standard2_cmd); install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd); install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd); install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard2_cmd); install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd); install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd); install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_all_cmd); install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_all_cmd); install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd); install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd); install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd); install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd); install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd); install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd); install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd); } quagga-1.2.4/bgpd/bgp_vty.h000066400000000000000000000021361325323223500155240ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_VTY_H #define _QUAGGA_BGP_VTY_H #define CMD_AS_RANGE "<1-4294967295>" extern void bgp_vty_init (void); extern const char *afi_safi_print (afi_t, safi_t); extern int bgp_parse_afi(const char *str, afi_t *afi); extern int bgp_parse_safi(const char *str, safi_t *safi); #endif /* _QUAGGA_BGP_VTY_H */ quagga-1.2.4/bgpd/bgp_zebra.c000066400000000000000000000756761325323223500160230ustar00rootroot00000000000000/* 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 "filter.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" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" /* All information about zebra. */ struct zclient *zclient = NULL; struct in_addr router_id_zebra; /* Growable buffer for nexthops sent to zebra */ struct stream *bgp_nexthop_buf = NULL; struct stream *bgp_ifindices_buf = NULL; int zclient_num_connects; /* Router-id update message from zebra. */ static int bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct prefix router_id; zebra_router_id_update_read(zclient->ibuf,&router_id); if (BGP_DEBUG(zebra, ZEBRA)) { char buf[128]; prefix2str(&router_id, buf, sizeof(buf)); zlog_debug("Zebra rcvd: router id update %s", buf); } router_id_zebra = router_id.u.prefix4; bgp_router_id_zebra_bump (); return 0; } /* Nexthop update message from zebra. */ static int bgp_read_nexthop_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { bgp_parse_nexthop_update(); return 0; } /* Inteface addition message from zebra. */ static int bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (BGP_DEBUG(zebra, ZEBRA) && ifp) zlog_debug("Zebra rcvd: interface add %s", ifp->name); return 0; } static int bgp_interface_delete (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; s = zclient->ibuf; ifp = zebra_interface_state_read (s, vrf_id); if (! ifp) return 0; ifp->ifindex = IFINDEX_INTERNAL; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra rcvd: interface delete %s", ifp->name); return 0; } static int bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; struct connected *c; struct listnode *node, *nnode; s = zclient->ibuf; ifp = zebra_interface_state_read (s, vrf_id); if (! ifp) return 0; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra rcvd: interface %s up", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_add (c); return 0; } static int bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; struct connected *c; struct listnode *node, *nnode; s = zclient->ibuf; ifp = zebra_interface_state_read (s, vrf_id); if (! ifp) return 0; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra rcvd: interface %s down", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_delete (c); /* Fast external-failover */ { struct listnode *mnode; struct bgp *bgp; struct peer *peer; for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp)) { if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) continue; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->gtsm_hops != 1 && peer_ttl (peer) != 1) continue; if (ifp == peer->nexthop.ifp) BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } static int bgp_interface_address_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id); if (ifc == NULL) return 0; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[128]; prefix2str(ifc->address, buf, sizeof(buf)); zlog_debug("Zebra rcvd: interface %s address add %s", ifc->ifp->name, buf); } if (if_is_operative (ifc->ifp)) bgp_connected_add (ifc); return 0; } static int bgp_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id); if (ifc == NULL) return 0; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[128]; prefix2str(ifc->address, buf, sizeof(buf)); zlog_debug("Zebra rcvd: interface %s address delete %s", ifc->ifp->name, buf); } if (if_is_operative (ifc->ifp)) bgp_connected_delete (ifc); connected_free (ifc); return 0; } /* Zebra route add and delete treatment. */ static int zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv4 api; struct in_addr nexthop; struct prefix_ipv4 p; unsigned char plength = 0; s = zclient->ibuf; 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; plength = stream_getc (s); p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength); 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); stream_getl (s); /* ifindex, unused */ } 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 (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) api.tag = stream_getl (s); else api.tag = 0; if (command == ZEBRA_IPV4_ROUTE_ADD) { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u tag %d", zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric, api.tag); } bgp_redistribute_add ((struct prefix *)&p, &nexthop, NULL, api.metric, api.type, api.tag); } else { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d " "nexthop %s metric %u tag %d", zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric, api.tag); } bgp_redistribute_delete((struct prefix *)&p, api.type); } return 0; } /* Zebra route add and delete treatment. */ static int zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv6 api; struct in6_addr nexthop; struct prefix_ipv6 p; unsigned char plength = 0; s = zclient->ibuf; 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; plength = stream_getc (s); p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, plength); 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); stream_getl (s); /* ifindex, unused */ } 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 (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) api.tag = stream_getl (s); else api.tag = 0; /* Simply ignore link-local address. */ if (IN6_IS_ADDR_LINKLOCAL (&p.prefix)) return 0; if (command == ZEBRA_IPV6_ROUTE_ADD) { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u tag %d", zebra_route_string(api.type), inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric, api.tag); } bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, api.metric, api.type, api.tag); } else { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d " "nexthop %s metric %u tag %d", zebra_route_string(api.type), inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])), api.metric, api.tag); } bgp_redistribute_delete ((struct prefix *) &p, api.type); } return 0; } struct interface * if_lookup_by_ipv4 (struct in_addr *addr) { struct listnode *ifnode; struct 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 (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { 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) { struct listnode *ifnode; struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if (cp->family == AF_INET) if (IPV4_ADDR_SAME (&cp->u.prefix4, addr)) return ifp; } } return NULL; } struct interface * if_lookup_by_ipv6 (struct in6_addr *addr) { struct listnode *ifnode; struct 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 (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { 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) { struct listnode *ifnode; struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if (cp->family == AF_INET6) if (IPV6_ADDR_SAME (&cp->u.prefix6, addr)) return ifp; } } return NULL; } static int if_get_ipv6_global (struct interface *ifp, struct in6_addr *addr) { struct listnode *cnode; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { 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; } static int if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr) { struct listnode *cnode; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { 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; } static int if_get_ipv4_address (struct interface *ifp, struct in_addr *addr) { struct listnode *cnode; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if ((cp->family == AF_INET) && !ipv4_martian(&(cp->u.prefix4))) { *addr = cp->u.prefix4; return 1; } } return 0; } 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; if (peer->update_if) ifp = if_lookup_by_name (peer->update_if); else ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr); } if (local->sa.sa_family == AF_INET6) { if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) { if (peer->ifname) ifp = if_lookup_by_name (peer->ifname); } else if (peer->update_if) ifp = if_lookup_by_name (peer->update_if); else ifp = if_lookup_by_ipv6_exact (&local->sin6.sin6_addr); } if (!ifp) return -1; nexthop->ifp = ifp; /* IPv4 connection. */ if (local->sa.sa_family == AF_INET) { /* 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); } /* IPv6 connection. */ if (local->sa.sa_family == AF_INET6) { struct interface *direct = NULL; /* IPv4 nexthop. */ ret = if_get_ipv4_address(ifp, &nexthop->v4); if (!ret && 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 */ return ret; } void bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi) { int flags; u_char distance; struct peer *peer; struct bgp_info *mpinfo; size_t oldsize, newsize; u_int32_t nhcount; route_tag_t tag = 0; if (zclient->sock < 0) return; if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_BGP], VRF_DEFAULT)) return; flags = 0; peer = info->peer; if ((info->attr->extra) && (info->attr->extra->tag != 0)) tag = info->attr->extra->tag; if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { SET_FLAG (flags, ZEBRA_FLAG_IBGP); SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); } if ((peer->sort == BGP_PEER_EBGP && peer_ttl (peer) != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); nhcount = 1 + bgp_info_mpath_count (info); if (p->family == AF_INET) { struct zapi_ipv4 api; struct in_addr *nexthop; /* resize nexthop buffer size if necessary */ if ((oldsize = stream_get_size (bgp_nexthop_buf)) < (sizeof (struct in_addr *) * nhcount)) { newsize = (sizeof (struct in_addr *) * nhcount); newsize = stream_resize (bgp_nexthop_buf, newsize); if (newsize == oldsize) { zlog_err ("can't resize nexthop buffer"); return; } } stream_reset (bgp_nexthop_buf); api.vrf_id = VRF_DEFAULT; api.flags = flags; nexthop = &info->attr->nexthop; stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); for (mpinfo = bgp_info_mpath_first (info); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { nexthop = &mpinfo->attr->nexthop; stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); } api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = nhcount; api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf); api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if (tag) { SET_FLAG (api.message, ZAPI_MESSAGE_TAG); api.tag = tag; } distance = bgp_distance_apply (p, info, bgp); if (distance) { SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } if (BGP_DEBUG(zebra, ZEBRA)) { int i; char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u" " tag %u count %d", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])), api.metric, api.tag, api.nexthop_num); for (i = 1; i < api.nexthop_num; i++) zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s", i, inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1]))); } zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, (struct prefix_ipv4 *) p, &api); } /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { ifindex_t ifindex; struct in6_addr *nexthop; struct zapi_ipv6 api; int valid_nh_count = 0; /* resize nexthop buffer size if necessary */ if ((oldsize = stream_get_size (bgp_nexthop_buf)) < (sizeof (struct in6_addr *) * nhcount)) { newsize = (sizeof (struct in6_addr *) * nhcount); newsize = stream_resize (bgp_nexthop_buf, newsize); if (newsize == oldsize) { zlog_err ("can't resize nexthop buffer"); return; } } stream_reset (bgp_nexthop_buf); /* resize ifindices buffer size if necessary */ if ((oldsize = stream_get_size (bgp_ifindices_buf)) < (sizeof (unsigned int) * nhcount)) { newsize = (sizeof (unsigned int) * nhcount); newsize = stream_resize (bgp_ifindices_buf, newsize); if (newsize == oldsize) { zlog_err ("can't resize nexthop buffer"); return; } } stream_reset (bgp_ifindices_buf); ifindex = 0; nexthop = NULL; assert (info->attr->extra); /* Only global address nexthop exists. */ if (info->attr->extra->mp_nexthop_len == 16) nexthop = &info->attr->extra->mp_nexthop_global; /* If both global and link-local address present. */ if (info->attr->extra->mp_nexthop_len == 32) { /* Workaround for Cisco's nexthop bug. */ if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global) && peer->su_remote->sa.sa_family == AF_INET6) nexthop = &peer->su_remote->sin6.sin6_addr; else nexthop = &info->attr->extra->mp_nexthop_local; if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } if (nexthop == NULL) return; if (!ifindex) { if (info->peer->ifname) ifindex = ifname2ifindex (info->peer->ifname); else if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *)); stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int)); valid_nh_count++; for (mpinfo = bgp_info_mpath_first (info); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { ifindex = 0; /* Only global address nexthop exists. */ if (mpinfo->attr->extra->mp_nexthop_len == 16) nexthop = &mpinfo->attr->extra->mp_nexthop_global; /* If both global and link-local address present. */ if (mpinfo->attr->extra->mp_nexthop_len == 32) { /* Workaround for Cisco's nexthop bug. */ if (IN6_IS_ADDR_UNSPECIFIED (&mpinfo->attr->extra->mp_nexthop_global) && mpinfo->peer->su_remote->sa.sa_family == AF_INET6) { nexthop = &mpinfo->peer->su_remote->sin6.sin6_addr; } else { nexthop = &mpinfo->attr->extra->mp_nexthop_local; } if (mpinfo->peer->nexthop.ifp) { ifindex = mpinfo->peer->nexthop.ifp->ifindex; } } if (nexthop == NULL) { continue; } if (!ifindex) { if (mpinfo->peer->ifname) { ifindex = if_nametoindex (mpinfo->peer->ifname); } else if (mpinfo->peer->nexthop.ifp) { ifindex = mpinfo->peer->nexthop.ifp->ifindex; } } if (ifindex == 0) { continue; } stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *)); stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int)); valid_nh_count++; } /* Make Zebra API structure. */ api.vrf_id = VRF_DEFAULT; api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = valid_nh_count; api.nexthop = (struct in6_addr **)STREAM_DATA (bgp_nexthop_buf); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = valid_nh_count; api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; distance = ipv6_bgp_distance_apply (p, info, bgp); if (distance) { SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } if (tag) { SET_FLAG (api.message, ZAPI_MESSAGE_TAG); api.tag = tag; } if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u" " tag %u", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])), api.metric, api.tag); } zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, (struct prefix_ipv6 *) p, &api); } } void bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) { int flags; struct peer *peer; if (zclient->sock < 0) return; if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_BGP], VRF_DEFAULT)) return; peer = info->peer; flags = 0; if (peer->sort == BGP_PEER_IBGP) { SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); SET_FLAG (flags, ZEBRA_FLAG_IBGP); } if ((peer->sort == BGP_PEER_EBGP && peer_ttl (peer) != 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; api.vrf_id = VRF_DEFAULT; api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; api.nexthop_num = 0; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if ((info->attr->extra) && (info->attr->extra->tag != 0)) { SET_FLAG(api.message, ZAPI_MESSAGE_TAG); api.tag = info->attr->extra->tag; } if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u tag %d", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, api.metric, api.tag); } zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, (struct prefix_ipv4 *) p, &api); } /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { struct zapi_ipv6 api; api.vrf_id = VRF_DEFAULT; api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; api.nexthop_num = 0; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if ((info->attr->extra) && (info->attr->extra->tag != 0)) { SET_FLAG(api.message, ZAPI_MESSAGE_TAG); api.tag = info->attr->extra->tag; } if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u tag %d", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, api.metric, api.tag); } zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, (struct prefix_ipv6 *) p, &api); } } /* 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 (vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_WARNING; vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT); /* Return if zebra connection is not established. */ if (zclient->sock < 0) return CMD_WARNING; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type)); /* Send distribute add message to zebra. */ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } /* Redistribute with route-map specification. */ int bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type, const 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 (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_WARNING; vrf_bitmap_unset (zclient->redist[type], VRF_DEFAULT); if (bgp->redist[AFI_IP][type] == 0 && bgp->redist[AFI_IP6][type] == 0 && zclient->sock >= 0) { /* Send distribute delete message to zebra. */ if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra send: redistribute delete %s", zebra_route_string(type)); zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT); } /* Withdraw redistributed routes from current BGP's routing table. */ bgp_redistribute_withdraw (bgp, afi, type); return CMD_SUCCESS; } void bgp_zclient_reset (void) { zclient_reset (zclient); } static void bgp_zebra_connected (struct zclient *zclient) { zclient_num_connects++; zclient_send_requests (zclient, VRF_DEFAULT); } void bgp_zebra_init (struct thread_master *master) { zclient_num_connects = 0; /* Set default values. */ zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_BGP); zclient->zebra_connected = bgp_zebra_connected; zclient->router_id_update = bgp_router_id_update; 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; zclient->ipv6_route_add = zebra_read_ipv6; zclient->ipv6_route_delete = zebra_read_ipv6; zclient->nexthop_update = bgp_read_nexthop_update; bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE); } void bgp_zebra_destroy(void) { if (zclient == NULL) return; zclient_stop(zclient); zclient_free(zclient); zclient = NULL; } int bgp_zebra_num_connects(void) { return zclient_num_connects; } quagga-1.2.4/bgpd/bgp_zebra.h000066400000000000000000000042611325323223500160060ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGP_ZEBRA_H #define _QUAGGA_BGP_ZEBRA_H #define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *)) #define BGP_IFINDICES_BUF_SIZE (8 * sizeof (unsigned int)) extern struct stream *bgp_nexthop_buf; extern struct in_addr router_id_zebra; extern struct stream *bgp_ifindices_buf; extern void bgp_zebra_init (struct thread_master *master); extern void bgp_zebra_destroy (void); extern int bgp_if_update_all (void); extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t, safi_t, int *); extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, int *); extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t); extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t); extern int bgp_redistribute_set (struct bgp *, afi_t, int); extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *); extern int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t); extern int bgp_redistribute_unset (struct bgp *, afi_t, int); extern struct interface *if_lookup_by_ipv4 (struct in_addr *); extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *); extern struct interface *if_lookup_by_ipv6 (struct in6_addr *); extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *); extern int bgp_zebra_num_connects(void); #endif /* _QUAGGA_BGP_ZEBRA_H */ quagga-1.2.4/bgpd/bgpd.c000066400000000000000000004476551325323223500150040ustar00rootroot00000000000000/* 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 "sockopt.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 "workqueue.h" #include "table.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_encap.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ /* BGP process wide configuration. */ static struct bgp_master bgp_master; extern struct in_addr router_id_zebra; /* 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: case BGP_OPT_NO_LISTEN: SET_FLAG (bm->options, flag); break; default: return BGP_ERR_INVALID_FLAG; } 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; } 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. */ static int bgp_router_id_set (struct bgp *bgp, struct in_addr *id) { struct peer *peer; struct listnode *node, *nnode; 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. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { IPV4_ADDR_COPY (&peer->local_id, id); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0; } void bgp_router_id_zebra_bump (void) { struct listnode *node, *nnode; struct bgp *bgp; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { if (!bgp->router_id_static.s_addr) bgp_router_id_set (bgp, &router_id_zebra); } } int bgp_router_id_static_set (struct bgp *bgp, struct in_addr id) { bgp->router_id_static = id; bgp_router_id_set (bgp, id.s_addr ? &id : &router_id_zebra); 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 *node, *nnode; 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. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->sort != BGP_PEER_IBGP) continue; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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 *node, *nnode; 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. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->sort != BGP_PEER_IBGP) continue; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0; } /* time_t value that is monotonicly increasing * and uneffected by adjustments to system clock */ time_t bgp_clock (void) { struct timeval tv; quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv); return tv.tv_sec; } /* 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 *node, *nnode; 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. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { /* 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 (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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 (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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 *node, *nnode; bgp->confed_id = 0; bgp_config_unset (bgp, BGP_CONFIG_CONFEDERATION); for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { /* We're looking for peers who's AS is not local */ if (peer_sort (peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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 *node, *nnode; 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)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->as == as) { peer->local_as = bgp->as; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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 *node, *nnode; 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)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->as == as) { peer->local_as = bgp->confed_id; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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; } /* If peer is RSERVER_CLIENT in at least one address family and is not member of a peer_group for that family, return 1. Used to check wether the peer is included in list bgp->rsclient. */ int peer_rsclient_active (struct peer *peer) { int i; int j; for (i=AFI_IP; i < AFI_MAX; i++) for (j=SAFI_UNICAST; j < SAFI_MAX; j++) if (CHECK_FLAG(peer->af_flags[i][j], PEER_FLAG_RSERVER_CLIENT) && ! peer->af_group[i][j]) return 1; 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; } } for (i = RMAP_IN; i < RMAP_MAX; i++) { 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 (afi, 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); SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_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; } /* peer global config reset */ static void peer_global_config_reset (struct peer *peer) { peer->weight = 0; peer->change_local_as = 0; peer->ttl = 0; peer->gtsm_hops = 0; 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_sort (peer) == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; peer->flags = 0; peer->config = 0; peer->holdtime = 0; peer->keepalive = 0; peer->connect = 0; peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; } /* Check peer's AS number and determines if this peer is IBGP or EBGP */ static bgp_peer_sort_t peer_calc_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); } } /* Calculate and cache the peer "sort" */ bgp_peer_sort_t peer_sort (struct peer *peer) { peer->sort = peer_calc_sort (peer); return peer->sort; } static void peer_free (struct peer *peer) { assert (peer->status == Deleted); /* this /ought/ to have been done already through bgp_stop earlier, * but just to be sure.. */ bgp_timer_set (peer); BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); BGP_EVENT_FLUSH (peer); if (peer->desc) { XFREE (MTYPE_PEER_DESC, peer->desc); peer->desc = NULL; } /* Free allocated host character. */ if (peer->host) { XFREE (MTYPE_BGP_PEER_HOST, peer->host); peer->host = NULL; } /* 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; } if (peer->clear_node_queue) { work_queue_free(peer->clear_node_queue); peer->clear_node_queue = NULL; } if (peer->notify.data) XFREE(MTYPE_TMP, peer->notify.data); bgp_sync_delete (peer); bgp_unlock(peer->bgp); memset (peer, 0, sizeof (struct peer)); XFREE (MTYPE_BGP_PEER, peer); } /* increase reference count on a struct peer */ struct peer * peer_lock_with_caller (const char *name, struct peer *peer) { assert (peer && (peer->lock >= 0)); #if 0 zlog_debug("%s peer_lock %p %d", name, peer, peer->lock); #endif peer->lock++; return peer; } /* decrease reference count on a struct peer * struct peer is freed and NULL returned if last reference */ struct peer * peer_unlock_with_caller (const char *name, struct peer *peer) { assert (peer && (peer->lock > 0)); #if 0 zlog_debug("%s peer_unlock %p %d", name, peer, peer->lock); #endif peer->lock--; if (peer->lock == 0) { peer_free (peer); return NULL; } return peer; } /* Allocate new peer object, implicitely locked. */ static struct peer * peer_new (struct bgp *bgp) { afi_t afi; safi_t safi; struct peer *peer; struct servent *sp; /* bgp argument is absolutely required */ assert (bgp); if (!bgp) return NULL; /* Allocate new peer. */ peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer)); /* Set default value. */ peer->fd = -1; peer->v_start = BGP_INIT_START_TIMER; peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; peer->status = Idle; peer->ostatus = Idle; peer->weight = 0; peer->password = NULL; peer->bgp = bgp; peer = peer_lock (peer); /* initial reference */ bgp_lock (bgp); /* 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); SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_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 (); /* We use a larger buffer for peer->work in the event that: * - We RX a BGP_UPDATE where the attributes alone are just * under BGP_MAX_PACKET_SIZE * - The user configures an outbound route-map that does many as-path * prepends or adds many communities. At most they can have CMD_ARGC_MAX * args in a route-map so there is a finite limit on how large they can * make the attributes. * * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid bounds * checking for every single attribute as we construct an UPDATE. */ peer->work = stream_new (BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW); peer->scratch = 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. */ static 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 (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; peer = peer_lock (peer); /* bgp peer list reference */ listnode_add_sort (bgp->peer, peer); active = peer_active (peer); if (afi && safi) peer->afc[afi][safi] = 1; /* Last read and reset time set */ peer->readtime = peer->resettime = bgp_clock (); /* Make peer's address string. */ sockunion2str (su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); /* 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 (bgp); peer = peer_lock (peer); /* bgp peer list reference */ listnode_add_sort (bgp->peer, peer); return peer; } /* Change peer's AS number. */ static void peer_as_change (struct peer *peer, as_t as) { struct peer *conf; /* Stop peer. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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); } 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 */ conf = NULL; if (peer->group) conf = peer->group->conf; if (conf && CHECK_FLAG (conf->config, PEER_CONFIG_ROUTEADV)) peer->v_routeadv = conf->routeadv; else if (peer_sort (peer) == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* 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_IP][SAFI_ENCAP], 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); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP], 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); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); } } /* 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_create (su, bgp, local_as, *as, 0, 0); else 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 (! active && peer_active (peer)) bgp_timer_set (peer); else { if (peer->status == Established) { if (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 *node, *nnode; if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { if (peer1->af_group[afi][safi]) return BGP_ERR_PEER_GROUP_MEMBER_EXISTS; } } else { if (peer->af_group[afi][safi]) return BGP_ERR_PEER_BELONGS_TO_GROUP; } if (! peer->afc[afi][safi]) return 0; /* 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_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, BGP_CLEAR_ROUTE_NORMAL); peer->pcount[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; } int peer_afc_set (struct peer *peer, afi_t afi, safi_t safi, int enable) { if (enable) return peer_activate (peer, afi, safi); else return peer_deactivate (peer, afi, safi); } static 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_RESERVED_3 ; safi++) peer->nsf[afi][safi] = 0; if (peer->t_gr_restart) { BGP_TIMER_OFF (peer->t_gr_restart); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%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_debug ("%s graceful restart stalepath timer stopped", peer->host); } bgp_clear_route_all (peer); } /* Delete peer from confguration. * * The peer is moved to a dead-end "Deleted" neighbour-state, to allow * it to "cool off" and refcounts to hit 0, at which state it is freed. * * This function /should/ take care to be idempotent, to guard against * it being called multiple times through stray events that come in * that happen to result in this function being called again. That * said, getting here for a "Deleted" peer is a bug in the neighbour * FSM. */ int peer_delete (struct peer *peer) { int i; afi_t afi; safi_t safi; struct bgp *bgp; struct bgp_filter *filter; struct listnode *pn; assert (peer->status != Deleted); bgp = peer->bgp; if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); /* If this peer belongs to peer group, clear up the relationship. */ if (peer->group) { if ((pn = listnode_lookup (peer->group->peer, peer))) { peer = peer_unlock (peer); /* group->peer list reference */ list_delete_node (peer->group->peer, pn); } 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. */ peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_stop (peer); bgp_fsm_change_status (peer, Deleted); /* Remove from NHT */ bgp_unlink_nexthop_by_peer (peer); /* Password configuration */ if (peer->password) { XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) bgp_md5_set (peer); } bgp_timer_set (peer); /* stops all timers for Deleted */ /* Delete from all peer list. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) && (pn = listnode_lookup (bgp->peer, peer))) { peer_unlock (peer); /* bgp peer list reference */ list_delete_node (bgp->peer, pn); } if (peer_rsclient_active (peer) && (pn = listnode_lookup (bgp->rsclient, peer))) { peer_unlock (peer); /* rsclient list reference */ list_delete_node (bgp->rsclient, pn); /* Clear our own rsclient ribs. */ 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_RSERVER_CLIENT)) bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); } /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not member of a peer_group. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if (peer->rib[afi][safi] && ! peer->af_group[afi][safi]) bgp_table_finish (&peer->rib[afi][safi]); /* Buffers. */ if (peer->ibuf) { stream_free (peer->ibuf); peer->ibuf = NULL; } if (peer->obuf) { stream_fifo_free (peer->obuf); peer->obuf = NULL; } if (peer->work) { stream_free (peer->work); peer->work = NULL; } if (peer->scratch) { stream_free(peer->scratch); peer->scratch = NULL; } /* Local and remote addresses. */ if (peer->su_local) { sockunion_free (peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { sockunion_free (peer->su_remote); peer->su_remote = NULL; } /* 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); 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; } } for (i = RMAP_IN; i < RMAP_MAX; i++) { if (filter->map[i].name) { free (filter->map[i].name); filter->map[i].name = NULL; } } if (filter->usmap.name) { free (filter->usmap.name); filter->usmap.name = NULL; } if (peer->default_rmap[afi][safi].name) { free (peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name = NULL; } } if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETING)) bgp_peer_clear_node_queue_drain_immediate(peer); peer_unlock (peer); /* initial reference */ return 0; } static int peer_group_cmp (struct peer_group *g1, struct peer_group *g2) { return strcmp (g1->name, g2->name); } /* If peer is configured at least one address family return 1. */ static int peer_group_active (struct peer *peer) { if (peer->af_group[AFI_IP][SAFI_UNICAST] || peer->af_group[AFI_IP][SAFI_MULTICAST] || peer->af_group[AFI_IP][SAFI_MPLS_VPN] || peer->af_group[AFI_IP][SAFI_ENCAP] || peer->af_group[AFI_IP6][SAFI_UNICAST] || peer->af_group[AFI_IP6][SAFI_MULTICAST] || peer->af_group[AFI_IP6][SAFI_MPLS_VPN] || peer->af_group[AFI_IP6][SAFI_ENCAP]) return 1; return 0; } /* Peer group cofiguration. */ static struct peer_group * peer_group_new (void) { return (struct peer_group *) XCALLOC (MTYPE_PEER_GROUP, sizeof (struct peer_group)); } static void peer_group_free (struct peer_group *group) { XFREE (MTYPE_PEER_GROUP, group); } struct peer_group * peer_group_lookup (struct bgp *bgp, const char *name) { struct peer_group *group; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { if (strcmp (group->name, name) == 0) return group; } return NULL; } struct peer_group * peer_group_get (struct bgp *bgp, const 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 (bgp); if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) group->conf->afc[AFI_IP][SAFI_UNICAST] = 1; group->conf->host = XSTRDUP (MTYPE_BGP_PEER_HOST, name); group->conf->group = group; group->conf->as = 0; group->conf->ttl = 0; group->conf->gtsm_hops = 0; group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER); UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT); group->conf->keepalive = 0; group->conf->holdtime = 0; group->conf->connect = 0; SET_FLAG (group->conf->sflags, PEER_STATUS_GROUP); listnode_add_sort (bgp->group, group); return 0; } static void peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, afi_t afi, safi_t safi) { int in = FILTER_IN; int out = FILTER_OUT; struct peer *conf; struct bgp_filter *pfilter; struct bgp_filter *gfilter; conf = group->conf; pfilter = &peer->filter[afi][safi]; gfilter = &conf->filter[afi][safi]; /* remote-as */ if (conf->as) peer->as = conf->as; /* remote-as */ if (conf->change_local_as) peer->change_local_as = conf->change_local_as; /* TTL */ peer->ttl = conf->ttl; /* GTSM hops */ peer->gtsm_hops = conf->gtsm_hops; /* Weight */ peer->weight = conf->weight; /* peer flags apply */ peer->flags = conf->flags; /* peer af_flags apply */ peer->af_flags[afi][safi] = conf->af_flags[afi][safi]; /* peer config apply */ peer->config = conf->config; /* peer timers apply */ peer->holdtime = conf->holdtime; peer->keepalive = conf->keepalive; peer->connect = conf->connect; if (CHECK_FLAG (conf->config, PEER_CONFIG_CONNECT)) peer->v_connect = conf->connect; else peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; /* advertisement-interval reset */ if (CHECK_FLAG (conf->config, PEER_CONFIG_ROUTEADV)) peer->v_routeadv = conf->routeadv; else if (peer_sort (peer) == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* password apply */ if (conf->password && !peer->password) peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, conf->password); bgp_md5_set (peer); /* maximum-prefix */ peer->pmax[afi][safi] = conf->pmax[afi][safi]; peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi]; peer->pmax_restart[afi][safi] = conf->pmax_restart[afi][safi]; /* allowas-in */ peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi]; /* route-server-client */ if (CHECK_FLAG(conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) { /* Make peer's RIB point to group's RIB. */ peer->rib[afi][safi] = group->conf->rib[afi][safi]; /* Import policy. */ if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); if (gfilter->map[RMAP_IMPORT].name) { pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; } else { pfilter->map[RMAP_IMPORT].name = NULL; pfilter->map[RMAP_IMPORT].map = NULL; } /* Export policy. */ if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) { pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; } } /* default-originate route-map */ if (conf->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 (conf->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].map = conf->default_rmap[afi][safi].map; } /* update-source apply */ if (conf->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 (conf->update_source); } else if (conf->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, conf->update_if); } /* 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[RMAP_IN].name && ! pfilter->map[RMAP_IN].name) { if (pfilter->map[RMAP_IN].name) free (pfilter->map[RMAP_IN].name); pfilter->map[RMAP_IN].name = strdup (gfilter->map[RMAP_IN].name); pfilter->map[RMAP_IN].map = gfilter->map[RMAP_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[RMAP_OUT].name) { if (pfilter->map[RMAP_OUT].name) free (pfilter->map[RMAP_OUT].name); pfilter->map[RMAP_OUT].name = strdup (gfilter->map[RMAP_OUT].name); pfilter->map[RMAP_OUT].map = gfilter->map[RMAP_OUT].map; } else { if (pfilter->map[RMAP_OUT].name) free (pfilter->map[RMAP_OUT].name); pfilter->map[RMAP_OUT].name = NULL; pfilter->map[RMAP_OUT].map = NULL; } /* RS-client's import/export route-maps. */ if (gfilter->map[RMAP_IMPORT].name) { if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; } else { if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].name = NULL; pfilter->map[RMAP_IMPORT].map = NULL; } if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) { if (pfilter->map[RMAP_EXPORT].name) free (pfilter->map[RMAP_EXPORT].name); pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; } 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; } } /* Peer group's remote AS configuration. */ int peer_group_remote_as (struct bgp *bgp, const char *group_name, as_t *as) { struct peer_group *group; struct peer *peer; struct listnode *node, *nnode; 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); for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->as != *as) peer_as_change (peer, *as); } return 0; } int peer_ttl (struct peer *peer) { if (peer->ttl) return peer->ttl; if (peer->gtsm_hops || peer->sort == BGP_PEER_IBGP) return 255; return 1; } int peer_group_delete (struct peer_group *group) { struct bgp *bgp; struct peer *peer; struct listnode *node, *nnode; bgp = group->bgp; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer_delete (peer); } list_delete (group->peer); free (group->name); group->name = NULL; group->conf->group = 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 *node, *nnode; if (! group->conf->as) return 0; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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; /* Check peer group's address family. */ if (! group->conf->afc[afi][safi]) return BGP_ERR_PEER_GROUP_AF_UNCONFIGURED; /* 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, afi, safi); peer->group = group; peer->af_group[afi][safi] = 1; peer = peer_lock (peer); /* group->peer list reference */ listnode_add (group->peer, peer); peer_group2peer_config_copy (group, peer, afi, safi); return 0; } /* When the peer already belongs to peer group, check the consistency. */ if (peer->af_group[afi][safi]) { if (strcmp (peer->group->name, group->name) != 0) return BGP_ERR_PEER_GROUP_CANT_CHANGE; return 0; } /* Check current peer group configuration. */ if (peer_group_active (peer) && strcmp (peer->group->name, group->name) != 0) return BGP_ERR_PEER_GROUP_MISMATCH; if (! group->conf->as) { if (peer_sort (group->conf) != BGP_PEER_INTERNAL && peer_sort (group->conf) != peer_sort (peer)) { if (as) *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } if (peer_sort (group->conf) == BGP_PEER_INTERNAL) first_member = 1; } peer->af_group[afi][safi] = 1; peer->afc[afi][safi] = 1; if (! peer->group) { peer->group = group; peer = peer_lock (peer); /* group->peer list reference */ listnode_add (group->peer, peer); } else assert (group && peer->group == group); if (first_member) { /* Advertisement-interval reset */ if (! CHECK_FLAG (group->conf->config, PEER_CONFIG_ROUTEADV)) { 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; } /* 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); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); } } if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) { struct listnode *pn; /* If it's not configured as RSERVER_CLIENT in any other address family, without being member of a peer_group, remove it from list bgp->rsclient.*/ if (! peer_rsclient_active (peer) && (pn = listnode_lookup (bgp->rsclient, peer))) { peer_unlock (peer); /* peer rsclient reference */ list_delete_node (bgp->rsclient, pn); /* Clear our own rsclient rib for this afi/safi. */ bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); } bgp_table_finish (&peer->rib[afi][safi]); /* Import policy. */ if (peer->filter[afi][safi].map[RMAP_IMPORT].name) { free (peer->filter[afi][safi].map[RMAP_IMPORT].name); peer->filter[afi][safi].map[RMAP_IMPORT].name = NULL; peer->filter[afi][safi].map[RMAP_IMPORT].map = NULL; } /* Export policy. */ if (! CHECK_FLAG(group->conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && peer->filter[afi][safi].map[RMAP_EXPORT].name) { free (peer->filter[afi][safi].map[RMAP_EXPORT].name); peer->filter[afi][safi].map[RMAP_EXPORT].name = NULL; peer->filter[afi][safi].map[RMAP_EXPORT].map = NULL; } } peer_group2peer_config_copy (group, peer, afi, safi); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RMAP_BIND; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } int peer_group_unbind (struct bgp *bgp, struct peer *peer, struct peer_group *group, afi_t afi, safi_t safi) { if (! peer->af_group[afi][safi]) return 0; if (group != peer->group) return BGP_ERR_PEER_GROUP_MISMATCH; peer->af_group[afi][safi] = 0; peer->afc[afi][safi] = 0; peer_af_flag_reset (peer, afi, safi); if (peer->rib[afi][safi]) peer->rib[afi][safi] = NULL; if (! peer_group_active (peer)) { assert (listnode_lookup (group->peer, peer)); peer_unlock (peer); /* peer group list reference */ listnode_delete (group->peer, peer); peer->group = NULL; if (group->conf->as) { peer_delete (peer); return 0; } peer_global_config_reset (peer); } if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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; } static int bgp_startup_timer_expire (struct thread *thread) { struct bgp *bgp; bgp = THREAD_ARG (thread); bgp->t_startup = NULL; return 0; } /* BGP instance creation by `router bgp' commands. */ static struct bgp * bgp_create (as_t *as, const char *name) { struct bgp *bgp; afi_t afi; safi_t safi; if ( (bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp))) == NULL) return NULL; bgp_lock (bgp); bgp->peer_self = peer_new (bgp); bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "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; bgp->rsclient = list_new (); bgp->rsclient->cmp = (int (*)(void*, void*)) peer_cmp; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { bgp->route[afi][safi] = bgp_table_init (afi, safi); bgp->aggregate[afi][safi] = bgp_table_init (afi, safi); bgp->rib[afi][safi] = bgp_table_init (afi, safi); bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; } 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_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); bgp->as = *as; if (name) bgp->name = strdup (name); THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire, bgp, bgp->restart_time); return bgp; } /* Return first entry of BGP. */ struct bgp * bgp_get_default (void) { if (bm && bm->bgp && bm->bgp->head) return (listgetdata (listhead (bm->bgp))); return NULL; } /* Lookup BGP entry. */ struct bgp * bgp_lookup (as_t as, const char *name) { struct bgp *bgp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) 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 (const char *name) { struct bgp *bgp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) 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, const 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); bgp_router_id_set(bgp, &router_id_zebra); *bgp_val = bgp; /* Create BGP server socket, if first instance. */ if (list_isempty(bm->bgp) && !bgp_option_check (BGP_OPT_NO_LISTEN)) { if (bgp_socket (bm->port, bm->address) < 0) return BGP_ERR_INVALID_VALUE; } listnode_add (bm->bgp, bgp); return 0; } /* Delete BGP instance. */ int bgp_delete (struct bgp *bgp) { struct peer *peer; struct peer_group *group; struct listnode *node, *pnode; struct listnode *next, *pnext; afi_t afi; int i; SET_FLAG(bgp->flags, BGP_FLAG_DELETING); THREAD_OFF (bgp->t_startup); for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer)) { if (peer->status == Established || peer->status == OpenSent || peer->status == OpenConfirm) { bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); } } /* 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 (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { /* Send notify to remote peer. */ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } peer_delete (peer); } for (ALL_LIST_ELEMENTS (bgp->group, node, next, group)) { for (ALL_LIST_ELEMENTS (group->peer, pnode, pnext, peer)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { /* Send notify to remote peer. */ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } } peer_group_delete (group); } assert (listcount (bgp->rsclient) == 0); if (bgp->peer_self) { peer_delete(bgp->peer_self); bgp->peer_self = NULL; } /* * Free pending deleted routes. Unfortunately, it also has to process * all the pending activity for other instances of struct bgp. * * This call was added to achieve clean memory allocation at exit, * for the sake of valgrind. */ bgp_process_queues_drain_immediate(); /* Remove visibility via the master list - there may however still be * routes to be processed still referencing the struct bgp. */ listnode_delete (bm->bgp, bgp); if (list_isempty(bm->bgp)) bgp_close (); bgp_unlock(bgp); /* initial reference */ return 0; } static void bgp_free (struct bgp *); void bgp_lock (struct bgp *bgp) { ++bgp->lock; } void bgp_unlock(struct bgp *bgp) { assert(bgp->lock > 0); if (--bgp->lock == 0) bgp_free (bgp); } static void bgp_free (struct bgp *bgp) { afi_t afi; safi_t safi; list_delete (bgp->group); list_delete (bgp->peer); list_delete (bgp->rsclient); 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]); } XFREE (MTYPE_BGP, bgp); } struct peer * peer_lookup (struct bgp *bgp, union sockunion *su) { struct peer *peer; struct listnode *node, *nnode; if (bgp != NULL) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) if (sockunion_same (&peer->su, su) && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) return peer; } else if (bm->bgp != NULL) { struct listnode *bgpnode, *nbgpnode; for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp)) for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) 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 *node; struct listnode *bgpnode; struct bgp *bgp; if (! bm->bgp) return NULL; for (ALL_LIST_ELEMENTS_RO (bm->bgp, bgpnode, bgp)) { for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { 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; } } for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { 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_IP][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP]) 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_IP][SAFI_ENCAP] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) 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, }; static 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 (peer->status != Established) 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; }; static const struct peer_flag_action peer_flag_action_list[] = { { PEER_FLAG_PASSIVE, 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 } }; static const 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_SEND_LARGE_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 }, { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out }, { PEER_FLAG_NEXTHOP_SELF_ALL, 1, peer_change_reset_out }, { 0, 0, 0 } }; /* Proper action set. */ static int peer_flag_action_set (const 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; const 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; } static 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_debug ("%s Maximum-prefix restart timer canceled", peer->host); } if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); else BGP_EVENT_ADD (peer, BGP_Stop); } else { peer->v_start = BGP_INIT_START_TIMER; BGP_EVENT_ADD (peer, BGP_Stop); } } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; else if (flag == PEER_FLAG_PASSIVE) peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } /* Change specified peer flag. */ static int peer_flag_modify (struct peer *peer, u_int32_t flag, int set) { int found; int size; struct peer_group *group; struct listnode *node, *nnode; 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_active (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_active (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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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); } static int peer_is_group_member (struct peer *peer, afi_t afi, safi_t safi) { if (peer->af_group[afi][safi]) return 1; return 0; } static 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 *node, *nnode; 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_is_group_member (peer, afi, safi)) 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->af_group[afi][safi]) 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (! peer->af_group[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 *node, *nnode; struct peer *peer1; if (peer->sort == BGP_PEER_IBGP) return BGP_ERR_NO_IBGP_WITH_TTLHACK; if (peer->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { if (peer1->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } } peer->ttl = ttl; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { bgp_set_socket_ttl (peer, peer->fd); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->ttl = ttl; bgp_set_socket_ttl (peer, peer->fd); } } return 0; } /* Neighbor description. */ int peer_description_set (struct peer *peer, const 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, const char *ifname) { struct peer_group *group; struct listnode *node, *nnode; 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 (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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 (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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, const union sockunion *su) { struct peer_group *group; struct listnode *node, *nnode; 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; } peer->update_source = sockunion_dup (su); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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 *node, *nnode; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) && ! peer->update_source && ! peer->update_if) return 0; 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_active (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 (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (! peer->update_source && ! peer->update_if) continue; 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 (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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, const char *rmap) { struct peer_group *group; struct listnode *node, *nnode; /* 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_is_group_member (peer, afi, safi)) 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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 *node, *nnode; /* 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_is_group_member (peer, afi, safi)) 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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) { struct peer_group *group; struct listnode *node, *nnode; SET_FLAG (peer->config, PEER_CONFIG_WEIGHT); peer->weight = weight; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->weight = group->conf->weight; } return 0; } int peer_weight_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; /* Set default weight. */ if (peer_group_active (peer)) peer->weight = peer->group->conf->weight; else peer->weight = 0; UNSET_FLAG (peer->config, PEER_CONFIG_WEIGHT); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->weight = 0; } return 0; } int peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime) { struct peer_group *group; struct listnode *node, *nnode; /* Not for peer group memeber. */ if (peer_group_active (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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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 *node, *nnode; if (peer_group_active (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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { UNSET_FLAG (peer->config, PEER_CONFIG_TIMER); peer->holdtime = 0; peer->keepalive = 0; } return 0; } int peer_timers_connect_set (struct peer *peer, u_int32_t connect) { struct peer_group *group; struct listnode *node, *nnode; if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; if (connect > 65535) return BGP_ERR_INVALID_VALUE; /* Set value to the configuration. */ SET_FLAG (peer->config, PEER_CONFIG_CONNECT); peer->connect = connect; /* Set value to timer setting. */ peer->v_connect = connect; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { SET_FLAG (peer->config, PEER_CONFIG_CONNECT); peer->connect = connect; peer->v_connect = connect; } return 0; } int peer_timers_connect_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; /* Clear configuration. */ UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT); peer->connect = 0; /* Set timer setting to default value. */ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT); peer->connect = 0; peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; } return 0; } int peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) { struct peer_group *group; struct listnode *node, *nnode; if (peer_group_active (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; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); peer->routeadv = routeadv; peer->v_routeadv = routeadv; } return 0; } int peer_advertise_interval_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); peer->routeadv = 0; if (peer->sort == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); peer->routeadv = 0; if (peer->sort == 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, const 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 *node, *nnode; 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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 *node, *nnode; 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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, int replace_as) { struct bgp *bgp = peer->bgp; struct peer_group *group; struct listnode *node, *nnode; 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_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; if (peer->as == as) return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS; 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)) && ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && replace_as) || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && ! replace_as))) 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 (replace_as) SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { 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 (replace_as) SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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 *node, *nnode; if (peer_group_active (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); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { 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; } /* Set password for authenticating with the peer. */ int peer_password_set (struct peer *peer, const char *password) { struct listnode *nn, *nnode; int len = password ? strlen(password) : 0; int ret = BGP_SUCCESS; if ((len < PEER_PASSWORD_MINLEN) || (len > PEER_PASSWORD_MAXLEN)) return BGP_ERR_INVALID_VALUE; if (peer->password && strcmp (peer->password, password) == 0 && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; if (peer->password) XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, password); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED; } for (ALL_LIST_ELEMENTS (peer->group->peer, nn, nnode, peer)) { if (peer->password && strcmp (peer->password, password) == 0) continue; if (peer->password) XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); if (bgp_md5_set (peer) < 0) ret = BGP_ERR_TCPSIG_FAILED; } return ret; } int peer_password_unset (struct peer *peer) { struct listnode *nn, *nnode; if (!peer->password && !CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; if (!CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer_group_active (peer) && peer->group->conf->password && strcmp (peer->group->conf->password, peer->password) == 0) return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); if (peer->password) XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = NULL; bgp_md5_set (peer); return 0; } XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = NULL; for (ALL_LIST_ELEMENTS (peer->group->peer, nn, nnode, peer)) { if (!peer->password) continue; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = NULL; bgp_md5_set (peer); } return 0; } /* Set distribute list to the peer. */ int peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; 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_is_group_member (peer, afi, safi)) 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)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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 *node, *nnode; 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_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; /* apply peer-group filter */ if (peer->af_group[afi][safi]) { gfilter = &peer->group->conf->filter[afi][safi]; if (gfilter->dlist[direct].name) { if (filter->dlist[direct].name) free (filter->dlist[direct].name); filter->dlist[direct].name = strdup (gfilter->dlist[direct].name); filter->dlist[direct].alist = gfilter->dlist[direct].alist; return 0; } } if (filter->dlist[direct].name) free (filter->dlist[direct].name); filter->dlist[direct].name = NULL; filter->dlist[direct].alist = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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. */ static void peer_distribute_update (const char *name) { afi_t afi; safi_t safi; int direct; struct listnode *mnode, *mnnode; struct listnode *node, *nnode; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct bgp_filter *filter; for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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; } } } for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { 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, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; 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_is_group_member (peer, afi, safi)) 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)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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 *node, *nnode; 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_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; /* apply peer-group filter */ if (peer->af_group[afi][safi]) { gfilter = &peer->group->conf->filter[afi][safi]; if (gfilter->plist[direct].name) { if (filter->plist[direct].name) free (filter->plist[direct].name); filter->plist[direct].name = strdup (gfilter->plist[direct].name); filter->plist[direct].plist = gfilter->plist[direct].plist; return 0; } } if (filter->plist[direct].name) free (filter->plist[direct].name); filter->plist[direct].name = NULL; filter->plist[direct].plist = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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. */ static void peer_prefix_list_update (struct prefix_list *plist) { struct listnode *mnode, *mnnode; struct listnode *node, *nnode; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct bgp_filter *filter; afi_t afi; safi_t safi; int direct; for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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; } } } for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { 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, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; 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_is_group_member (peer, afi, safi)) 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)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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 *node, *nnode; 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_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; /* apply peer-group filter */ if (peer->af_group[afi][safi]) { gfilter = &peer->group->conf->filter[afi][safi]; if (gfilter->aslist[direct].name) { if (filter->aslist[direct].name) free (filter->aslist[direct].name); filter->aslist[direct].name = strdup (gfilter->aslist[direct].name); filter->aslist[direct].aslist = gfilter->aslist[direct].aslist; return 0; } } if (filter->aslist[direct].name) free (filter->aslist[direct].name); filter->aslist[direct].name = NULL; filter->aslist[direct].aslist = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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; } static void peer_aslist_update (void) { afi_t afi; safi_t safi; int direct; struct listnode *mnode, *mnnode; struct listnode *node, *nnode; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct bgp_filter *filter; for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { 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; } } } for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { 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, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != RMAP_IN && direct != RMAP_OUT && direct != RMAP_IMPORT && direct != RMAP_EXPORT) return BGP_ERR_INVALID_VALUE; if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) && peer_is_group_member (peer, afi, safi)) 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)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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 *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != RMAP_IN && direct != RMAP_OUT && direct != RMAP_IMPORT && direct != RMAP_EXPORT) return BGP_ERR_INVALID_VALUE; if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; /* apply peer-group filter */ if (peer->af_group[afi][safi]) { gfilter = &peer->group->conf->filter[afi][safi]; if (gfilter->map[direct].name) { if (filter->map[direct].name) free (filter->map[direct].name); filter->map[direct].name = strdup (gfilter->map[direct].name); filter->map[direct].map = gfilter->map[direct].map; return 0; } } if (filter->map[direct].name) free (filter->map[direct].name); filter->map[direct].name = NULL; filter->map[direct].map = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (peer_is_group_member (peer, afi, safi)) 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)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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 peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (peer_is_group_member (peer, afi, safi)) 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 (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[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 *node, *nnode; 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; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (! peer->af_group[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); if ((peer->status == Established) && (peer->afc[afi][safi])) bgp_maximum_prefix_overflow (peer, afi, safi, 1); } } else { if ((peer->status == Established) && (peer->afc[afi][safi])) bgp_maximum_prefix_overflow (peer, afi, safi, 1); } return 0; } int peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi) { struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; /* apply peer-group config */ if (peer->af_group[afi][safi]) { 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]; return 0; } 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 (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (! peer->af_group[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; } /* Set # of hops between us and BGP peer. */ int peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) { struct peer_group *group; struct listnode *node, *nnode; struct peer *peer1; zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); if (peer->ttl != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { if (peer1->ttl != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } } peer->gtsm_hops = gtsm_hops; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { bgp_set_socket_ttl (peer, peer->fd); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->gtsm_hops = gtsm_hops; /* Change setting of existing peer * established then change value (may break connectivity) * not established yet (teardown session and restart) * no session then do nothing (will get handled by next connection) */ if (peer->status == Established) { bgp_set_socket_ttl (peer, peer->fd); } else if (peer->status < Established) { if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s Min-ttl changed", peer->host); BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } int peer_clear (struct peer *peer) { if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) { 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_debug ("%s Maximum-prefix restart timer canceled", peer->host); } BGP_EVENT_ADD (peer, BGP_Start); return 0; } peer->v_start = BGP_INIT_START_TIMER; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) 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; peer->rtt = sockopt_tcp_rtt (peer->fd); if (stype == BGP_CLEAR_SOFT_RSCLIENT) { if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) return 0; bgp_check_local_routes_rsclient (peer, afi, safi); bgp_soft_reconfig_rsclient (peer, afi, safi); } 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.*/ /* XXX: why does this function return char * when it takes buffer? */ 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 %lu", (u_long)len); /* XXX: should return status instead of buf... */ snprintf (buf, len, " "); return buf; } /* If there is no connection has been done before print `never'. */ if (uptime2 == 0) { snprintf (buf, len, "never "); return buf; } /* Get current time. */ uptime1 = bgp_clock (); uptime1 -= uptime2; tm = gmtime (&uptime1); /* Making formatted timer strings. */ #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND ONE_DAY_SECOND*7 #define ONE_YEAR_SECOND ONE_DAY_SECOND*365 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 if (uptime1 < ONE_YEAR_SECOND) snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); else snprintf (buf, len, "%02dy%02dw%dd", tm->tm_year - 70, tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7)); return buf; } static 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->af_group[afi][safi]) 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[RMAP_IN].name) if (! gfilter || ! gfilter->map[RMAP_IN].name || strcmp (filter->map[RMAP_IN].name, gfilter->map[RMAP_IN].name) != 0) vty_out (vty, " neighbor %s route-map %s in%s", addr, filter->map[RMAP_IN].name, VTY_NEWLINE); if (filter->map[RMAP_OUT].name && ! gfilter) vty_out (vty, " neighbor %s route-map %s out%s", addr, filter->map[RMAP_OUT].name, VTY_NEWLINE); if (filter->map[RMAP_IMPORT].name && ! gfilter) vty_out (vty, " neighbor %s route-map %s import%s", addr, filter->map[RMAP_IMPORT].name, VTY_NEWLINE); if (filter->map[RMAP_EXPORT].name) if (! gfilter || ! gfilter->map[RMAP_EXPORT].name || strcmp (filter->map[RMAP_EXPORT].name, gfilter->map[RMAP_EXPORT].name) != 0) vty_out (vty, " neighbor %s route-map %s export%s", addr, filter->map[RMAP_EXPORT].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. */ static void bgp_config_write_peer (struct vty *vty, struct bgp *bgp, struct peer *peer, afi_t afi, safi_t safi) { struct peer *g_peer = NULL; char buf[SU_ADDRSTRLEN]; char *addr; addr = peer->host; if (peer_group_active (peer)) g_peer = peer->group->conf; /************************************ ****** Global to the neighbor ****** ************************************/ if (afi == AFI_IP && safi == SAFI_UNICAST) { /* remote-as. */ if (! peer_group_active (peer)) { 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 %u%s", addr, peer->as, VTY_NEWLINE); } else { if (! g_peer->as) vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as, VTY_NEWLINE); if (peer->af_group[AFI_IP][SAFI_UNICAST]) vty_out (vty, " neighbor %s peer-group %s%s", addr, peer->group->name, VTY_NEWLINE); } /* local-as. */ if (peer->change_local_as) if (! peer_group_active (peer)) vty_out (vty, " neighbor %s local-as %u%s%s%s", addr, peer->change_local_as, CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? " no-prepend" : "", CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ? " replace-as" : "", 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_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN)) vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE); /* Password. */ if (peer->password) if (!peer_group_active (peer) || ! g_peer->password || strcmp (peer->password, g_peer->password) != 0) vty_out (vty, " neighbor %s password %s%s", addr, peer->password, VTY_NEWLINE); /* 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); /* Passive. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSIVE)) vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE); /* TTL option */ if (peer->gtsm_hops && ! peer_group_active (peer)) vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, peer->gtsm_hops, VTY_NEWLINE); else if (peer->ttl && ! peer_group_active (peer)) 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_active (peer) || ! CHECK_FLAG (g_peer->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_active (peer) || ! g_peer->update_if || strcmp (g_peer->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_active (peer) || ! g_peer->update_source || sockunion_cmp (g_peer->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) && ! peer_group_active (peer)) 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_active (peer)) vty_out (vty, " neighbor %s timers %d %d%s", addr, peer->keepalive, peer->holdtime, VTY_NEWLINE); if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT) && ! peer_group_active (peer)) vty_out (vty, " neighbor %s timers connect %d%s", addr, peer->connect, VTY_NEWLINE); /* Default weight. */ if (CHECK_FLAG (peer->config, PEER_CONFIG_WEIGHT)) if (! peer_group_active (peer) || g_peer->weight != peer->weight) vty_out (vty, " neighbor %s weight %d%s", addr, peer->weight, VTY_NEWLINE); /* Dynamic capability. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->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_active (peer) || ! CHECK_FLAG (g_peer->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_active (peer) || ! CHECK_FLAG (g_peer->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_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) vty_out (vty, " neighbor %s strict-capability-match%s", addr, VTY_NEWLINE); if (! peer->af_group[AFI_IP][SAFI_UNICAST]) { if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) { if (peer->afc[AFI_IP][SAFI_UNICAST]) vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE); } else { if (! peer->afc[AFI_IP][SAFI_UNICAST]) vty_out (vty, " no neighbor %s activate%s", addr, VTY_NEWLINE); } } } /************************************ ****** Per AF to the neighbor ****** ************************************/ if (! (afi == AFI_IP && safi == SAFI_UNICAST)) { if (peer->af_group[afi][safi]) 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); } /* 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->af_group[afi][safi]) { 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); } /* Route reflector client. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT) && ! peer->af_group[afi][safi]) 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->af_group[afi][safi]) vty_out (vty, " neighbor %s next-hop-self%s%s", addr, peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF_ALL) ? " all" : "", VTY_NEWLINE); /* Remove private AS. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s remove-private-AS%s", addr, VTY_NEWLINE); /* send-community print. */ if (! peer->af_group[afi][safi]) { 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) && peer_af_flag_check(peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)) vty_out (vty, " neighbor %s send-community all%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_LARGE_COMMUNITY)) vty_out (vty, " neighbor %s send-community large%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) && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)) vty_out (vty, " no neighbor %s send-community all%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_LARGE_COMMUNITY)) vty_out (vty, " no neighbor %s send-community large%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->af_group[afi][safi]) { 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); } /* Soft reconfiguration inbound. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) if (! peer->af_group[afi][safi] || ! CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) vty_out (vty, " neighbor %s soft-reconfiguration inbound%s", addr, VTY_NEWLINE); /* maximum-prefix. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) if (! peer->af_group[afi][safi] || g_peer->pmax[afi][safi] != peer->pmax[afi][safi] || g_peer->pmax_threshold[afi][safi] != peer->pmax_threshold[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); } /* Route server client. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE); /* Nexthop-local unchanged. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s nexthop-local unchanged%s", addr, VTY_NEWLINE); /* Allow AS in. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) if (! peer_group_active (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); } /* Filter. */ bgp_config_write_filter (vty, peer, afi, safi); /* atribute-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->af_group[afi][safi]) { 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); } } /* 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; if (afi == AFI_IP && safi == SAFI_UNICAST) return; vty_out (vty, "!%s address-family ", VTY_NEWLINE); if (afi == AFI_IP) { if (safi == SAFI_MULTICAST) vty_out (vty, "ipv4 multicast"); else if (safi == SAFI_MPLS_VPN) vty_out (vty, "vpnv4"); else if (safi == SAFI_ENCAP) vty_out (vty, "encap"); } else if (afi == AFI_IP6) { if (safi == SAFI_MPLS_VPN) vty_out (vty, "vpnv6"); else if (safi == SAFI_ENCAP) vty_out (vty, "encapv6"); else { vty_out (vty, "ipv6"); if (safi == SAFI_MULTICAST) vty_out (vty, " multicast"); } } vty_out (vty, "%s", VTY_NEWLINE); *write = 1; } /* Address family based peer configuration display. */ static 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 *node, *nnode; bgp_config_write_network (vty, bgp, afi, safi, &write); bgp_config_write_redistribute (vty, bgp, afi, safi, &write); for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { if (group->conf->afc[afi][safi]) { bgp_config_write_family_header (vty, afi, safi, &write); bgp_config_write_peer (vty, bgp, group->conf, afi, safi); } } for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (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_maxpaths (vty, bgp, afi, safi, &write); bgp_config_write_distance (vty, bgp, afi, safi, &write); if (write) 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 *node, *nnode; struct listnode *mnode, *mnnode; /* 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. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { if (write) vty_out (vty, "!%s", VTY_NEWLINE); /* Router bgp ASN */ vty_out (vty, "router bgp %u", 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); /* No Synchronization */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) vty_out (vty, " no synchronization%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, " no 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, " %u", bgp->confed_peers[i]); vty_out (vty, "%s", VTY_NEWLINE); } /* BGP enforce-first-as. */ if (bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) vty_out (vty, " 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->restart_time != BGP_DEFAULT_RESTART_TIME) vty_out (vty, " bgp graceful-restart restart-time %d%s", bgp->restart_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_ASPATH_CONFED)) vty_out (vty, " bgp bestpath as-path confed%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { vty_out (vty, " bgp bestpath as-path multipath-relax%s", VTY_NEWLINE); } if (bgp_flag_check (bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { vty_out (vty, " bgp route-reflector allow-outbound-policy%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_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); } /* BGP network import check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) vty_out (vty, " bgp network import-check%s", VTY_NEWLINE); /* BGP flag dampening. */ if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST], BGP_CONFIG_DAMPENING)) bgp_config_write_damp (vty); /* BGP static route configuration. */ bgp_config_write_network (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* BGP redistribute configuration. */ bgp_config_write_redistribute (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* 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); /* peer-group */ for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { bgp_config_write_peer (vty, bgp, group->conf, AFI_IP, SAFI_UNICAST); } /* Normal neighbor configuration. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST); } /* maximum-paths */ bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* Distance configuration. */ bgp_config_write_distance (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* No auto-summary */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) vty_out (vty, " no auto-summary%s", VTY_NEWLINE); /* 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); /* ENCAPv4 configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_ENCAP); /* IPv6 unicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_UNICAST); /* IPv6 multicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST); /* IPv6 VPN configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN); /* ENCAPv6 configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_ENCAP); vty_out (vty, " exit%s", VTY_NEWLINE); write++; } return write; } void bgp_master_init (void) { memset (&bgp_master, 0, sizeof (struct bgp_master)); bm = &bgp_master; bm->bgp = list_new (); bm->listen_sockets = list_new (); bm->port = BGP_PORT_DEFAULT; bm->master = thread_master_create (); bm->start_time = bgp_clock (); } void bgp_init (void) { /* allocates some vital data structures used by peer commands in vty_init */ bgp_scan_init (); /* Init zebra. */ bgp_zebra_init (bm->master); /* BGP VTY commands installation. */ bgp_vty_init (); /* BGP inits. */ bgp_attr_init (); bgp_debug_init (); bgp_dump_init (); bgp_route_init (); bgp_route_map_init (); bgp_address_init (); bgp_scan_vty_init(); bgp_mplsvpn_init (); bgp_encap_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 */ } void bgp_terminate (void) { struct bgp *bgp; struct peer *peer; struct listnode *node, *nnode; struct listnode *mnode, *mnnode; for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) if (peer->status == Established) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); bgp_cleanup_routes (); if (bm->process_main_queue) { work_queue_free (bm->process_main_queue); bm->process_main_queue = NULL; } if (bm->process_rsclient_queue) { work_queue_free (bm->process_rsclient_queue); bm->process_rsclient_queue = NULL; } } quagga-1.2.4/bgpd/bgpd.conf.sample000066400000000000000000000010661325323223500167450ustar00rootroot00000000000000! -*- bgp -*- ! ! BGPd sample configuratin file ! ! $Id: bgpd.conf.sample,v 1.1 2002/12/13 20:15:29 paul 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 quagga-1.2.4/bgpd/bgpd.conf.sample2000066400000000000000000000053611325323223500170310ustar00rootroot00000000000000! ! 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 ! quagga-1.2.4/bgpd/bgpd.h000066400000000000000000001073531325323223500147750ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_BGPD_H #define _QUAGGA_BGPD_H /* For union sockunion. */ #include "sockunion.h" /* Typedef BGP specific types. */ typedef u_int32_t as_t; typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */ 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; /* work queues */ struct work_queue *process_main_queue; struct work_queue *process_rsclient_queue; /* Listening sockets */ struct list *listen_sockets; /* BGP port number. */ u_int16_t port; /* Listener address */ char *address; /* 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) #define BGP_OPT_NO_LISTEN (1 << 3) }; /* BGP instance structure. */ struct bgp { /* AS number of this BGP instance. */ as_t as; /* Name of this BGP instance. */ char *name; /* Reference count to allow peer_delete to finish after bgp_delete */ int lock; /* Self peer. */ struct peer *peer_self; /* BGP peer. */ struct list *peer; /* BGP peer group. */ struct list *group; /* BGP route-server-clients. */ struct list *rsclient; /* 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; struct in_addr router_id_static; /* 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; struct thread *t_startup; /* BGP flags. */ u_int32_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_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_ASPATH_CONFED (1 << 13) #define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14) #define BGP_FLAG_DELETING (1 << 15) #define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 16) /* 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 ipv6 distance configuration. */ u_char ipv6_distance_ebgp; u_char ipv6_distance_ibgp; u_char ipv6_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; /* Maximum-paths configuration */ struct bgp_maxpaths_cfg { u_int16_t maxpaths_ebgp; u_int16_t maxpaths_ibgp; } maxpaths[AFI_MAX][SAFI_MAX]; }; /* 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; struct in6_addr v6_global; struct in6_addr v6_local; }; /* BGP router distinguisher value. */ #define BGP_RD_SIZE 8 struct bgp_rd { u_char val[BGP_RD_SIZE]; }; #define RMAP_IN 0 #define RMAP_OUT 1 #define RMAP_IMPORT 2 #define RMAP_EXPORT 3 #define RMAP_MAX 4 /* 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[RMAP_MAX]; /* Unsuppress-map. */ struct { char *name; struct route_map *map; } usmap; }; /* IBGP/EBGP identifier. We also have a CONFED peer, which is to say, a peer who's AS is part of our Confederation. */ typedef enum { BGP_PEER_IBGP = 1, BGP_PEER_EBGP, BGP_PEER_INTERNAL, BGP_PEER_CONFED, } bgp_peer_sort_t; #define BGP_MAX_PACKET_SIZE_OVERFLOW 1024 /* BGP neighbor structure. */ struct peer { /* BGP structure. */ struct bgp *bgp; /* reference count, primarily to allow bgp_process'ing of route_node's * to be done after a struct peer is deleted. * * named 'lock' for hysterical reasons within Quagga. */ int lock; /* BGP peer group. */ struct peer_group *group; u_char af_group[AFI_MAX][SAFI_MAX]; /* Peer's remote AS number. */ as_t as; /* Peer's local AS number. */ as_t local_as; bgp_peer_sort_t sort; /* 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; /* Peer specific RIB when configured as route-server-client. */ struct bgp_table *rib[AFI_MAX][SAFI_MAX]; /* Packet receive and send buffer. */ struct stream *ibuf; struct stream_fifo *obuf; struct stream *work; /* We use a separate stream to encode MP_REACH_NLRI for efficient * NLRI packing. peer->work stores all the other attributes. The * actual packet is then constructed by concatenating the two. */ struct stream *scratch; /* Status of the peer. */ int status; int ostatus; /* Peer index, used for dumping TABLE_DUMP_V2 format */ uint16_t table_dump_index; /* Peer information */ int fd; /* File descriptor */ int ttl; /* TTL of TCP connection to the peer. */ int rtt; /* Estimated round-trip-time from TCP_INFO */ int gtsm_hops; /* minimum hopcount to 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 */ ifindex_t 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_int16_t 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 */ #define PEER_CAP_AS4_ADV (1 << 7) /* as4 advertised */ #define PEER_CAP_AS4_RCV (1 << 8) /* as4 received */ #define PEER_CAP_RESTART_BIT_ADV (1 << 9) /* sent restart state */ #define PEER_CAP_RESTART_BIT_RCV (1 << 10) /* peer restart state */ /* 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_PASSIVE (1 << 0) /* passive mode */ #define PEER_FLAG_SHUTDOWN (1 << 1) /* shutdown */ #define PEER_FLAG_DONT_CAPABILITY (1 << 2) /* dont-capability */ #define PEER_FLAG_OVERRIDE_CAPABILITY (1 << 3) /* override-capability */ #define PEER_FLAG_STRICT_CAP_MATCH (1 << 4) /* strict-match */ #define PEER_FLAG_DYNAMIC_CAPABILITY (1 << 5) /* dynamic capability */ #define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 6) /* disable-connected-check */ #define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */ #define PEER_FLAG_LOCAL_AS_REPLACE_AS (1 << 8) /* local-as no-prepend replace-as */ /* 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 */ #define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */ #define PEER_FLAG_NEXTHOP_SELF_ALL (1 << 17) /* next-hop-self all */ #define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 18) /* Send large Communities */ /* MD5 password */ 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_OPEN_DEFERRED (1 << 3) /* deferred to open_receive */ #define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */ #define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */ #define PEER_STATUS_NSF_WAIT (1 << 6) /* 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_WEIGHT (1 << 0) /* Default weight. */ #define PEER_CONFIG_TIMER (1 << 1) /* keepalive & holdtime */ #define PEER_CONFIG_CONNECT (1 << 2) /* connect */ #define PEER_CONFIG_ROUTEADV (1 << 3) /* route advertise */ u_int32_t weight; u_int32_t holdtime; u_int32_t keepalive; u_int32_t connect; 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_routeadv; u_int32_t v_pmax_restart; 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_routeadv; struct thread *t_pmax_restart; struct thread *t_gr_restart; struct thread *t_gr_stale; /* workqueues */ struct work_queue *clear_node_queue; /* 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; /* 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_PASSIVE_CHANGE 20 /* neighbor passive command */ #define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop 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 */ #define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */ #define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */ }; #define PEER_PASSWORD_MINLEN (1) #define PEER_PASSWORD_MAXLEN (80) /* 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_AS4_PATH 17 #define BGP_ATTR_AS4_AGGREGATOR 18 #define BGP_ATTR_AS_PATHLIMIT 21 #define BGP_ATTR_ENCAP 23 #define BGP_ATTR_LARGE_COMMUNITIES 32 /* 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 #define BGP_NOTIFY_SUBCODE_UNSPECIFIC 0 /* 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_UNSPECIFIC 0 #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 (RFC 4486). */ #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_COLLISION_RESOLUTION 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 Clearing 7 #define Deleted 8 #define BGP_STATUS_MAX 9 /* 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 Clearing_Completed 14 #define BGP_Stop_with_error 15 #define BGP_EVENTS_MAX 16 /* BGP timers default value. */ #define BGP_INIT_START_TIMER 1 #define BGP_DEFAULT_HOLDTIME 180 #define BGP_DEFAULT_KEEPALIVE 60 #define BGP_DEFAULT_EBGP_ROUTEADV 3 #define BGP_DEFAULT_IBGP_ROUTEADV 1 #define BGP_DEFAULT_CONNECT_RETRY 5 /* 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 /* RFC4364 */ #define SAFI_MPLS_LABELED_VPN 128 /* 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_DEFAULT_CONFIG "bgpd.conf" /* Check AS path loop when we send NLRI. */ /* #define BGP_SEND_ASPATH_CHECK */ /* 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, BGP_CLEAR_SOFT_RSCLIENT }; /* Macros. */ #define BGP_INPUT(P) ((P)->ibuf) #define BGP_INPUT_PNT(P) (STREAM_PNT(BGP_INPUT(P))) #define BGP_IS_VALID_STATE_FOR_NOTIF(S)\ (((S) == OpenSent) || ((S) == OpenConfirm) || ((S) == Established)) /* 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_TCPSIG_FAILED -29 #define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -30 #define BGP_ERR_NO_IBGP_WITH_TTLHACK -31 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -32 #define BGP_ERR_MAX -33 extern struct bgp_master *bm; /* Prototypes. */ extern void bgp_terminate (void); extern void bgp_reset (void); extern time_t bgp_clock (void); extern void bgp_zclient_reset (void); extern int bgp_nexthop_set (union sockunion *, union sockunion *, struct bgp_nexthop *, struct peer *); extern struct bgp *bgp_get_default (void); extern struct bgp *bgp_lookup (as_t, const char *); extern struct bgp *bgp_lookup_by_name (const char *); extern struct peer *peer_lookup (struct bgp *, union sockunion *); extern struct peer_group *peer_group_lookup (struct bgp *, const char *); extern struct peer_group *peer_group_get (struct bgp *, const char *); extern struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_addr *, int *); /* * Peers are incredibly easy to memory leak * due to the various ways that they are actually used * Provide some functionality to debug locks and unlocks */ extern struct peer *peer_lock_with_caller(const char *, struct peer *); extern struct peer *peer_unlock_with_caller(const char *, struct peer *); #define peer_unlock(A) peer_unlock_with_caller(__FUNCTION__, (A)) #define peer_lock(B) peer_lock_with_caller(__FUNCTION__, (B)) extern bgp_peer_sort_t peer_sort (struct peer *peer); extern int peer_active (struct peer *); extern int peer_active_nego (struct peer *); extern struct peer *peer_create_accept (struct bgp *); extern char *peer_uptime (time_t, char *, size_t); extern int bgp_config_write (struct vty *); extern void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *); extern void bgp_master_init (void); extern void bgp_init (void); extern void bgp_route_map_init (void); extern int bgp_option_set (int); extern int bgp_option_unset (int); extern int bgp_option_check (int); extern int bgp_get (struct bgp **, as_t *, const char *); extern int bgp_delete (struct bgp *); extern int bgp_flag_set (struct bgp *, int); extern int bgp_flag_unset (struct bgp *, int); extern int bgp_flag_check (struct bgp *, int); extern void bgp_lock (struct bgp *); extern void bgp_unlock (struct bgp *); extern void bgp_router_id_zebra_bump (void); extern int bgp_router_id_static_set (struct bgp *, struct in_addr); extern int bgp_cluster_id_set (struct bgp *, struct in_addr *); extern int bgp_cluster_id_unset (struct bgp *); extern int bgp_confederation_id_set (struct bgp *, as_t); extern int bgp_confederation_id_unset (struct bgp *); extern int bgp_confederation_peers_check (struct bgp *, as_t); extern int bgp_confederation_peers_add (struct bgp *, as_t); extern int bgp_confederation_peers_remove (struct bgp *, as_t); extern int bgp_timers_set (struct bgp *, u_int32_t keepalive, u_int32_t holdtime); extern int bgp_timers_unset (struct bgp *); extern int bgp_default_local_preference_set (struct bgp *, u_int32_t); extern int bgp_default_local_preference_unset (struct bgp *); extern int peer_rsclient_active (struct peer *); extern int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t); extern int peer_group_remote_as (struct bgp *, const char *, as_t *); extern int peer_ttl (struct peer *peer); extern int peer_delete (struct peer *peer); extern int peer_group_delete (struct peer_group *); extern int peer_group_remote_as_delete (struct peer_group *); extern int peer_activate (struct peer *, afi_t, safi_t); extern int peer_deactivate (struct peer *, afi_t, safi_t); extern int peer_afc_set (struct peer *, afi_t, safi_t, int); extern int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *, afi_t, safi_t, as_t *); extern int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *, afi_t, safi_t); extern int peer_flag_set (struct peer *, u_int32_t); extern int peer_flag_unset (struct peer *, u_int32_t); extern int peer_af_flag_set (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_ebgp_multihop_set (struct peer *, int); extern int peer_description_set (struct peer *, const char *); extern int peer_description_unset (struct peer *); extern int peer_update_source_if_set (struct peer *, const char *); extern int peer_update_source_addr_set (struct peer *, const union sockunion *); extern int peer_update_source_unset (struct peer *); extern int peer_default_originate_set (struct peer *, afi_t, safi_t, const char *); extern int peer_default_originate_unset (struct peer *, afi_t, safi_t); extern int peer_port_set (struct peer *, u_int16_t); extern int peer_port_unset (struct peer *); extern int peer_weight_set (struct peer *, u_int16_t); extern int peer_weight_unset (struct peer *); extern int peer_timers_set (struct peer *, u_int32_t keepalive, u_int32_t holdtime); extern int peer_timers_unset (struct peer *); extern int peer_timers_connect_set (struct peer *, u_int32_t); extern int peer_timers_connect_unset (struct peer *); extern int peer_advertise_interval_set (struct peer *, u_int32_t); extern int peer_advertise_interval_unset (struct peer *); extern int peer_interface_set (struct peer *, const char *); extern int peer_interface_unset (struct peer *); extern int peer_distribute_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_distribute_unset (struct peer *, afi_t, safi_t, int); extern int peer_allowas_in_set (struct peer *, afi_t, safi_t, int); extern int peer_allowas_in_unset (struct peer *, afi_t, safi_t); extern int peer_local_as_set (struct peer *, as_t, int, int); extern int peer_local_as_unset (struct peer *); extern int peer_prefix_list_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_prefix_list_unset (struct peer *, afi_t, safi_t, int); extern int peer_aslist_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_aslist_unset (struct peer *,afi_t, safi_t, int); extern int peer_route_map_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_route_map_unset (struct peer *, afi_t, safi_t, int); extern int peer_unsuppress_map_set (struct peer *, afi_t, safi_t, const char *); extern int peer_password_set (struct peer *, const char *); extern int peer_password_unset (struct peer *); extern int peer_unsuppress_map_unset (struct peer *, afi_t, safi_t); extern int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, u_char, int, u_int16_t); extern int peer_maximum_prefix_unset (struct peer *, afi_t, safi_t); extern int peer_clear (struct peer *); extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type); extern int peer_ttl_security_hops_set (struct peer *, int); extern void bgp_scan_finish (void); #endif /* _QUAGGA_BGPD_H */ quagga-1.2.4/common.am000066400000000000000000000021431325323223500145720ustar00rootroot00000000000000# # Automake fragment intended to be shared by Makefile.am files in the # tree. # if HAVE_PROTOBUF # Uncomment to use an non-system version of libprotobuf-c. # # Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src # Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la Q_PROTOBUF_C_CLIENT_INCLUDES= Q_PROTOBUF_C_CLIENT_LDOPTS=-lprotobuf-c Q_PROTOC=protoc Q_PROTOC_C=protoc-c Q_PROTOBUF_CFILES = $(filter %.pb-c.c,$(SOURCES)) Q_PROTOBUF_SRCS = $(Q_PROTOBUF_CFILES) $(Q_PROTOBUF_HFILES) # Rules %.pb.h: %.proto $(Q_PROTOC) $(PROTOBUF_INCLUDES) --cpp_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ %.pb-c.c %.pb-c.h: %.proto $(Q_PROTOC_C) $(PROTOBUF_INCLUDES) --c_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ # # Information about how to link to various libraries. # Q_QUAGGA_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libquagga_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS) Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfpm_pb.la $(Q_QUAGGA_PB_CLIENT_LDOPTS) endif # HAVE_PROTOBUF Q_CLEANFILES = $(Q_PROTOBUF_SRCS) Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS) quagga-1.2.4/compile000077500000000000000000000162451325323223500143510ustar00rootroot00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2014 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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, see . # 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. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: quagga-1.2.4/config.guess000077500000000000000000001256441325323223500153170ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2016 Free Software Foundation, Inc. timestamp='2016-10-02' # 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 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) 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 case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # 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 tuples: *-*-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. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || \ echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "${UNAME_MACHINE_ARCH}" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; *:Sortix:*:*) echo ${UNAME_MACHINE}-unknown-sortix exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # 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. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; 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 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; 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 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; 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 ;; 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 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /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 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # 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 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build 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 -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; 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 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????: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 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi 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 ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build 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 -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build 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 -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; 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 i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; e2k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; k1om:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; mips64el:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # 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. echo i386-sequent-sysv4 exit ;; 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 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; 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 ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; 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|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; 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 i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; 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 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*: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; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' 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; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *: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 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; 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 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *: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 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac cat >&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: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: quagga-1.2.4/config.h.in000066400000000000000000000535501325323223500150160ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* bgpd vty socket */ #undef BGP_VTYSH_PATH /* Mask for config files */ #undef CONFIGFILE_MASK /* Consumed Time Check */ #undef CONSUMED_TIME_CHECK /* daemon vty directory */ #undef DAEMON_VTY_DIR /* Build for development */ #undef DEV_BUILD /* Disable BGP installation to zebra */ #undef DISABLE_BGP_ANNOUNCE /* include git version info */ #undef GIT_VERSION /* GNU Linux */ #undef GNU_LINUX /* Define to 1 if you have the `alarm' function. */ #undef HAVE_ALARM /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ASM_TYPES_H /* Broken CMSG_FIRSTHDR */ #undef HAVE_BROKEN_CMSG_FIRSTHDR /* BSD ifi_link_state available */ #undef HAVE_BSD_IFI_LINK_STATE /* BSD link-detect */ #undef HAVE_BSD_LINK_DETECT /* Can pass ifindex in struct ip_mreq */ #undef HAVE_BSD_STRUCT_IP_MREQ_HACK /* capabilities */ #undef HAVE_CAPABILITIES /* Define to 1 if your system has a working `chown' function. */ #undef HAVE_CHOWN /* Have monotonic clock */ #undef HAVE_CLOCK_MONOTONIC /* Define to 1 if you have the `daemon' function. */ #undef HAVE_DAEMON /* Define to 1 if you have the declaration of `TCP_MD5SIG', and to 0 if you don't. */ #undef HAVE_DECL_TCP_MD5SIG /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 /* Define to 1 if you have the `fcntl' function. */ #undef HAVE_FCNTL /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_FEATURES_H /* Define to 1 if your system has a working POSIX `fnmatch' function. */ #undef HAVE_FNMATCH /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Forwarding Plane Manager support */ #undef HAVE_FPM /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD /* Define to 1 if you have the `getgrouplist' function. */ #undef HAVE_GETGROUPLIST /* Define to 1 if you have the `gethostbyname' function. */ #undef HAVE_GETHOSTBYNAME /* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Glibc backtrace */ #undef HAVE_GLIBC_BACKTRACE /* GNU regexp library */ #undef HAVE_GNU_REGEX /* Define to 1 if you have the `if_indextoname' function. */ #undef HAVE_IF_INDEXTONAME /* Define to 1 if you have the `if_nametoindex' function. */ #undef HAVE_IF_NAMETOINDEX /* Define to 1 if you have the `inet_aton' function. */ #undef HAVE_INET_ATON /* Define to 1 if you have the header file. */ #undef HAVE_INET_ND_H /* Define to 1 if you have the `inet_ntoa' function. */ #undef HAVE_INET_NTOA /* inet_ntop */ #undef HAVE_INET_NTOP /* inet_pton */ #undef HAVE_INET_PTON /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* IPv6 */ #undef HAVE_IPV6 /* Have IP_PKTINFO */ #undef HAVE_IP_PKTINFO /* Have IP_RECVDSTADDR */ #undef HAVE_IP_RECVDSTADDR /* Have IP_RECVIF */ #undef HAVE_IP_RECVIF /* IRDP */ #undef HAVE_IRDP /* Define to 1 if you have the header file. */ #undef HAVE_KVM_H /* Capabilities */ #undef HAVE_LCAPS /* Define to 1 if you have the `crypt' library (-lcrypt). */ #undef HAVE_LIBCRYPT /* Have libm */ #undef HAVE_LIBM /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define to 1 if you have the `pcreposix' library (-lpcreposix). */ #undef HAVE_LIBPCREPOSIX /* 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 `umem' library (-lumem). */ #undef HAVE_LIBUMEM /* Define to 1 if you have the `xnet' library (-lxnet). */ #undef HAVE_LIBXNET /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_MROUTE_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_VERSION_H /* mallinfo */ #undef HAVE_MALLINFO /* Define to 1 if you have the `memchr' function. */ #undef HAVE_MEMCHR /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* 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_IN6_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET6_IN6_VAR_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_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_SYSTM_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_VAR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IP_ICMP_H /* netlink */ #undef HAVE_NETLINK /* Have netns */ #undef HAVE_NETNS /* 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_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 /* Define to 1 if you have the header file. */ #undef HAVE_NET_ROUTE_H /* NET_RT_IFLIST */ #undef HAVE_NET_RT_IFLIST /* Have openpam.h */ #undef HAVE_OPENPAM_H /* Have pam_misc.h */ #undef HAVE_PAM_MISC_H /* Define to 1 if you have the `pow' function. */ #undef HAVE_POW /* Solaris printstack */ #undef HAVE_PRINTSTACK /* Define to 1 if you have the header file. */ #undef HAVE_PRIV_H /* protobuf */ #undef HAVE_PROTOBUF /* prctl */ #undef HAVE_PR_SET_KEEPCAPS /* Have RFC3678 protocol-independed API */ #undef HAVE_RFC3678 /* Enable IPv6 Routing Advertisement support */ #undef HAVE_RTADV /* rusage */ #undef HAVE_RUSAGE /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 if you have the `setns' function. */ #undef HAVE_SETNS /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* SNMP */ #undef HAVE_SNMP /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if the system has the type `socklen_t'. */ #undef HAVE_SOCKLEN_T /* getpflags */ #undef HAVE_SOLARIS_CAPABILITIES /* Stack symbol decoding */ #undef HAVE_STACK_TRACE /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_STAT_EMPTY_STRING_BUG /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* 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 `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strcspn' function. */ #undef HAVE_STRCSPN /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* 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 `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP /* Define to 1 if you have the `strnlen' function. */ #undef HAVE_STRNLEN /* Define to 1 if you have the header file. */ #undef HAVE_STROPTS_H /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the `strspn' function. */ #undef HAVE_STRSPN /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the `strtoul' function. */ #undef HAVE_STRTOUL /* Define to 1 if the system has the type `struct icmphdr'. */ #undef HAVE_STRUCT_ICMPHDR /* Define to 1 if the system has the type `struct if6_aliasreq'. */ #undef HAVE_STRUCT_IF6_ALIASREQ /* Define to 1 if `ifra_lifetime' is a member of `struct if6_aliasreq'. */ #undef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME /* Define to 1 if the system has the type `struct ifaliasreq'. */ #undef HAVE_STRUCT_IFALIASREQ /* Define to 1 if `ifm_status' is a member of `struct ifmediareq'. */ #undef HAVE_STRUCT_IFMEDIAREQ_IFM_STATUS /* Define to 1 if `ifi_link_state' is a member of `struct if_data'. */ #undef HAVE_STRUCT_IF_DATA_IFI_LINK_STATE /* Define to 1 if the system has the type `struct igmpmsg'. */ #undef HAVE_STRUCT_IGMPMSG /* Define to 1 if the system has the type `struct in6_aliasreq'. */ #undef HAVE_STRUCT_IN6_ALIASREQ /* Define to 1 if the system has the type `struct in_pktinfo'. */ #undef HAVE_STRUCT_IN_PKTINFO /* Define to 1 if `imr_ifindex' is a member of `struct ip_mreqn'. */ #undef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX /* Define to 1 if the system has the type `struct mfcctl'. */ #undef HAVE_STRUCT_MFCCTL /* Define to 1 if the system has the type `struct nd_opt_adv_interval'. */ #undef HAVE_STRUCT_ND_OPT_ADV_INTERVAL /* Define to 1 if `nd_opt_ai_type' is a member of `struct nd_opt_adv_interval'. */ #undef HAVE_STRUCT_ND_OPT_ADV_INTERVAL_ND_OPT_AI_TYPE /* Define to 1 if the system has the type `struct nd_opt_homeagent_info'. */ #undef HAVE_STRUCT_ND_OPT_HOMEAGENT_INFO /* Define to 1 if the system has the type `struct rt_addrinfo'. */ #undef HAVE_STRUCT_RT_ADDRINFO /* Define to 1 if the system has the type `struct sioc_sg_req'. */ #undef HAVE_STRUCT_SIOC_SG_REQ /* Define to 1 if the system has the type `struct sioc_vif_req'. */ #undef HAVE_STRUCT_SIOC_VIF_REQ /* Define to 1 if the system has the type `struct sockaddr'. */ #undef HAVE_STRUCT_SOCKADDR /* Define to 1 if the system has the type `struct sockaddr_dl'. */ #undef HAVE_STRUCT_SOCKADDR_DL /* Define to 1 if `sdl_len' is a member of `struct sockaddr_dl'. */ #undef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN /* Define to 1 if the system has the type `struct sockaddr_in'. */ #undef HAVE_STRUCT_SOCKADDR_IN /* Define to 1 if the system has the type `struct sockaddr_in6'. */ #undef HAVE_STRUCT_SOCKADDR_IN6 /* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */ #undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID /* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */ #undef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN /* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ #undef HAVE_STRUCT_SOCKADDR_SA_LEN /* Define to 1 if the system has the type `struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN /* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN /* Define to 1 if the system has the type `struct vifctl'. */ #undef HAVE_STRUCT_VIFCTL /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_CAPABILITY_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_CDEFS_H /* 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_IOCTL_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_PARAM_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_SOCKET_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 /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define this if your system can create weak aliases */ #undef HAVE_SYS_WEAK_ALIAS /* Define this if weak aliases may be created with __attribute__ */ #undef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE /* Define this if weak aliases may be created with #pragma _CRI duplicate */ #undef HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE /* Define this if weak aliases in other files are honored */ #undef HAVE_SYS_WEAK_ALIAS_CROSSFILE /* Define this if weak aliases may be created with #pragma _HP_SECONDARY_DEF */ #undef HAVE_SYS_WEAK_ALIAS_HPSECONDARY /* Define this if weak aliases may be created with #pragma weak */ #undef HAVE_SYS_WEAK_ALIAS_PRAGMA /* Old Linux 2.4 TCP MD5 Signature Patch */ #undef HAVE_TCP_MD5_LINUX24 /* Use TCP for zebra communication */ #undef HAVE_TCP_ZEBRA /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_UCONTEXT_H /* Define to 1 if `uc_mcontext.gregs' is a member of `ucontext_t'. */ #undef HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS /* Define to 1 if `uc_mcontext.regs' is a member of `ucontext_t'. */ #undef HAVE_UCONTEXT_T_UC_MCONTEXT_REGS /* Define to 1 if `uc_mcontext.regs.nip' is a member of `ucontext_t'. */ #undef HAVE_UCONTEXT_T_UC_MCONTEXT_REGS_NIP /* Define to 1 if `uc_mcontext.uc_regs' is a member of `ucontext_t'. */ #undef HAVE_UCONTEXT_T_UC_MCONTEXT_UC_REGS /* Define to 1 if you have the `uname' function. */ #undef HAVE_UNAME /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if the system has the type `vifi_t'. */ #undef HAVE_VIFI_T /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H /* Define to 1 if you have the header file. */ #undef HAVE_WCTYPE_H /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL /* selected method for isis, == one of the constants */ #undef ISIS_METHOD /* constant value for isis method bpf */ #undef ISIS_METHOD_BPF /* constant value for isis method dlpi */ #undef ISIS_METHOD_DLPI /* constant value for isis method pfpacket */ #undef ISIS_METHOD_PFPACKET /* isisd vty socket */ #undef ISIS_VTYSH_PATH /* KAME IPv6 */ #undef KAME /* Linux IPv6 stack */ #undef LINUX_IPV6 /* Mask for log files */ #undef LOGFILE_MASK /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Maximum number of paths for a route */ #undef MULTIPATH_NUM /* nhrpd vty socket */ #undef NHRP_VTYSH_PATH /* OpenBSD */ #undef OPEN_BSD /* ospf6d vty socket */ #undef OSPF6_VTYSH_PATH /* ospfd vty socket */ #undef OSPF_VTYSH_PATH /* 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 home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Have openpam_ttyconv */ #undef PAM_CONV_FUNC /* bgpd PID */ #undef PATH_BGPD_PID /* isisd PID */ #undef PATH_ISISD_PID /* nhrpd PID */ #undef PATH_NHRPD_PID /* ospf6d PID */ #undef PATH_OSPF6D_PID /* ospfd PID */ #undef PATH_OSPFD_PID /* pimd PID */ #undef PATH_PIMD_PID /* ripd PID */ #undef PATH_RIPD_PID /* ripngd PID */ #undef PATH_RIPNGD_PID /* watchquagga PID */ #undef PATH_WATCHQUAGGA_PID /* zebra PID */ #undef PATH_ZEBRA_PID /* pimd vty socket */ #undef PIM_VTYSH_PATH /* Quagga Group */ #undef QUAGGA_GROUP /* Hide deprecated interfaces */ #undef QUAGGA_NO_DEPRECATED_INTERFACES /* Quagga User */ #undef QUAGGA_USER /* ripng vty socket */ #undef RIPNG_VTYSH_PATH /* rip vty socket */ #undef RIP_VTYSH_PATH /* Define to the type of arg 1 for `select'. */ #undef SELECT_TYPE_ARG1 /* Define to the type of args 2, 3 and 4 for `select'. */ #undef SELECT_TYPE_ARG234 /* Define to the type of arg 5 for `select'. */ #undef SELECT_TYPE_ARG5 /* Use SNMP AgentX to interface with snmpd */ #undef SNMP_AGENTX /* Use SNMP SMUX to interface with snmpd */ #undef SNMP_SMUX /* Solaris IPv6 */ #undef SOLARIS_IPV6 /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* SunOS 5 */ #undef SUNOS_5 /* SunOS 5.6 to 5.7 */ #undef SUNOS_56 /* SunOS 5.8 up */ #undef SUNOS_59 /* OSPFAPI */ #undef SUPPORT_OSPF_API /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Enable IS-IS topology generator code */ #undef TOPOLOGY_GENERATE /* Use PAM for authentication */ #undef USE_PAM /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Version number of package */ #undef VERSION /* VTY shell */ #undef VTYSH /* VTY Sockets Group */ #undef VTY_GROUP /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* zebra api socket */ #undef ZEBRA_SERV_PATH /* zebra vty socket */ #undef ZEBRA_VTYSH_PATH /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to 1 if on MINIX. */ #undef _MINIX /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE /* Define to 1 if you need to in order for `stat' and other things to work. */ #undef _POSIX_SOURCE /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to `int' if does not define. */ #undef mode_t /* Define to `int' if does not define. */ #undef pid_t /* Define to the equivalent of the C99 'restrict' keyword, or to nothing if this is not supported. Do not define if restrict is supported directly. */ #undef restrict /* Work around a bug in Sun C++: it does not support _Restrict or __restrict__, even though the corresponding Sun C compiler ends up with "#define restrict _Restrict" or "#define restrict __restrict__" in the previous line. Perhaps some future version of Sun C++ will work with restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ #if defined __SUNPRO_CC && !defined __RESTRICT # define _Restrict # define __restrict__ #endif /* Old readline */ #undef rl_completion_matches /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if doesn't define. */ #undef uid_t /* Define as `fork' if `vfork' does not work. */ #undef vfork /* Define to empty if the keyword `volatile' does not work. Warning: valid code using `volatile' can become incorrect without. Disable with care. */ #undef volatile quagga-1.2.4/config.sub000077500000000000000000001067371325323223500147640ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2016 Free Software Foundation, Inc. timestamp='2016-09-05' # 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 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # 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. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # 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 or ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) 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* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) 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 | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -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/'` ;; -sco5v6*) # 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*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -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. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # 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*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. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # 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 ;; abacus) basic_machine=abacus-unknown ;; 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 ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; 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 ;; aros) basic_machine=i386-pc os=-aros ;; asmjs) basic_machine=asmjs-unknown ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; 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 | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` os=$os"spe" ;; 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 ;; go32) basic_machine=i386-pc os=-go32 ;; 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*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*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 ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; 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 ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; 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 ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-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 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; 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=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; 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 ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-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 ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) 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 ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) 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. -auroraux) os=-auroraux ;; -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* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | -onefs* | -tirtos* | -phoenix*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -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 ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -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[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -ios) ;; -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 score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-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 ;; f30[01]-fujitsu | f700-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 ;; -cnk*|-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 ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: quagga-1.2.4/configure000077500000000000000000027523741325323223500147160ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for Quagga 1.2.4. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 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 more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= 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 IFS=$as_save_IFS ;; 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 $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: https://bugzilla.quagga.net about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; 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 if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # 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 as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # 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 sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # 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'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Quagga' PACKAGE_TARNAME='quagga' PACKAGE_VERSION='1.2.4' PACKAGE_STRING='Quagga 1.2.4' PACKAGE_BUGREPORT='https://bugzilla.quagga.net' PACKAGE_URL='' ac_unique_file="lib/zebra.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_list= ac_func_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS quagga_statedir CONFDATE WEAK_ALIAS_CROSSFILE WEAK_ALIAS LIBCAP NETSNMP_CONFIG CARES_LIBS CARES_CFLAGS LIB_REGEX HAVE_LIBPCREPOSIX OSPFAPI OSPFCLIENT CURSES VTYSH SOLARIS PIMD ISISD WATCHQUAGGA NHRPD OSPF6D OSPFD RIPNGD RIPD BGPD ZEBRA DOC PIMD_FALSE PIMD_TRUE ISISD_FALSE ISISD_TRUE OSPF6D_FALSE OSPF6D_TRUE RIPNGD_FALSE RIPNGD_TRUE OSPFCLIENT_FALSE OSPFCLIENT_TRUE WATCHQUAGGA_FALSE WATCHQUAGGA_TRUE NHRPD_FALSE NHRPD_TRUE OSPFD_FALSE OSPFD_TRUE RIPD_FALSE RIPD_TRUE BGPD_FALSE BGPD_TRUE ZEBRA_FALSE ZEBRA_TRUE IPFORWARD IOCTL_METHOD IF_METHOD RTREAD_METHOD HAVE_NETLINK_FALSE HAVE_NETLINK_TRUE KERNEL_METHOD RT_METHOD LIBM LIBOBJS LIBPAM VTYSH_FALSE VTYSH_TRUE LIBREADLINE GIT_VERSION_FALSE GIT_VERSION_TRUE enable_vty_group enable_group enable_user ISIS_TOPOLOGY_LIB ISIS_TOPOLOGY_DIR ISIS_TOPOLOGY_INCLUDES HAVE_PROTOBUF_FALSE HAVE_PROTOBUF_TRUE PROTOBUF_C_LIBS PROTOBUF_C_CFLAGS PROTOC_C DEV_BUILD_FALSE DEV_BUILD_TRUE WERROR HAVE_PANDOC_FALSE HAVE_PANDOC_TRUE PANDOC HAVE_LATEX_FALSE HAVE_LATEX_TRUE LATEXMK PDFLATEX LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP SED LIBTOOL PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG EGREP GREP CPP am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC pkgsrcrcdir pkgsrcdir exampledir GAWK PERL AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build CONFIG_ARGS target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_exampledir enable_pkgsrcrcdir with_cflags enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_aix_soname with_gnu_ld with_sysroot enable_libtool_lock with_pkg_extra_version with_pkg_git_version enable_vtysh enable_doc enable_zebra enable_bgpd enable_ripd enable_ripngd enable_ospfd enable_ospf6d enable_nhrpd enable_watchquagga enable_isisd enable_pimd enable_bgp_announce enable_snmp with_libpam enable_tcp_zebra enable_ospfapi enable_ospfclient enable_multipath enable_user enable_group enable_vty_group enable_configfile_mask enable_logfile_mask enable_rtadv enable_irdp enable_isis_topology enable_capabilities enable_rusage enable_gcc_ultra_verbose enable_linux24_tcp_md5 enable_gcc_rdynamic enable_backtrace enable_time_check enable_pcreposix enable_fpm enable_werror enable_protobuf enable_dev_build enable_largefile ' ac_precious_vars='build_alias host_alias target_alias GAWK CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR LT_SYS_LIBRARY_PATH PROTOBUF_C_CFLAGS PROTOBUF_C_LIBS CARES_CFLAGS CARES_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # 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. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= 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 case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -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) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$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 ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$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 ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) 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 ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$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_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=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 ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_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'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" 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 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 ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # 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 the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | 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 test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # 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 Quagga 1.2.4 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 \`..'] 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] --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] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/quagga] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _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] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Quagga 1.2.4:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-exampledir specify alternate directory for examples --enable-pkgsrcrcdir specify directory for rc.d scripts --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-vtysh do not build integrated vty shell for Quagga --disable-doc do not build docs --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 --disable-nhrpd do not build nhrpd --disable-watchquagga do not build watchquagga --disable-isisd do not build isisd --disable-pimd do not build pimd --disable-bgp-announce, turn off BGP route announcement --enable-snmp=ARG enable SNMP support (smux or agentx) --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon --disable-ospfapi do not build OSPFAPI to access the OSPF LSA Database --disable-ospfclient do not build OSPFAPI client for OSPFAPI, (this is the default if --disable-ospfapi is set) --enable-multipath=ARG enable multipath function, ARG must be digit --enable-user=USER user to run Quagga suite as (default quagga) --enable-group=GROUP group to run Quagga suite as (default quagga) --enable-vty-group=ARG set vty sockets to have specified group as owner --enable-configfile-mask=ARG set mask for config files --enable-logfile-mask=ARG set mask for log files --disable-rtadv disable IPV6 router advertisement feature --enable-irdp enable IRDP server support in zebra --enable-isis-topology enable IS-IS topology generator --disable-capabilities disable using POSIX capabilities --disable-rusage disable using getrusage --enable-gcc-ultra-verbose enable ultra verbose GCC warnings --enable-linux24-tcp-md5 enable support for old, Linux-2.4 RFC2385 patch --enable-gcc-rdynamic enable linking with -rdynamic for better backtraces (default if gcc) --disable-backtrace, disable crash backtraces (default autodetect) --disable-time-check disable slow thread warning messages --enable-pcreposix enable using PCRE Posix libs for regex functions --enable-fpm enable Forwarding Plane Manager support --enable-werror enable -Werror (recommended for developers only) --enable-protobuf Enable experimental protobuf support --enable-dev-build build for development --disable-largefile omit support for large files 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-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, [default=aix]. --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-pkg-extra-version=VER add extra version field, for packagers/distributions --with-pkg-git-version add git information to MOTD and build version string --with-libpam use libpam for PAM support in vtysh Some influential environment variables: GAWK GNU AWK CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path LT_SYS_LIBRARY_PATH User-defined run-time library search path. PROTOBUF_C_CFLAGS C compiler flags for PROTOBUF_C, overriding pkg-config PROTOBUF_C_LIBS linker flags for PROTOBUF_C, overriding pkg-config CARES_CFLAGS C compiler flags for CARES, overriding pkg-config CARES_LIBS linker flags for CARES, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested 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 else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF Quagga configure 1.2.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 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 fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------------ ## ## Report this to https://bugzilla.quagga.net ## ## ------------------------------------------ ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* 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_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Quagga $as_me 1.2.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { 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` /usr/bin/hostinfo = `(/usr/bin/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=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&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_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=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append 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 as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset 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: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > 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 cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } 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. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_list " sys/time.h" as_fn_append ac_header_list " unistd.h" as_fn_append ac_func_list " alarm" # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; 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,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_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 # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_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. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## 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 CONFIG_ARGS="$*" 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 as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- # Disable portability warnings -- our automake code (in particular # common.am) uses some constructs specific to gmake. am__api_version='1.15' # 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. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&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_fn_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 rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir 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. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$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' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # 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 ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file 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 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". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file 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 $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='quagga' VERSION='1.2.4' 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"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=0;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' ac_config_headers="$ac_config_headers config.h" # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PERL+:} false; then : $as_echo_n "(cached) " >&6 else case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 $as_echo "$PERL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "gawk", so it can be a program name with args. set dummy gawk; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_GAWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$GAWK"; then ac_cv_prog_GAWK="$GAWK" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_GAWK="gawk" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_GAWK" && ac_cv_prog_GAWK="not-in-PATH" fi fi GAWK=$ac_cv_prog_GAWK if test -n "$GAWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GAWK" >&5 $as_echo "$GAWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$GAWK" = "xnot-in-PATH" ; then as_fn_error $? "GNU awk is required for lib/memtype.h made by memtypes.awk. BSD awk complains: awk: gensub doesn't support backreferences (subst \"\1\") " "$LINENO" 5 fi exampledir=${sysconfdir} # Check whether --enable-exampledir was given. if test "${enable_exampledir+set}" = set; then : enableval=$enable_exampledir; exampledir="$enableval" fi pkgsrcrcdir="" pkgsrcdir="" # Check whether --enable-pkgsrcrcdir was given. if test "${enable_pkgsrcrcdir+set}" = set; then : enableval=$enable_pkgsrcrcdir; pkgsrcrcdir="$enableval"; pkgsrcdir="pkgsrc" fi # Check whether --with-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 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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&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_fn_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" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; 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 | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* 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 -std 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 -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 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 for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : 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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" 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 DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-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='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&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". rm -rf conftest.dir 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 # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub 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 am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # 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. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # 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. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; 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 ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; } if ${ac_cv_prog_cc_c99+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy. static void test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str; int number; float fnumber; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. test_varargs ("s, d' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c99" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 $as_echo "$ac_cv_prog_cc_c99" >&6; } ;; esac if test "x$ac_cv_prog_cc_c99" != xno; then : fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #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)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h 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=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" if test "x$ac_cv_header_minix_config_h" = xyes; then : MINIX=yes else MINIX= fi if test "$MINIX" = yes; then $as_echo "#define _POSIX_SOURCE 1" >>confdefs.h $as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h $as_echo "#define _MINIX 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } if ${ac_cv_safe_to_define___extensions__+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_safe_to_define___extensions__=yes else ac_cv_safe_to_define___extensions__=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 $as_echo "$ac_cv_safe_to_define___extensions__" >&6; } test $ac_cv_safe_to_define___extensions__ = yes && $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h $as_echo "#define _ALL_SOURCE 1" >>confdefs.h $as_echo "#define _GNU_SOURCE 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.6' macro_revision='2.4.6' ltmain=$ac_aux_dir/ltmain.sh # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case $ECHO in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST 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_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n "$lt_cv_sys_max_cmd_len"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; then reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 $as_echo "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 $as_echo_n "checking for a working dd... " >&6; } if ${ac_cv_path_lt_DD+:} false; then : $as_echo_n "(cached) " >&6 else printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_found=false # Loop through the user's path and test for each of PROGNAME-LIST 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_prog in dd; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 $as_echo "$ac_cv_path_lt_DD" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 $as_echo_n "checking how to truncate binary pipes... " >&6; } if ${lt_cv_truncate_bin+:} false; then : $as_echo_n "(cached) " >&6 else printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 $as_echo "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else 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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext 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 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[012][,.]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac else pic_mode=default fi # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac else enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 $as_echo_n "checking which variant of shared library versioning to provide... " >&6; } # Check whether --with-aix-soname was given. if test "${with_aix_soname+set}" = set; then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else if ${lt_cv_with_aix_soname+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 $as_echo "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o func_cc_basename $compiler cc_basename=$func_cc_basename_result # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/${ac_tool_prefix}file"; then lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/file"; then lt_cv_path_MAGIC_CMD=$ac_dir/"file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC=$CC 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 # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test no = "$hard_links"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='$wl--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' link_all_deplibs=yes ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) export_dynamic_flag_spec='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test no = "$ld_shlibs"; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi export_dynamic_flag_spec='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' $wl-bernotok' allow_undefined_flag=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test yes = "$lt_cv_ld_force_load"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test yes = "$GCC"; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; then archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' else archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes ;; osf3*) if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test yes = "$GCC"; then wlarc='$wl' archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='$wl-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='$wl-z,text' allow_undefined_flag='$wl-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test no = "$ld_shlibs" && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test yes,yes = "$GCC,$enable_shared"; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([A-Za-z]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Add ABI-specific directories to the system library path. sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen=shl_load else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen=dlopen else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld fi fi fi fi fi fi ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test yes = "$cross_compiling"; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test yes = "$cross_compiling"; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report what library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } 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 CC=$lt_save_CC ac_config_commands="$ac_config_commands libtool" # Only expand once: : ${CONFIG_LT=./config.lt} { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_LT" >&5 $as_echo "$as_me: creating $CONFIG_LT" >&6;} as_write_fail=0 cat >"$CONFIG_LT" <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate a libtool stub with the current configuration. SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>"$CONFIG_LT" <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= 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 IFS=$as_save_IFS ;; 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 $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; 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 if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # 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 ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # 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'" exec 6>&1 ## --------------------------------- ## ## Main body of "$CONFIG_LT" script. ## ## --------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x "$CONFIG_LT" cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $0 [OPTIONS] -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 Report bugs to ." lt_cl_version="\ Quagga config.lt 1.2.4 configured by $0, generated by GNU Autoconf 2.69. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $# do case $1 in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) as_fn_error $? "unrecognized option: $1 Try '$0 --help' for more information." "$LINENO" 5 ;; *) as_fn_error $? "unrecognized argument: $1 Try '$0 --help' for more information." "$LINENO" 5 ;; esac shift done if $lt_cl_silent; then exec 6>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile' _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ofile" >&5 $as_echo "$as_me: creating $ofile" >&6;} # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain=$ac_aux_dir/ltmain.sh # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" as_fn_exit 0 _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec 5>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec 5>>config.log $lt_cl_success || as_fn_exit 1 # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_SED+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$SED"; then ac_cv_prog_SED="$SED" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_SED="sed" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_SED" && ac_cv_prog_SED="/bin/false" fi fi SED=$ac_cv_prog_SED if test -n "$SED"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 $as_echo "$SED" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "pdflatex", so it can be a program name with args. set dummy pdflatex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PDFLATEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PDFLATEX"; then ac_cv_prog_PDFLATEX="$PDFLATEX" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PDFLATEX="pdflatex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_PDFLATEX" && ac_cv_prog_PDFLATEX="/bin/false" fi fi PDFLATEX=$ac_cv_prog_PDFLATEX if test -n "$PDFLATEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5 $as_echo "$PDFLATEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "latexmk", so it can be a program name with args. set dummy latexmk; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LATEXMK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LATEXMK"; then ac_cv_prog_LATEXMK="$LATEXMK" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LATEXMK="latexmk" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_LATEXMK" && ac_cv_prog_LATEXMK="/bin/false" fi fi LATEXMK=$ac_cv_prog_LATEXMK if test -n "$LATEXMK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LATEXMK" >&5 $as_echo "$LATEXMK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$PDFLATEX" = "x/bin/false" -o "x$LATEXMK" = "x/bin/false"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Will not be able to make PDF versions of TeX documents" >&5 $as_echo "$as_me: WARNING: Will not be able to make PDF versions of TeX documents" >&2;} else HAVE_LATEX=true fi if test "x$HAVE_LATEX" = "xtrue"; then HAVE_LATEX_TRUE= HAVE_LATEX_FALSE='#' else HAVE_LATEX_TRUE='#' HAVE_LATEX_FALSE= fi # Extract the first word of "pandoc", so it can be a program name with args. set dummy pandoc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PANDOC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PANDOC"; then ac_cv_prog_PANDOC="$PANDOC" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PANDOC="pandoc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_PANDOC" && ac_cv_prog_PANDOC="/bin/false" fi fi PANDOC=$ac_cv_prog_PANDOC if test -n "$PANDOC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PANDOC" >&5 $as_echo "$PANDOC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$PDFLATEX" = "x/bin/false" -o "x$PANDOC" = "x/bin/false"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Will not be able to make PDF versions of MD documents" >&5 $as_echo "$as_me: WARNING: Will not be able to make PDF versions of MD documents" >&2;} else HAVE_PANDOC=true fi if test "x$HAVE_PANDOC" = "xtrue"; then HAVE_PANDOC_TRUE= HAVE_PANDOC_FALSE='#' else HAVE_PANDOC_TRUE='#' HAVE_PANDOC_FALSE= fi if test "x${GCC}" != "xyes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using SunPro compiler" >&5 $as_echo_n "checking whether we are using SunPro compiler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ "__SUNPRO_C" __SUNPRO_C _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "^__SUNPRO_C.*0x5(7|8|9)" >/dev/null 2>&1; then : COMPILER="SUNPRO" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking which default CFLAGS to set" >&5 $as_echo_n "checking which default CFLAGS to set... " >&6; } if test "x${cflags_specified}" = "x" ; then case ${COMPILER} in "SUNPRO") { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sun Studio" >&5 $as_echo "Sun Studio" >&6; } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -g" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -g" >&5 $as_echo_n "checking whether $CC supports -g... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -xO4" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -xO4" >&5 $as_echo_n "checking whether $CC supports -xO4... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -xspace" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -xspace" >&5 $as_echo_n "checking whether $CC supports -xspace... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -xstrconst" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -xstrconst" >&5 $as_echo_n "checking whether $CC supports -xstrconst... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -xc99" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -xc99" >&5 $as_echo_n "checking whether $CC supports -xc99... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -errfmt" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -errfmt" >&5 $as_echo_n "checking whether $CC supports -errfmt... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -xipo" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -xipo" >&5 $as_echo_n "checking whether $CC supports -xipo... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: autodetecting" >&5 $as_echo "autodetecting" >&6; } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -diag-error 10006" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -diag-error 10006" >&5 $as_echo_n "checking whether $CC supports -diag-error 10006... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -g" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -g" >&5 $as_echo_n "checking whether $CC supports -g... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Os" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Os" >&5 $as_echo_n "checking whether $CC supports -Os... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -O2" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -O2" >&5 $as_echo_n "checking whether $CC supports -O2... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } fi rm -f core 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 } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libtool can support fstack-protector" >&5 $as_echo_n "checking whether libtool can support fstack-protector... " >&6; } if test x"$(./libtool --version | awk 'NR == 1 { print $NF }' \ | awk -F. '{ \ if ($(NF-2) < 2) print 0; \ else if ($(NF-2) > 2) print 1; \ else if ($(NF-1) < 4) print 0; \ else if ($(NF-1) > 4) print 1; \ else if ($NF < 6) print 0; \ else print 1; \ }')" = "x1" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -fstack-protector-strong" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fstack-protector-strong" >&5 $as_echo_n "checking whether $CC supports -fstack-protector-strong... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS --param=ssp-buffer-size=4" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports --param=ssp-buffer-size=4" >&5 $as_echo_n "checking whether $CC supports --param=ssp-buffer-size=4... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: upgrade to libtool >= 2.4.6!" >&5 $as_echo "$as_me: WARNING: upgrade to libtool >= 2.4.6!" >&2;} 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -D_FORTIFY_SOURCE=2" >&5 $as_echo_n "checking whether $CC supports -D_FORTIFY_SOURCE=2... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wformat" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wformat" >&5 $as_echo_n "checking whether $CC supports -Wformat... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wformat-security" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wformat-security" >&5 $as_echo_n "checking whether $CC supports -Wformat-security... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -fpie" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fpie" >&5 $as_echo_n "checking whether $CC supports -fpie... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -fno-omit-frame-pointer" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fno-omit-frame-pointer" >&5 $as_echo_n "checking whether $CC supports -fno-omit-frame-pointer... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wall" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wall" >&5 $as_echo_n "checking whether $CC supports -Wall... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wextra" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wextra" >&5 $as_echo_n "checking whether $CC supports -Wextra... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wmissing-prototypes" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wmissing-prototypes" >&5 $as_echo_n "checking whether $CC supports -Wmissing-prototypes... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wmissing-declarations" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wmissing-declarations" >&5 $as_echo_n "checking whether $CC supports -Wmissing-declarations... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wpointer-arith" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpointer-arith" >&5 $as_echo_n "checking whether $CC supports -Wpointer-arith... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wbad-function-cast" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wbad-function-cast" >&5 $as_echo_n "checking whether $CC supports -Wbad-function-cast... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wwrite-strings" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wwrite-strings" >&5 $as_echo_n "checking whether $CC supports -Wwrite-strings... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wcast-qual" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wcast-qual" >&5 $as_echo_n "checking whether $CC supports -Wcast-qual... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wstrict-prototypes" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wstrict-prototypes" >&5 $as_echo_n "checking whether $CC supports -Wstrict-prototypes... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wmissing-noreturn" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wmissing-noreturn" >&5 $as_echo_n "checking whether $CC supports -Wmissing-noreturn... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wmissing-format-attribute" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wmissing-format-attribute" >&5 $as_echo_n "checking whether $CC supports -Wmissing-format-attribute... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wunreachable-code" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wunreachable-code" >&5 $as_echo_n "checking whether $CC supports -Wunreachable-code... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wpacked" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpacked" >&5 $as_echo_n "checking whether $CC supports -Wpacked... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wpadded" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpadded" >&5 $as_echo_n "checking whether $CC supports -Wpadded... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } else { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wno-unused-result" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-unused-result" >&5 $as_echo_n "checking whether $CC supports -Wno-unused-result... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wno-unused-parameter" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-unused-parameter" >&5 $as_echo_n "checking whether $CC supports -Wno-unused-parameter... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -Wno-missing-field-initializers" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-missing-field-initializers" >&5 $as_echo_n "checking whether $CC supports -Wno-missing-field-initializers... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } # ICC emits a broken warning for const char *x = a ? "b" : "c"; # for some reason the string consts get 'promoted' to char *, # triggering a const to non-const conversion warning. { 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 ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS -diag-disable 3179" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -diag-disable 3179" >&5 $as_echo_n "checking whether $CC supports -diag-disable 3179... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CFLAGS="$ac_c_flag_save" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core 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 } ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: result: CFLAGS supplied by user" >&5 $as_echo "CFLAGS supplied by user" >&6; } fi if test x"${enable_werror}" = x"yes" ; then WERROR="-Werror" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ${MAKE-make} is GNU make" >&5 $as_echo_n "checking if ${MAKE-make} is GNU make... " >&6; } if ${quagga_cv_gnu_make+:} false; then : $as_echo_n "(cached) " >&6 else quagga_cv_gnu_make=no if ${MAKE-make} --version 2>/dev/null | \ grep '^GNU Make ' >/dev/null ; then quagga_cv_gnu_make=yes; fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $quagga_cv_gnu_make" >&5 $as_echo "$quagga_cv_gnu_make" >&6; } # Check whether --with-pkg-extra-version was given. if test "${with_pkg_extra_version+set}" = set; then : withval=$with_pkg_extra_version; EXTRAVERSION=$withval fi # Check whether --with-pkg-git-version was given. if test "${with_pkg_git_version+set}" = set; then : withval=$with_pkg_git_version; test "x$withval" != "xno" && with_pkg_git_version="yes" fi # Check whether --enable-vtysh was given. if test "${enable_vtysh+set}" = set; then : enableval=$enable_vtysh; fi # Check whether --enable-doc was given. if test "${enable_doc+set}" = set; then : enableval=$enable_doc; fi # Check whether --enable-zebra was given. if test "${enable_zebra+set}" = set; then : enableval=$enable_zebra; fi # Check whether --enable-bgpd was given. if test "${enable_bgpd+set}" = set; then : enableval=$enable_bgpd; fi # Check whether --enable-ripd was given. if test "${enable_ripd+set}" = set; then : enableval=$enable_ripd; fi # Check whether --enable-ripngd was given. if test "${enable_ripngd+set}" = set; then : enableval=$enable_ripngd; fi # Check whether --enable-ospfd was given. if test "${enable_ospfd+set}" = set; then : enableval=$enable_ospfd; fi # Check whether --enable-ospf6d was given. if test "${enable_ospf6d+set}" = set; then : enableval=$enable_ospf6d; fi # Check whether --enable-nhrpd was given. if test "${enable_nhrpd+set}" = set; then : enableval=$enable_nhrpd; fi # Check whether --enable-watchquagga was given. if test "${enable_watchquagga+set}" = set; then : enableval=$enable_watchquagga; fi # Check whether --enable-isisd was given. if test "${enable_isisd+set}" = set; then : enableval=$enable_isisd; fi # Check whether --enable-pimd was given. if test "${enable_pimd+set}" = set; then : enableval=$enable_pimd; fi # Check whether --enable-bgp-announce was given. if test "${enable_bgp_announce+set}" = set; then : enableval=$enable_bgp_announce; fi # Check whether --enable-snmp was given. if test "${enable_snmp+set}" = set; then : enableval=$enable_snmp; fi # Check whether --with-libpam was given. if test "${with_libpam+set}" = set; then : withval=$with_libpam; fi # Check whether --enable-tcp-zebra was given. if test "${enable_tcp_zebra+set}" = set; then : enableval=$enable_tcp_zebra; fi # Check whether --enable-ospfapi was given. if test "${enable_ospfapi+set}" = set; then : enableval=$enable_ospfapi; fi # Check whether --enable-ospfclient was given. if test "${enable_ospfclient+set}" = set; then : enableval=$enable_ospfclient; fi # Check whether --enable-multipath was given. if test "${enable_multipath+set}" = set; then : enableval=$enable_multipath; fi # Check whether --enable-user was given. if test "${enable_user+set}" = set; then : enableval=$enable_user; fi # Check whether --enable-group was given. if test "${enable_group+set}" = set; then : enableval=$enable_group; fi # Check whether --enable-vty_group was given. if test "${enable_vty_group+set}" = set; then : enableval=$enable_vty_group; fi # Check whether --enable-configfile_mask was given. if test "${enable_configfile_mask+set}" = set; then : enableval=$enable_configfile_mask; fi # Check whether --enable-logfile_mask was given. if test "${enable_logfile_mask+set}" = set; then : enableval=$enable_logfile_mask; fi # Check whether --enable-rtadv was given. if test "${enable_rtadv+set}" = set; then : enableval=$enable_rtadv; fi # Check whether --enable-irdp was given. if test "${enable_irdp+set}" = set; then : enableval=$enable_irdp; fi # Check whether --enable-isis_topology was given. if test "${enable_isis_topology+set}" = set; then : enableval=$enable_isis_topology; fi # Check whether --enable-capabilities was given. if test "${enable_capabilities+set}" = set; then : enableval=$enable_capabilities; fi # Check whether --enable-rusage was given. if test "${enable_rusage+set}" = set; then : enableval=$enable_rusage; fi # Check whether --enable-gcc_ultra_verbose was given. if test "${enable_gcc_ultra_verbose+set}" = set; then : enableval=$enable_gcc_ultra_verbose; fi # Check whether --enable-linux24_tcp_md5 was given. if test "${enable_linux24_tcp_md5+set}" = set; then : enableval=$enable_linux24_tcp_md5; fi # Check whether --enable-gcc-rdynamic was given. if test "${enable_gcc_rdynamic+set}" = set; then : enableval=$enable_gcc_rdynamic; fi # Check whether --enable-backtrace was given. if test "${enable_backtrace+set}" = set; then : enableval=$enable_backtrace; fi # Check whether --enable-time-check was given. if test "${enable_time_check+set}" = set; then : enableval=$enable_time_check; fi # Check whether --enable-pcreposix was given. if test "${enable_pcreposix+set}" = set; then : enableval=$enable_pcreposix; fi # Check whether --enable-fpm was given. if test "${enable_fpm+set}" = set; then : enableval=$enable_fpm; fi # Check whether --enable-werror was given. if test "${enable_werror+set}" = set; then : enableval=$enable_werror; fi # Check whether --enable-protobuf was given. if test "${enable_protobuf+set}" = set; then : enableval=$enable_protobuf; fi # Check whether --enable-dev_build was given. if test "${enable_dev_build+set}" = set; then : enableval=$enable_dev_build; fi if test x"${enable_gcc_rdynamic}" != x"no" ; then if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then LDFLAGS="${LDFLAGS} -rdynamic" fi fi if test x"${enable_time_check}" != x"no" ; then if test x"${enable_time_check}" = x"yes" -o x"${enable_time_check}" = x ; then $as_echo "#define CONSUMED_TIME_CHECK 5000000" >>confdefs.h else cat >>confdefs.h <<_ACEOF #define CONSUMED_TIME_CHECK $enable_time_check _ACEOF fi fi if test "${enable_fpm}" = "yes"; then $as_echo "#define HAVE_FPM /**/" >>confdefs.h fi if test "x${enable_dev_build}" = "xyes"; then $as_echo "#define DEV_BUILD /**/" >>confdefs.h fi if test "x$enable_dev_build" = "xyes"; then DEV_BUILD_TRUE= DEV_BUILD_FALSE='#' else DEV_BUILD_TRUE='#' DEV_BUILD_FALSE= fi # # Logic for protobuf support. # if test "$enable_protobuf" = "yes"; then have_protobuf=yes # Check for protoc-c # Extract the first word of "protoc-c", so it can be a program name with args. set dummy protoc-c; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PROTOC_C+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PROTOC_C"; then ac_cv_prog_PROTOC_C="$PROTOC_C" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PROTOC_C="protoc-c" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_PROTOC_C" && ac_cv_prog_PROTOC_C="/bin/false" fi fi PROTOC_C=$ac_cv_prog_PROTOC_C if test -n "$PROTOC_C"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROTOC_C" >&5 $as_echo "$PROTOC_C" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$PROTOC_C" = "x/bin/false"; then have_protobuf=no else found_protobuf_c=no pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PROTOBUF_C" >&5 $as_echo_n "checking for PROTOBUF_C... " >&6; } if test -n "$PROTOBUF_C_CFLAGS"; then pkg_cv_PROTOBUF_C_CFLAGS="$PROTOBUF_C_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libprotobuf-c >= 0.14\""; } >&5 ($PKG_CONFIG --exists --print-errors "libprotobuf-c >= 0.14") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PROTOBUF_C_CFLAGS=`$PKG_CONFIG --cflags "libprotobuf-c >= 0.14" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PROTOBUF_C_LIBS"; then pkg_cv_PROTOBUF_C_LIBS="$PROTOBUF_C_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libprotobuf-c >= 0.14\""; } >&5 ($PKG_CONFIG --exists --print-errors "libprotobuf-c >= 0.14") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PROTOBUF_C_LIBS=`$PKG_CONFIG --libs "libprotobuf-c >= 0.14" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PROTOBUF_C_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libprotobuf-c >= 0.14" 2>&1` else PROTOBUF_C_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libprotobuf-c >= 0.14" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PROTOBUF_C_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: pkg-config did not find libprotobuf-c" >&5 $as_echo "pkg-config did not find libprotobuf-c" >&6; } elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: pkg-config did not find libprotobuf-c" >&5 $as_echo "pkg-config did not find libprotobuf-c" >&6; } else PROTOBUF_C_CFLAGS=$pkg_cv_PROTOBUF_C_CFLAGS PROTOBUF_C_LIBS=$pkg_cv_PROTOBUF_C_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } found_protobuf_c=yes fi if test "x$found_protobuf_c" = "xyes"; then LDFLAGS="$LDFLAGS $PROTOBUF_C_LIBS" CFLAGS="$CFLAGS $PROTOBUF_C_CFLAGS" else ac_fn_c_check_header_mongrel "$LINENO" "google/protobuf-c/protobuf-c.h" "ac_cv_header_google_protobuf_c_protobuf_c_h" "$ac_includes_default" if test "x$ac_cv_header_google_protobuf_c_protobuf_c_h" = xyes; then : else have_protobuf=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: Couldn't find google/protobuf-c.h" >&5 $as_echo "Couldn't find google/protobuf-c.h" >&6; } fi fi fi fi # Fail if the user explicity enabled protobuf support and we couldn't # find the compiler or libraries. if test "x$have_protobuf" = "xno" && test "x$enable_protobuf" = "xyes"; then as_fn_error $? "Protobuf enabled explicitly but can't find libraries/tools" "$LINENO" 5 fi if test "x$have_protobuf" = "xyes"; then $as_echo "#define HAVE_PROTOBUF /**/" >>confdefs.h fi if test "x$have_protobuf" = "xyes"; then HAVE_PROTOBUF_TRUE= HAVE_PROTOBUF_FALSE='#' else HAVE_PROTOBUF_TRUE='#' HAVE_PROTOBUF_FALSE= fi # # End of logic for protobuf support. # if test "${enable_tcp_zebra}" = "yes"; then $as_echo "#define HAVE_TCP_ZEBRA /**/" >>confdefs.h fi if test "${enable_linux24_tcp_md5}" = "yes"; then $as_echo "#define HAVE_TCP_MD5_LINUX24 /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if zebra should be configurable to send Route Advertisements" >&5 $as_echo_n "checking if zebra should be configurable to send Route Advertisements... " >&6; } if test "${enable_rtadv}" != "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_RTADV /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${enable_irdp}" = "yes"; then $as_echo "#define HAVE_IRDP /**/" >>confdefs.h fi if test "${enable_isisd}" != "no" && test "${enable_isis_topology}" = yes; then $as_echo "#define TOPOLOGY_GENERATE /**/" >>confdefs.h ISIS_TOPOLOGY_INCLUDES="-I\$(srcdir)/topology" ISIS_TOPOLOGY_DIR="topology" ISIS_TOPOLOGY_LIB="./topology/libtopology.a" fi if test x"${enable_user}" = x"no"; then enable_user="" else if test x"${enable_user}" = x"yes" || test x"${enable_user}" = x""; then enable_user="quagga" fi cat >>confdefs.h <<_ACEOF #define QUAGGA_USER "${enable_user}" _ACEOF fi if test x"${enable_group}" = x"no"; then enable_group="" else if test x"${enable_group}" = x"yes" || test x"${enable_group}" = x""; then enable_group="quagga" fi cat >>confdefs.h <<_ACEOF #define QUAGGA_GROUP "${enable_group}" _ACEOF fi if test x"${enable_vty_group}" = x"yes" ; then as_fn_error $? "--enable-vty-group requires a group as argument, not yes" "$LINENO" 5 elif test x"${enable_vty_group}" != x""; then if test x"${enable_vty_group}" != x"no"; then cat >>confdefs.h <<_ACEOF #define VTY_GROUP "${enable_vty_group}" _ACEOF fi fi enable_configfile_mask=${enable_configfile_mask:-0600} cat >>confdefs.h <<_ACEOF #define CONFIGFILE_MASK ${enable_configfile_mask} _ACEOF enable_logfile_mask=${enable_logfile_mask:-0600} cat >>confdefs.h <<_ACEOF #define LOGFILE_MASK ${enable_logfile_mask} _ACEOF MPATH_NUM=1 case "${enable_multipath}" in 0) MPATH_NUM=64 ;; [1-9]|[1-9][0-9]|[1-9][0-9][0-9]) MPATH_NUM="${enable_multipath}" ;; "") ;; *) { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Please specify digit to enable multipath ARG See \`config.log' for more details" "$LINENO" 5; } ;; esac cat >>confdefs.h <<_ACEOF #define MULTIPATH_NUM $MPATH_NUM _ACEOF if test "x${EXTRAVERSION}" != "x" ; then VERSION="${VERSION}${EXTRAVERSION}" PACKAGE_VERSION="${PACKAGE_VERSION}${EXTRAVERSION}" PACKAGE_STRING="${PACKAGE_STRING}${EXTRAVERSION}" fi if test "x$with_pkg_git_version" = "xyes"; then if test -d "${srcdir}/.git"; then $as_echo "#define GIT_VERSION 1" >>confdefs.h else with_pkg_git_version="no" { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-pkg-git-version given, but this is not a git checkout" >&5 $as_echo "$as_me: WARNING: --with-pkg-git-version given, but this is not a git checkout" >&2;} fi fi if test "x$with_pkg_git_version" = "xyes"; then GIT_VERSION_TRUE= GIT_VERSION_FALSE='#' else GIT_VERSION_TRUE='#' GIT_VERSION_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* 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"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 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 sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 $as_echo_n "checking for C/C++ restrict keyword... " >&6; } if ${ac_cv_c_restrict+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_restrict=no # The order here caters to the fact that C++ does not require restrict. for ac_kw in __restrict __restrict__ _Restrict restrict; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ typedef int * int_ptr; int foo (int_ptr $ac_kw ip) { return ip[0]; } int main () { int s[1]; int * $ac_kw t = s; t[0] = 0; return foo(t) ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_restrict=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_restrict" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 $as_echo "$ac_cv_c_restrict" >&6; } case $ac_cv_c_restrict in restrict) ;; no) $as_echo "#define restrict /**/" >>confdefs.h ;; *) cat >>confdefs.h <<_ACEOF #define restrict $ac_cv_c_restrict _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5 $as_echo_n "checking for working volatile... " >&6; } if ${ac_cv_c_volatile+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { volatile int x; int * volatile y = (int *) 0; return !x && !y; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_volatile=yes else ac_cv_c_volatile=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5 $as_echo "$ac_cv_c_volatile" >&6; } if test $ac_cv_c_volatile = no; then $as_echo "#define volatile /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #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)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 $as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } if ${ac_cv_header_stdbool_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef bool "error: bool is not defined" #endif #ifndef false "error: false is not defined" #endif #if false "error: false is not 0" #endif #ifndef true "error: true is not defined" #endif #if true != 1 "error: true is not 1" #endif #ifndef __bool_true_false_are_defined "error: __bool_true_false_are_defined is not defined" #endif struct s { _Bool s: 1; _Bool t; } s; char a[true == 1 ? 1 : -1]; char b[false == 0 ? 1 : -1]; char c[__bool_true_false_are_defined == 1 ? 1 : -1]; char d[(bool) 0.5 == true ? 1 : -1]; /* See body of main program for 'e'. */ char f[(_Bool) 0.0 == false ? 1 : -1]; char g[true]; char h[sizeof (_Bool)]; char i[sizeof s.t]; enum { j = false, k = true, l = false * true, m = true * 256 }; /* The following fails for HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ _Bool n[m]; char o[sizeof n == m * sizeof n[0] ? 1 : -1]; char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; /* Catch a bug in an HP-UX C compiler. See http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html */ _Bool q = true; _Bool *pq = &q; int main () { bool e = &s; *pq |= q; *pq |= ! q; /* Refer to every declared value, to avoid compiler optimizations. */ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + !m + !n + !o + !p + !q + !pq); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdbool_h=yes else ac_cv_header_stdbool_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 $as_echo "$ac_cv_header_stdbool_h" >&6; } ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE__BOOL 1 _ACEOF fi if test $ac_cv_header_stdbool_h = yes; then $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if ${ac_cv_type_uid_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then : ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then $as_echo "#define uid_t int" >>confdefs.h $as_echo "#define gid_t int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define mode_t int _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi for ac_header in stropts.h sys/ksym.h sys/times.h sys/select.h \ sys/types.h linux/version.h netdb.h asm/types.h \ sys/cdefs.h sys/param.h limits.h signal.h \ sys/socket.h netinet/in.h time.h sys/time.h features.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in net/if.h do : ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ " if test "x$ac_cv_header_net_if_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_IF_H 1 _ACEOF fi done for ac_header in net/if_var.h do : ac_fn_c_check_header_compile "$LINENO" "net/if_var.h" "ac_cv_header_net_if_var_h" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif " if test "x$ac_cv_header_net_if_var_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_IF_VAR_H 1 _ACEOF fi done for ac_header in sys/un.h netinet/in_systm.h netinet/in_var.h \ net/if_dl.h net/netopt.h net/route.h \ inet/nd.h arpa/inet.h netinet/ip_icmp.h \ fcntl.h stddef.h sys/ioctl.h syslog.h wchar.h wctype.h \ sys/sysctl.h sys/sockio.h kvm.h sys/conf.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in ucontext.h do : ac_fn_c_check_header_compile "$LINENO" "ucontext.h" "ac_cv_header_ucontext_h" "#ifndef __USE_GNU #define __USE_GNU #endif /* __USE_GNU */ #ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif " if test "x$ac_cv_header_ucontext_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UCONTEXT_H 1 _ACEOF fi done ac_fn_c_check_member "$LINENO" "ucontext_t" "uc_mcontext.uc_regs" "ac_cv_member_ucontext_t_uc_mcontext_uc_regs" "#include " if test "x$ac_cv_member_ucontext_t_uc_mcontext_uc_regs" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UCONTEXT_T_UC_MCONTEXT_UC_REGS 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "ucontext_t" "uc_mcontext.regs" "ac_cv_member_ucontext_t_uc_mcontext_regs" "#include " if test "x$ac_cv_member_ucontext_t_uc_mcontext_regs" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UCONTEXT_T_UC_MCONTEXT_REGS 1 _ACEOF ac_fn_c_check_member "$LINENO" "ucontext_t" "uc_mcontext.regs.nip" "ac_cv_member_ucontext_t_uc_mcontext_regs_nip" "#include " if test "x$ac_cv_member_ucontext_t_uc_mcontext_regs_nip" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UCONTEXT_T_UC_MCONTEXT_REGS_NIP 1 _ACEOF fi fi ac_fn_c_check_member "$LINENO" "ucontext_t" "uc_mcontext.gregs" "ac_cv_member_ucontext_t_uc_mcontext_gregs" "#include " if test "x$ac_cv_member_ucontext_t_uc_mcontext_gregs" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS 1 _ACEOF fi case "$host" in *-sunos5.[6-7]* | *-solaris2.[6-7]*) opsys=sol2-6 $as_echo "#define SUNOS_56 1" >>confdefs.h $as_echo "#define SUNOS_5 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lxnet" >&5 $as_echo_n "checking for main in -lxnet... " >&6; } if ${ac_cv_lib_xnet_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lxnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_xnet_main=yes else ac_cv_lib_xnet_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xnet_main" >&5 $as_echo "$ac_cv_lib_xnet_main" >&6; } if test "x$ac_cv_lib_xnet_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBXNET 1 _ACEOF LIBS="-lxnet $LIBS" fi CURSES=-lcurses SOLARIS="solaris" ;; *-sunos5.[8-9] \ | *-sunos5.1[0-9] \ | *-sunos5.1[0-9].[0-9] \ | *-solaris2.[8-9] \ | *-solaris2.1[0-9] \ | *-solaris2.1[0-9].[0-9]) opsys=sol8 $as_echo "#define SUNOS_59 1" >>confdefs.h $as_echo "#define SUNOS_5 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsocket" >&5 $as_echo_n "checking for main in -lsocket... " >&6; } if ${ac_cv_lib_socket_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_main=yes else ac_cv_lib_socket_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5 $as_echo "$ac_cv_lib_socket_main" >&6; } if test "x$ac_cv_lib_socket_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5 $as_echo_n "checking for main in -lnsl... " >&6; } if ${ac_cv_lib_nsl_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_main=yes else ac_cv_lib_nsl_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5 $as_echo "$ac_cv_lib_nsl_main" >&6; } if test "x$ac_cv_lib_nsl_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lumem" >&5 $as_echo_n "checking for main in -lumem... " >&6; } if ${ac_cv_lib_umem_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lumem $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_umem_main=yes else ac_cv_lib_umem_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_umem_main" >&5 $as_echo "$ac_cv_lib_umem_main" >&6; } if test "x$ac_cv_lib_umem_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBUMEM 1 _ACEOF LIBS="-lumem $LIBS" fi for ac_func in printstack do : ac_fn_c_check_func "$LINENO" "printstack" "ac_cv_func_printstack" if test "x$ac_cv_func_printstack" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PRINTSTACK 1 _ACEOF $as_echo "#define HAVE_PRINTSTACK 1" >>confdefs.h $as_echo "#define HAVE_STACK_TRACE 1" >>confdefs.h fi done CURSES=-lcurses SOLARIS="solaris" ;; *-sunos5* | *-solaris2*) $as_echo "#define SUNOS_5 /**/" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsocket" >&5 $as_echo_n "checking for main in -lsocket... " >&6; } if ${ac_cv_lib_socket_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_main=yes else ac_cv_lib_socket_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5 $as_echo "$ac_cv_lib_socket_main" >&6; } if test "x$ac_cv_lib_socket_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5 $as_echo_n "checking for main in -lnsl... " >&6; } if ${ac_cv_lib_nsl_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_main=yes else ac_cv_lib_nsl_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5 $as_echo "$ac_cv_lib_nsl_main" >&6; } if test "x$ac_cv_lib_nsl_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi CURSES=-lcurses SOLARIS="solaris" ;; *-linux*) opsys=gnu-linux $as_echo "#define GNU_LINUX /**/" >>confdefs.h ;; *-openbsd*) opsys=openbsd $as_echo "#define OPEN_BSD /**/" >>confdefs.h ;; esac # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi case "${enable_vtysh}" in "no") VTYSH="";; *) VTYSH="vtysh"; $as_echo "#define VTYSH /**/" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tputs in -ltermcap" >&5 $as_echo_n "checking for tputs in -ltermcap... " >&6; } if ${ac_cv_lib_termcap_tputs+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ltermcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char tputs (); int main () { return tputs (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_termcap_tputs=yes else ac_cv_lib_termcap_tputs=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_termcap_tputs" >&5 $as_echo "$ac_cv_lib_termcap_tputs" >&6; } if test "x$ac_cv_lib_termcap_tputs" = xyes; then : LIBREADLINE="$LIBREADLINE -ltermcap" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tputs in -ltinfo" >&5 $as_echo_n "checking for tputs in -ltinfo... " >&6; } if ${ac_cv_lib_tinfo_tputs+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ltinfo $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char tputs (); int main () { return tputs (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_tinfo_tputs=yes else ac_cv_lib_tinfo_tputs=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfo_tputs" >&5 $as_echo "$ac_cv_lib_tinfo_tputs" >&6; } if test "x$ac_cv_lib_tinfo_tputs" = xyes; then : LIBREADLINE="$LIBREADLINE -ltinfo" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tputs in -lcurses" >&5 $as_echo_n "checking for tputs in -lcurses... " >&6; } if ${ac_cv_lib_curses_tputs+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char tputs (); int main () { return tputs (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_curses_tputs=yes else ac_cv_lib_curses_tputs=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_tputs" >&5 $as_echo "$ac_cv_lib_curses_tputs" >&6; } if test "x$ac_cv_lib_curses_tputs" = xyes; then : LIBREADLINE="$LIBREADLINE -lcurses" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tputs in -lncurses" >&5 $as_echo_n "checking for tputs in -lncurses... " >&6; } if ${ac_cv_lib_ncurses_tputs+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lncurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char tputs (); int main () { return tputs (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ncurses_tputs=yes else ac_cv_lib_ncurses_tputs=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_tputs" >&5 $as_echo "$ac_cv_lib_ncurses_tputs" >&6; } if test "x$ac_cv_lib_ncurses_tputs" = xyes; then : LIBREADLINE="$LIBREADLINE -lncurses" fi fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lreadline" >&5 $as_echo_n "checking for main in -lreadline... " >&6; } if ${ac_cv_lib_readline_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline "$LIBREADLINE" $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_readline_main=yes else ac_cv_lib_readline_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_main" >&5 $as_echo "$ac_cv_lib_readline_main" >&6; } if test "x$ac_cv_lib_readline_main" = xyes; then : LIBREADLINE="-lreadline $LIBREADLINE" fi if test $ac_cv_lib_readline_main = no; then as_fn_error $? "vtysh needs libreadline but was not found and usable on your system." "$LINENO" 5 fi ac_fn_c_check_header_mongrel "$LINENO" "readline/history.h" "ac_cv_header_readline_history_h" "$ac_includes_default" if test "x$ac_cv_header_readline_history_h" = xyes; then : fi if test $ac_cv_header_readline_history_h = no;then as_fn_error $? "readline is too old to have readline/history.h, please update to the latest readline library." "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -lreadline" >&5 $as_echo_n "checking for rl_completion_matches in -lreadline... " >&6; } if ${ac_cv_lib_readline_rl_completion_matches+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline "$LIBREADLINE" $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char rl_completion_matches (); int main () { return rl_completion_matches (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_readline_rl_completion_matches=yes else ac_cv_lib_readline_rl_completion_matches=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_matches" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_matches" >&6; } if test "x$ac_cv_lib_readline_rl_completion_matches" = xyes; then : LIBREADLINE="$LIBREADLINE" fi if test $ac_cv_lib_readline_rl_completion_matches = no; then $as_echo "#define rl_completion_matches completion_matches" >>confdefs.h fi ;; "no" ) VTYSH="";; esac if test "x$VTYSH" = "xvtysh"; then VTYSH_TRUE= VTYSH_FALSE='#' else VTYSH_TRUE='#' VTYSH_FALSE= fi if test "$with_libpam" = "yes"; then ac_fn_c_check_header_compile "$LINENO" "security/pam_misc.h" "ac_cv_header_security_pam_misc_h" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif " if test "x$ac_cv_header_security_pam_misc_h" = xyes; then : $as_echo "#define HAVE_PAM_MISC_H /**/" >>confdefs.h $as_echo "#define PAM_CONV_FUNC misc_conv" >>confdefs.h pam_conv_func="misc_conv" fi ac_fn_c_check_header_compile "$LINENO" "security/openpam.h" "ac_cv_header_security_openpam_h" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #include " if test "x$ac_cv_header_security_openpam_h" = xyes; then : $as_echo "#define HAVE_OPENPAM_H /**/" >>confdefs.h $as_echo "#define PAM_CONV_FUNC openpam_ttyconv" >>confdefs.h pam_conv_func="openpam_ttyconv" fi if test -z "$ac_cv_header_security_pam_misc_h$ac_cv_header_security_openpam_h" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** pam support will not be built ***" >&5 $as_echo "$as_me: WARNING: *** pam support will not be built ***" >&2;} with_libpam="no" fi fi if test "$with_libpam" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_start in -lpam" >&5 $as_echo_n "checking for pam_start in -lpam... " >&6; } if ${ac_cv_lib_pam_pam_start+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pam_start (); int main () { return pam_start (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pam_pam_start=yes else ac_cv_lib_pam_pam_start=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_start" >&5 $as_echo "$ac_cv_lib_pam_pam_start" >&6; } if test "x$ac_cv_lib_pam_pam_start" = xyes; then : as_ac_Lib=`$as_echo "ac_cv_lib_pam_$pam_conv_func" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $pam_conv_func in -lpam" >&5 $as_echo_n "checking for $pam_conv_func in -lpam... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $pam_conv_func (); int main () { return $pam_conv_func (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : $as_echo "#define USE_PAM /**/" >>confdefs.h LIBPAM="-lpam" else $as_echo "#define USE_PAM /**/" >>confdefs.h LIBPAM="-lpam -lpam_misc" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_end in -lpam" >&5 $as_echo_n "checking for pam_end in -lpam... " >&6; } if ${ac_cv_lib_pam_pam_end+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam -ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pam_end (); int main () { return pam_end (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pam_pam_end=yes else ac_cv_lib_pam_pam_end=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_end" >&5 $as_echo "$ac_cv_lib_pam_pam_end" >&6; } if test "x$ac_cv_lib_pam_pam_end" = xyes; then : as_ac_Lib=`$as_echo "ac_cv_lib_pam_$pam_conv_func" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $pam_conv_func in -lpam" >&5 $as_echo_n "checking for $pam_conv_func in -lpam... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $pam_conv_func (); int main () { return $pam_conv_func (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : $as_echo "#define USE_PAM /**/" >>confdefs.h LIBPAM="-lpam -ldl" else $as_echo "#define USE_PAM /**/" >>confdefs.h LIBPAM="-lpam -ldl -lpam_misc" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** pam support will not be built ***" >&5 $as_echo "$as_me: WARNING: *** pam support will not be built ***" >&2;} fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; 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 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac for ac_header in unistd.h do : ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UNISTD_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5 $as_echo_n "checking for working chown... " >&6; } if ${ac_cv_func_chown_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_chown_works=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include int main () { char *f = "conftest.chown"; struct stat before, after; if (creat (f, 0600) < 0) return 1; if (stat (f, &before) < 0) return 1; if (chown (f, (uid_t) -1, (gid_t) -1) == -1) return 1; if (stat (f, &after) < 0) return 1; return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_chown_works=yes else ac_cv_func_chown_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f conftest.chown fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 $as_echo "$ac_cv_func_chown_works" >&6; } if test $ac_cv_func_chown_works = yes; then $as_echo "#define HAVE_CHOWN 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working POSIX fnmatch" >&5 $as_echo_n "checking for working POSIX fnmatch... " >&6; } if ${ac_cv_func_fnmatch_works+:} false; then : $as_echo_n "(cached) " >&6 else # Some versions of Solaris, SCO, and the GNU C Library # have a broken or incompatible fnmatch. # So we run a test program. If we are cross-compiling, take no chance. # Thanks to John Oleynick, Franc,ois Pinard, and Paul Eggert for this test. if test "$cross_compiling" = yes; then : ac_cv_func_fnmatch_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include # define y(a, b, c) (fnmatch (a, b, c) == 0) # define n(a, b, c) (fnmatch (a, b, c) == FNM_NOMATCH) int main () { return (!(y ("a*", "abc", 0) && n ("d*/*1", "d/s/1", FNM_PATHNAME) && y ("a\\\\bc", "abc", 0) && n ("a\\\\bc", "abc", FNM_NOESCAPE) && y ("*x", ".x", 0) && n ("*x", ".x", FNM_PERIOD) && 1)); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_fnmatch_works=yes else ac_cv_func_fnmatch_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fnmatch_works" >&5 $as_echo "$ac_cv_func_fnmatch_works" >&6; } if test $ac_cv_func_fnmatch_works = yes; then : $as_echo "#define HAVE_FNMATCH 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi for ac_header in vfork.h do : ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" if test "x$ac_cv_header_vfork_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VFORK_H 1 _ACEOF fi done for ac_func in fork vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "x$ac_cv_func_fork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 $as_echo_n "checking for working fork... " >&6; } if ${ac_cv_func_fork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_fork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_fork_works=yes else ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 $as_echo "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 $as_echo_n "checking for working vfork... " >&6; } if ${ac_cv_func_vfork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_vfork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #ifdef HAVE_VFORK_H # include #endif /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void #ifdef __cplusplus sparc_address_test (int arg) # else sparc_address_test (arg) int arg; #endif { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main () { pid_t parent = getpid (); pid_t child; sparc_address_test (0); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_vfork_works=yes else ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 $as_echo "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then $as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h else $as_echo "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 $as_echo_n "checking for working memcmp... " >&6; } if ${ac_cv_func_memcmp_working+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_memcmp_working=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Some versions of memcmp are not 8-bit clean. */ char c0 = '\100', c1 = '\200', c2 = '\201'; if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) return 1; /* The Next x86 OpenStep bug shows up only when comparing 16 bytes or more and with at least one buffer not starting on a 4-byte boundary. William Lewis provided this test program. */ { char foo[21]; char bar[21]; int i; for (i = 0; i < 4; i++) { char *a = foo + i; char *b = bar + i; strcpy (a, "--------01111111"); strcpy (b, "--------10000000"); if (memcmp (a, b, 16) >= 0) return 1; } return 0; } ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_memcmp_working=yes else ac_cv_func_memcmp_working=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 $as_echo "$ac_cv_func_memcmp_working" >&6; } test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac for ac_header in $ac_header_list do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in $ac_func_list do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mktime" >&5 $as_echo_n "checking for working mktime... " >&6; } if ${ac_cv_func_working_mktime+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_working_mktime=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Test program from Paul Eggert and Tony Leneis. */ #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #include #include #ifdef HAVE_UNISTD_H # include #endif #ifndef HAVE_ALARM # define alarm(X) /* empty */ #endif /* Work around redefinition to rpl_putenv by other config tests. */ #undef putenv static time_t time_t_max; static time_t time_t_min; /* Values we'll use to set the TZ environment variable. */ static const char *tz_strings[] = { (const char *) 0, "TZ=GMT0", "TZ=JST-9", "TZ=EST+3EDT+2,M10.1.0/00:00:00,M2.3.0/00:00:00" }; #define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0])) /* Return 0 if mktime fails to convert a date in the spring-forward gap. Based on a problem report from Andreas Jaeger. */ static int spring_forward_gap () { /* glibc (up to about 1998-10-07) failed this test. */ struct tm tm; /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" instead of "TZ=America/Vancouver" in order to detect the bug even on systems that don't support the Olson extension, or don't have the full zoneinfo tables installed. */ putenv ((char*) "TZ=PST8PDT,M4.1.0,M10.5.0"); tm.tm_year = 98; tm.tm_mon = 3; tm.tm_mday = 5; tm.tm_hour = 2; tm.tm_min = 0; tm.tm_sec = 0; tm.tm_isdst = -1; return mktime (&tm) != (time_t) -1; } static int mktime_test1 (time_t now) { struct tm *lt; return ! (lt = localtime (&now)) || mktime (lt) == now; } static int mktime_test (time_t now) { return (mktime_test1 (now) && mktime_test1 ((time_t) (time_t_max - now)) && mktime_test1 ((time_t) (time_t_min + now))); } static int irix_6_4_bug () { /* Based on code from Ariel Faigon. */ struct tm tm; tm.tm_year = 96; tm.tm_mon = 3; tm.tm_mday = 0; tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; tm.tm_isdst = -1; mktime (&tm); return tm.tm_mon == 2 && tm.tm_mday == 31; } static int bigtime_test (int j) { struct tm tm; time_t now; tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = j; now = mktime (&tm); if (now != (time_t) -1) { struct tm *lt = localtime (&now); if (! (lt && lt->tm_year == tm.tm_year && lt->tm_mon == tm.tm_mon && lt->tm_mday == tm.tm_mday && lt->tm_hour == tm.tm_hour && lt->tm_min == tm.tm_min && lt->tm_sec == tm.tm_sec && lt->tm_yday == tm.tm_yday && lt->tm_wday == tm.tm_wday && ((lt->tm_isdst < 0 ? -1 : 0 < lt->tm_isdst) == (tm.tm_isdst < 0 ? -1 : 0 < tm.tm_isdst)))) return 0; } return 1; } static int year_2050_test () { /* The correct answer for 2050-02-01 00:00:00 in Pacific time, ignoring leap seconds. */ unsigned long int answer = 2527315200UL; struct tm tm; time_t t; tm.tm_year = 2050 - 1900; tm.tm_mon = 2 - 1; tm.tm_mday = 1; tm.tm_hour = tm.tm_min = tm.tm_sec = 0; tm.tm_isdst = -1; /* Use the portable POSIX.1 specification "TZ=PST8PDT,M4.1.0,M10.5.0" instead of "TZ=America/Vancouver" in order to detect the bug even on systems that don't support the Olson extension, or don't have the full zoneinfo tables installed. */ putenv ((char*) "TZ=PST8PDT,M4.1.0,M10.5.0"); t = mktime (&tm); /* Check that the result is either a failure, or close enough to the correct answer that we can assume the discrepancy is due to leap seconds. */ return (t == (time_t) -1 || (0 < t && answer - 120 <= t && t <= answer + 120)); } int main () { time_t t, delta; int i, j; /* This test makes some buggy mktime implementations loop. Give up after 60 seconds; a mktime slower than that isn't worth using anyway. */ alarm (60); for (;;) { t = (time_t_max << 1) + 1; if (t <= time_t_max) break; time_t_max = t; } time_t_min = - ((time_t) ~ (time_t) 0 == (time_t) -1) - time_t_max; delta = time_t_max / 997; /* a suitable prime number */ for (i = 0; i < N_STRINGS; i++) { if (tz_strings[i]) putenv ((char*) tz_strings[i]); for (t = 0; t <= time_t_max - delta; t += delta) if (! mktime_test (t)) return 1; if (! (mktime_test ((time_t) 1) && mktime_test ((time_t) (60 * 60)) && mktime_test ((time_t) (60 * 60 * 24)))) return 1; for (j = 1; ; j <<= 1) if (! bigtime_test (j)) return 1; else if (INT_MAX / 2 < j) break; if (! bigtime_test (INT_MAX)) return 1; } return ! (irix_6_4_bug () && spring_forward_gap () && year_2050_test ()); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_working_mktime=yes else ac_cv_func_working_mktime=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_working_mktime" >&5 $as_echo "$ac_cv_func_working_mktime" >&6; } if test $ac_cv_func_working_mktime = no; then case " $LIBOBJS " in *" mktime.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS mktime.$ac_objext" ;; esac fi for ac_func in strftime do : ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" if test "x$ac_cv_func_strftime" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRFTIME 1 _ACEOF else # strftime is in -lintl on SCO UNIX. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5 $as_echo_n "checking for strftime in -lintl... " >&6; } if ${ac_cv_lib_intl_strftime+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strftime (); int main () { return strftime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_strftime=yes else ac_cv_lib_intl_strftime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5 $as_echo "$ac_cv_lib_intl_strftime" >&6; } if test "x$ac_cv_lib_intl_strftime" = xyes; then : $as_echo "#define HAVE_STRFTIME 1" >>confdefs.h LIBS="-lintl $LIBS" fi fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 $as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } if ${ac_cv_func_lstat_dereferences_slashed_symlink+:} false; then : $as_echo_n "(cached) " >&6 else rm -f conftest.sym conftest.file echo >conftest.file if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then if test "$cross_compiling" = yes; then : ac_cv_func_lstat_dereferences_slashed_symlink=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; /* Linux will dereference the symlink and fail, as required by POSIX. That is better in the sense that it means we will not have to compile and use the lstat wrapper. */ return lstat ("conftest.sym/", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_lstat_dereferences_slashed_symlink=yes else ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else # If the `ln -s' command failed, then we probably don't even # have an lstat function. ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f conftest.sym conftest.file fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 $as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && cat >>confdefs.h <<_ACEOF #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 _ACEOF if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5 $as_echo_n "checking whether stat accepts an empty string... " >&6; } if ${ac_cv_func_stat_empty_string_bug+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_stat_empty_string_bug=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; return stat ("", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_stat_empty_string_bug=no else ac_cv_func_stat_empty_string_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_stat_empty_string_bug" >&5 $as_echo "$ac_cv_func_stat_empty_string_bug" >&6; } if test $ac_cv_func_stat_empty_string_bug = yes; then case " $LIBOBJS " in *" stat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS stat.$ac_objext" ;; esac cat >>confdefs.h <<_ACEOF #define HAVE_STAT_EMPTY_STRING_BUG 1 _ACEOF fi for ac_header in sys/select.h sys/socket.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5 $as_echo_n "checking types of arguments for select... " >&6; } if ${ac_cv_func_select_args+:} false; then : $as_echo_n "(cached) " >&6 else for ac_arg234 in 'fd_set *' 'int *' 'void *'; do for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif int main () { extern int select ($ac_arg1, $ac_arg234, $ac_arg234, $ac_arg234, $ac_arg5); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done done done # Provide a safe default value. : "${ac_cv_func_select_args=int,int *,struct timeval *}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5 $as_echo "$ac_cv_func_select_args" >&6; } ac_save_IFS=$IFS; IFS=',' set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'` IFS=$ac_save_IFS shift cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG1 $1 _ACEOF cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG234 ($2) _ACEOF cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG5 ($3) _ACEOF rm -f conftest* for ac_func in strftime do : ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" if test "x$ac_cv_func_strftime" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRFTIME 1 _ACEOF else # strftime is in -lintl on SCO UNIX. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5 $as_echo_n "checking for strftime in -lintl... " >&6; } if ${ac_cv_lib_intl_strftime+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strftime (); int main () { return strftime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_strftime=yes else ac_cv_lib_intl_strftime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5 $as_echo "$ac_cv_lib_intl_strftime" >&6; } if test "x$ac_cv_lib_intl_strftime" = xyes; then : $as_echo "#define HAVE_STRFTIME 1" >>confdefs.h LIBS="-lintl $LIBS" fi fi done for ac_func in vprintf do : ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" if test "x$ac_cv_func_vprintf" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VPRINTF 1 _ACEOF ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" if test "x$ac_cv_func__doprnt" = xyes; then : $as_echo "#define HAVE_DOPRNT 1" >>confdefs.h fi fi done TMPLIBS="$LIBS" ac_fn_c_check_header_mongrel "$LINENO" "math.h" "ac_cv_header_math_h" "$ac_includes_default" if test "x$ac_cv_header_math_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5 $as_echo_n "checking for pow in -lm... " >&6; } if ${ac_cv_lib_m_pow+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_pow=yes else ac_cv_lib_m_pow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5 $as_echo "$ac_cv_lib_m_pow" >&6; } if test "x$ac_cv_lib_m_pow" = xyes; then : LIBM="-lm" LIBS="$LIBS $LIBM" $as_echo "#define HAVE_LIBM /**/" >>confdefs.h for ac_func in pow do : ac_fn_c_check_func "$LINENO" "pow" "ac_cv_func_pow" if test "x$ac_cv_func_pow" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POW 1 _ACEOF else LIBM="" fi done fi fi if test x"$LIBM" = x ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to find working pow function - bgpd may not link" >&5 $as_echo "$as_me: WARNING: Unable to find working pow function - bgpd may not link" >&2;} fi LIBS="$TMPLIBS" for ac_func in dup2 ftruncate getcwd gethostbyname getpagesize gettimeofday \ inet_ntoa inet_aton strnlen \ memchr memmove memset select socket \ strcasecmp strchr strcspn strdup strerror \ strncasecmp strndup strrchr strspn strstr \ strtol strtoul strlcat strlcpy \ daemon snprintf vsnprintf \ if_nametoindex if_indextoname getifaddrs \ uname fcntl getgrouplist do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "asm-generic/unistd.h" "ac_cv_header_asm_generic_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_asm_generic_unistd_h" = xyes; then : ac_fn_c_check_decl "$LINENO" "__NR_setns" "ac_cv_have_decl___NR_setns" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #include " if test "x$ac_cv_have_decl___NR_setns" = xyes; then : $as_echo "#define HAVE_NETNS /**/" >>confdefs.h fi for ac_func in setns do : ac_fn_c_check_func "$LINENO" "setns" "ac_cv_func_setns" if test "x$ac_cv_func_setns" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETNS 1 _ACEOF $as_echo "#define HAVE_SETNS /**/" >>confdefs.h fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking zebra between kernel interface method" >&5 $as_echo_n "checking zebra between kernel interface method... " >&6; } if test x"$opsys" = x"gnu-linux"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: netlink" >&5 $as_echo "netlink" >&6; } RT_METHOD=rt_netlink.o $as_echo "#define HAVE_NETLINK /**/" >>confdefs.h netlink=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: result: Route socket" >&5 $as_echo "Route socket" >&6; } KERNEL_METHOD="kernel_socket.o" RT_METHOD="rt_socket.o" fi if test "x$netlink" = "xyes"; then HAVE_NETLINK_TRUE= HAVE_NETLINK_FALSE='#' else HAVE_NETLINK_TRUE='#' HAVE_NETLINK_FALSE= fi $as_echo "#define ISIS_METHOD_PFPACKET 1" >>confdefs.h $as_echo "#define ISIS_METHOD_DLPI 2" >>confdefs.h $as_echo "#define ISIS_METHOD_BPF 3" >>confdefs.h ac_fn_c_check_header_mongrel "$LINENO" "net/bpf.h" "ac_cv_header_net_bpf_h" "$ac_includes_default" if test "x$ac_cv_header_net_bpf_h" = xyes; then : fi ac_fn_c_check_header_mongrel "$LINENO" "sys/dlpi.h" "ac_cv_header_sys_dlpi_h" "$ac_includes_default" if test "x$ac_cv_header_sys_dlpi_h" = xyes; then : fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking zebra IS-IS I/O method" >&5 $as_echo_n "checking zebra IS-IS I/O method... " >&6; } if test x"$opsys" = x"gnu-linux"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: pfpacket" >&5 $as_echo "pfpacket" >&6; } ISIS_METHOD_MACRO="ISIS_METHOD_PFPACKET" elif test x"$opsys" = x"sol2-6" -o x"$opsys" = x"sol8"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: DLPI" >&5 $as_echo "DLPI" >&6; } ISIS_METHOD_MACRO="ISIS_METHOD_DLPI" else if test $ac_cv_header_net_bpf_h = no; then if test $ac_cv_header_sys_dlpi_h = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** IS-IS support will not be built ***" >&5 $as_echo "$as_me: WARNING: *** IS-IS support will not be built ***" >&2;} ISISD="" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: DLPI" >&5 $as_echo "DLPI" >&6; } fi ISIS_METHOD_MACRO="ISIS_METHOD_DLPI" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: BPF" >&5 $as_echo "BPF" >&6; } ISIS_METHOD_MACRO="ISIS_METHOD_BPF" fi fi cat >>confdefs.h <<_ACEOF #define ISIS_METHOD $ISIS_METHOD_MACRO _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken CMSG_FIRSTHDR" >&5 $as_echo_n "checking for broken CMSG_FIRSTHDR... " >&6; } if test "$cross_compiling" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif main() { struct msghdr msg; char buf[4]; msg.msg_control = buf; msg.msg_controllen = 0; if (CMSG_FIRSTHDR(&msg) != NULL) exit(0); exit (1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes - using workaround" >&5 $as_echo "yes - using workaround" >&6; } $as_echo "#define HAVE_BROKEN_CMSG_FIRSTHDR /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking route read method" >&5 $as_echo_n "checking route read method... " >&6; } if ${quagga_cv_rtread_method+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$netlink" = xyes; then quagga_cv_rtread_method="netlink" else for quagga_cv_rtread_method in /dev/ip /dev/null; do test x`ls $quagga_cv_rtread_method 2>/dev/null` = x"$quagga_cv_rtread_method" && break done case $quagga_cv_rtread_method in "/dev/ip") case "$host" in *-freebsd*) quagga_cv_rtread_method="sysctl";; *) quagga_cv_rtread_method="getmsg";; esac;; *) quagga_cv_rtread_method="sysctl";; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $quagga_cv_rtread_method" >&5 $as_echo "$quagga_cv_rtread_method" >&6; } RTREAD_METHOD=rtread_${quagga_cv_rtread_method}.o IOCTL_METHOD=ioctl.o { $as_echo "$as_me:${as_lineno-$LINENO}: checking interface looking up method" >&5 $as_echo_n "checking interface looking up method... " >&6; } if test "$netlink" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: netlink" >&5 $as_echo "netlink" >&6; } IF_METHOD=if_netlink.o elif test "$opsys" = "sol2-6";then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Solaris GIF" >&5 $as_echo "Solaris GIF" >&6; } IF_METHOD=if_ioctl.o elif test "$opsys" = "sol8";then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Solaris GLIF" >&5 $as_echo "Solaris GLIF" >&6; } IF_METHOD=if_ioctl_solaris.o IOCTL_METHOD=ioctl_solaris.o elif test "$opsys" = "openbsd";then { $as_echo "$as_me:${as_lineno-$LINENO}: result: openbsd" >&5 $as_echo "openbsd" >&6; } IF_METHOD=if_ioctl.o elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: sysctl" >&5 $as_echo "sysctl" >&6; } IF_METHOD=if_sysctl.o $as_echo "#define HAVE_NET_RT_IFLIST /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ioctl" >&5 $as_echo "ioctl" >&6; } IF_METHOD=if_ioctl.o fi ac_fn_c_check_member "$LINENO" "struct ip_mreqn" "imr_ifindex" "ac_cv_member_struct_ip_mreqn_imr_ifindex" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif " if test "x$ac_cv_member_struct_ip_mreqn_imr_ifindex" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IP_MREQN_IMR_IFINDEX 1 _ACEOF fi for ac_header in linux/mroute.h do : ac_fn_c_check_header_compile "$LINENO" "linux/mroute.h" "ac_cv_header_linux_mroute_h" " #if HAVE_NETINET_IN_H #include #endif " if test "x$ac_cv_header_linux_mroute_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_MROUTE_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD struct ip_mreq hack" >&5 $as_echo_n "checking for BSD struct ip_mreq hack... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_PARAM_H #include #endif int main () { #if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__DragonFly__) || defined(__sun) return (0); #else #error No support for BSD struct ip_mreq hack detected #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_BSD_STRUCT_IP_MREQ_HACK /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RFC3678 protocol-independed API" >&5 $as_echo_n "checking for RFC3678 protocol-independed API... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct group_req gr; int sock; setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr)); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_RFC3678 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif " if test "x$ac_cv_header_net_if_h" = xyes; then : ac_fn_c_check_header_compile "$LINENO" "net/if_media.h" "ac_cv_header_net_if_media_h" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif " if test "x$ac_cv_header_net_if_media_h" = xyes; then : ac_fn_c_check_member "$LINENO" "struct ifmediareq" "ifm_status" "ac_cv_member_struct_ifmediareq_ifm_status" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #include " if test "x$ac_cv_member_struct_ifmediareq_ifm_status" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IFMEDIAREQ_IFM_STATUS 1 _ACEOF $as_echo "#define HAVE_BSD_LINK_DETECT /**/" >>confdefs.h fi fi fi ac_fn_c_check_header_mongrel "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "$ac_includes_default" if test "x$ac_cv_header_net_if_h" = xyes; then : ac_fn_c_check_member "$LINENO" "struct if_data" "ifi_link_state" "ac_cv_member_struct_if_data_ifi_link_state" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif " if test "x$ac_cv_member_struct_if_data_ifi_link_state" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IF_DATA_IFI_LINK_STATE 1 _ACEOF $as_echo "#define HAVE_BSD_IFI_LINK_STATE /**/" >>confdefs.h fi fi ac_fn_c_check_header_compile "$LINENO" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif " if test "x$ac_cv_header_netinet_tcp_h" = xyes; then : ac_fn_c_check_decl "$LINENO" "TCP_MD5SIG" "ac_cv_have_decl_TCP_MD5SIG" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #include " if test "x$ac_cv_have_decl_TCP_MD5SIG" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_TCP_MD5SIG $ac_have_decl _ACEOF fi if test $ac_cv_have_decl_TCP_MD5SIG = no; then ac_fn_c_check_header_mongrel "$LINENO" "linux/tcp.h" "ac_cv_header_linux_tcp_h" "$ac_includes_default" if test "x$ac_cv_header_linux_tcp_h" = xyes; then : ac_fn_c_check_decl "$LINENO" "TCP_MD5SIG" "ac_cv_have_decl_TCP_MD5SIG" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #include " if test "x$ac_cv_have_decl_TCP_MD5SIG" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_TCP_MD5SIG $ac_have_decl _ACEOF fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking ipforward method" >&5 $as_echo_n "checking ipforward method... " >&6; } if ${quagga_cv_ipforward_method+:} false; then : $as_echo_n "(cached) " >&6 else if test x$cross_compiling = xyes; then if test x"$opsys" = x"gnu-linux"; then quagga_cv_ipforward_method=/proc/net/snmp else quagga_cv_ipforward_method=/dev/ip fi else for quagga_cv_ipforward_method in /proc/net/snmp /dev/ip /dev/null; do test x`ls $quagga_cv_ipforward_method 2>/dev/null` = x"$quagga_cv_ipforward_method" && break done fi case $quagga_cv_ipforward_method in "/proc/net/snmp") quagga_cv_ipforward_method="proc";; "/dev/ip") case "$host" in *-freebsd*) quagga_cv_ipforward_method="sysctl";; *) quagga_cv_ipforward_method="solaris";; esac;; *) quagga_cv_ipforward_method="sysctl";; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $quagga_cv_ipforward_method" >&5 $as_echo "$quagga_cv_ipforward_method" >&6; } IPFORWARD=ipforward_${quagga_cv_ipforward_method}.o for ac_func in getaddrinfo do : ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" if test "x$ac_cv_func_getaddrinfo" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETADDRINFO 1 _ACEOF have_getaddrinfo=yes else have_getaddrinfo=no fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether does this OS have IPv6 stack" >&5 $as_echo_n "checking whether does this OS have IPv6 stack... " >&6; } if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then $as_echo "#define KAME 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: KAME" >&5 $as_echo "KAME" >&6; } elif test x"$opsys" = x"sol8"; then $as_echo "#define SOLARIS_IPV6 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: Solaris IPv6" >&5 $as_echo "Solaris IPv6" >&6; } elif test x"$opsys" = x"gnu-linux"; then $as_echo "#define LINUX_IPV6 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: Linux IPv6" >&5 $as_echo "Linux IPv6" >&6; } else as_fn_error $? "Failed to detect IPv6 stack" "$LINENO" 5 fi $as_echo "#define HAVE_IPV6 1" >>confdefs.h for ac_header in netinet6/in6.h netinet/in6_var.h netinet/icmp6.h \ netinet6/in6_var.h netinet6/nd6.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done if test "${enable_doc}" = "no";then DOC="" else DOC="doc" fi if test "${enable_zebra}" = "no";then ZEBRA="" else ZEBRA="zebra" fi if test "x$ZEBRA" = "xzebra"; then ZEBRA_TRUE= ZEBRA_FALSE='#' else ZEBRA_TRUE='#' ZEBRA_FALSE= fi if test "${enable_bgpd}" = "no";then BGPD="" else BGPD="bgpd" fi if test "x$BGPD" = "xbgpd"; then BGPD_TRUE= BGPD_FALSE='#' else BGPD_TRUE='#' BGPD_FALSE= fi if test "${enable_ripd}" = "no";then RIPD="" else RIPD="ripd" fi if test "x$RIPD" = "xripd"; then RIPD_TRUE= RIPD_FALSE='#' else RIPD_TRUE='#' RIPD_FALSE= fi if test "${enable_ospfd}" = "no";then OSPFD="" else OSPFD="ospfd" fi if test "x$OSPFD" = "xospfd"; then OSPFD_TRUE= OSPFD_FALSE='#' else OSPFD_TRUE='#' OSPFD_FALSE= fi if test x"$opsys" != x"gnu-linux"; then enable_nhrpd="no" fi if test "${enable_nhrpd}" = "no";then NHRPD="" else NHRPD="nhrpd" fi if test "x$NHRPD" = "xnhrpd"; then NHRPD_TRUE= NHRPD_FALSE='#' else NHRPD_TRUE='#' NHRPD_FALSE= fi if test "${enable_watchquagga}" = "no";then WATCHQUAGGA="" else WATCHQUAGGA="watchquagga" fi if test "x$WATCHQUAGGA" = "xwatchquagga"; then WATCHQUAGGA_TRUE= WATCHQUAGGA_FALSE='#' else WATCHQUAGGA_TRUE='#' WATCHQUAGGA_FALSE= fi OSPFCLIENT="" if test "${enable_ospfapi}" != "no";then $as_echo "#define SUPPORT_OSPF_API /**/" >>confdefs.h if test "${enable_ospfclient}" != "no";then OSPFCLIENT="ospfclient" fi fi if test "x$OSPFCLIENT" = "xospfclient"; then OSPFCLIENT_TRUE= OSPFCLIENT_FALSE='#' else OSPFCLIENT_TRUE='#' OSPFCLIENT_FALSE= fi case "${enable_ripngd}" in "no" ) RIPNGD="";; * ) RIPNGD="ripngd";; esac if test "x$RIPNGD" = "xripngd"; then RIPNGD_TRUE= RIPNGD_FALSE='#' else RIPNGD_TRUE='#' RIPNGD_FALSE= fi case "${enable_ospf6d}" in "no" ) OSPF6D="";; * ) OSPF6D="ospf6d";; esac if test "x$OSPF6D" = "xospf6d"; then OSPF6D_TRUE= OSPF6D_FALSE='#' else OSPF6D_TRUE='#' OSPF6D_FALSE= fi case "${enable_isisd}" in "no" ) ISISD="";; * ) ISISD="isisd";; esac if test "x$ISISD" = "xisisd"; then ISISD_TRUE= ISISD_FALSE='#' else ISISD_TRUE='#' ISISD_FALSE= fi case "${enable_pimd}" in "no" ) PIMD="";; * ) PIMD="pimd";; esac if test "x$PIMD" = "xpimd"; then PIMD_TRUE= PIMD_FALSE='#' else PIMD_TRUE='#' PIMD_FALSE= fi if test "${enable_bgp_announce}" = "no";then $as_echo "#define DISABLE_BGP_ANNOUNCE 1" >>confdefs.h else $as_echo "#define DISABLE_BGP_ANNOUNCE 0" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntop in -lc" >&5 $as_echo_n "checking for inet_ntop in -lc... " >&6; } if ${ac_cv_lib_c_inet_ntop+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntop (); int main () { return inet_ntop (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_inet_ntop=yes else ac_cv_lib_c_inet_ntop=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_ntop" >&5 $as_echo "$ac_cv_lib_c_inet_ntop" >&6; } if test "x$ac_cv_lib_c_inet_ntop" = xyes; then : $as_echo "#define HAVE_INET_NTOP /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_pton in -lc" >&5 $as_echo_n "checking for inet_pton in -lc... " >&6; } if ${ac_cv_lib_c_inet_pton+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_pton (); int main () { return inet_pton (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_inet_pton=yes else ac_cv_lib_c_inet_pton=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_pton" >&5 $as_echo "$ac_cv_lib_c_inet_pton" >&6; } if test "x$ac_cv_lib_c_inet_pton" = xyes; then : $as_echo "#define HAVE_INET_PTON /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5 $as_echo_n "checking for crypt in -lcrypt... " >&6; } if ${ac_cv_lib_crypt_crypt+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char crypt (); int main () { return crypt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypt_crypt=yes else ac_cv_lib_crypt_crypt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5 $as_echo "$ac_cv_lib_crypt_crypt" >&6; } if test "x$ac_cv_lib_crypt_crypt" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCRYPT 1 _ACEOF LIBS="-lcrypt $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for res_init in -lresolv" >&5 $as_echo_n "checking for res_init in -lresolv... " >&6; } if ${ac_cv_lib_resolv_res_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lresolv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char res_init (); int main () { return res_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_resolv_res_init=yes else ac_cv_lib_resolv_res_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_res_init" >&5 $as_echo "$ac_cv_lib_resolv_res_init" >&6; } if test "x$ac_cv_lib_resolv_res_init" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF LIBS="-lresolv $LIBS" fi if test "x$enable_pcreposix" = "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcreposix_regexec in -lpcreposix" >&5 $as_echo_n "checking for pcreposix_regexec in -lpcreposix... " >&6; } if ${ac_cv_lib_pcreposix_pcreposix_regexec+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcreposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pcreposix_regexec (); int main () { return pcreposix_regexec (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcreposix_pcreposix_regexec=yes else ac_cv_lib_pcreposix_pcreposix_regexec=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcreposix_pcreposix_regexec" >&5 $as_echo "$ac_cv_lib_pcreposix_pcreposix_regexec" >&6; } if test "x$ac_cv_lib_pcreposix_pcreposix_regexec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPCREPOSIX 1 _ACEOF LIBS="-lpcreposix $LIBS" else enable_pcreposix=no { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** falling back to other regex library ***" >&5 $as_echo "$as_me: WARNING: *** falling back to other regex library ***" >&2;} fi fi if test "x$enable_pcreposix" != "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether system has GNU regex" >&5 $as_echo_n "checking whether system has GNU regex... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for regexec in -lc" >&5 $as_echo_n "checking for regexec in -lc... " >&6; } if ${ac_cv_lib_c_regexec+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char regexec (); int main () { return regexec (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_regexec=yes else ac_cv_lib_c_regexec=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_regexec" >&5 $as_echo "$ac_cv_lib_c_regexec" >&6; } if test "x$ac_cv_lib_c_regexec" = xyes; then : $as_echo "#define HAVE_GNU_REGEX /**/" >>confdefs.h LIB_REGEX="" else LIB_REGEX="regex.o" fi fi if test "${enable_nhrpd}" != "no";then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CARES" >&5 $as_echo_n "checking for CARES... " >&6; } if test -n "$CARES_CFLAGS"; then pkg_cv_CARES_CFLAGS="$CARES_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcares\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcares") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CARES_CFLAGS=`$PKG_CONFIG --cflags "libcares" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CARES_LIBS"; then pkg_cv_CARES_LIBS="$CARES_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcares\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcares") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CARES_LIBS=`$PKG_CONFIG --libs "libcares" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CARES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcares" 2>&1` else CARES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcares" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CARES_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (libcares) were not met: $CARES_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables CARES_CFLAGS and CARES_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables CARES_CFLAGS and CARES_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else CARES_CFLAGS=$pkg_cv_CARES_CFLAGS CARES_LIBS=$pkg_cv_CARES_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi fi if test "${enable_snmp}" != ""; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}net-snmp-config", so it can be a program name with args. set dummy ${ac_tool_prefix}net-snmp-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_NETSNMP_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $NETSNMP_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_NETSNMP_CONFIG="$NETSNMP_CONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_NETSNMP_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi NETSNMP_CONFIG=$ac_cv_path_NETSNMP_CONFIG if test -n "$NETSNMP_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NETSNMP_CONFIG" >&5 $as_echo "$NETSNMP_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_NETSNMP_CONFIG"; then ac_pt_NETSNMP_CONFIG=$NETSNMP_CONFIG # Extract the first word of "net-snmp-config", so it can be a program name with args. set dummy net-snmp-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_NETSNMP_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_NETSNMP_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_NETSNMP_CONFIG="$ac_pt_NETSNMP_CONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_NETSNMP_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_NETSNMP_CONFIG=$ac_cv_path_ac_pt_NETSNMP_CONFIG if test -n "$ac_pt_NETSNMP_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_NETSNMP_CONFIG" >&5 $as_echo "$ac_pt_NETSNMP_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_NETSNMP_CONFIG" = x; then NETSNMP_CONFIG="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NETSNMP_CONFIG=$ac_pt_NETSNMP_CONFIG fi else NETSNMP_CONFIG="$ac_cv_path_NETSNMP_CONFIG" fi if test x"$NETSNMP_CONFIG" = x"no"; then as_fn_error $? "--enable-snmp given but unable to find net-snmp-config" "$LINENO" 5 fi LIBS="$LIBS `${NETSNMP_CONFIG} --agent-libs`" CFLAGS="`${NETSNMP_CONFIG} --base-cflags` $CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can link to Net-SNMP" >&5 $as_echo_n "checking whether we can link to Net-SNMP... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(void); int main () { { return 0; } ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "--enable-snmp given but not usable" "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext $as_echo "#define HAVE_SNMP /**/" >>confdefs.h case "${enable_snmp}" in yes) SNMP_METHOD=agentx ;; smux|agentx) SNMP_METHOD="${enable_snmp}" ;; *) as_fn_error $? "--enable-snmp given with an unknown method (${enable_snmp}). Use smux or agentx" "$LINENO" 5 ;; esac cat >>confdefs.h <<_ACEOF #define `$as_echo "SNMP_${SNMP_METHOD}" | $as_tr_cpp` /**/ _ACEOF fi ac_fn_c_check_type "$LINENO" "struct sockaddr" "ac_cv_type_struct_sockaddr" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_sockaddr" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct sockaddr_in" "ac_cv_type_struct_sockaddr_in" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_sockaddr_in" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_IN 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct sockaddr_in6" "ac_cv_type_struct_sockaddr_in6" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_sockaddr_in6" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_IN6 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct sockaddr_un" "ac_cv_type_struct_sockaddr_un" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_sockaddr_un" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_UN 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct sockaddr_dl" "ac_cv_type_struct_sockaddr_dl" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_sockaddr_dl" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_DL 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_socklen_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SOCKLEN_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct vifctl" "ac_cv_type_struct_vifctl" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_vifctl" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_VIFCTL 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct mfcctl" "ac_cv_type_struct_mfcctl" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_mfcctl" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_MFCCTL 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct sioc_sg_req" "ac_cv_type_struct_sioc_sg_req" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_sioc_sg_req" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SIOC_SG_REQ 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "vifi_t" "ac_cv_type_vifi_t" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_vifi_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VIFI_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct sioc_vif_req" "ac_cv_type_struct_sioc_vif_req" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_sioc_vif_req" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SIOC_VIF_REQ 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct igmpmsg" "ac_cv_type_struct_igmpmsg" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_igmpmsg" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IGMPMSG 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct ifaliasreq" "ac_cv_type_struct_ifaliasreq" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_ifaliasreq" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IFALIASREQ 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct if6_aliasreq" "ac_cv_type_struct_if6_aliasreq" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_if6_aliasreq" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IF6_ALIASREQ 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct in6_aliasreq" "ac_cv_type_struct_in6_aliasreq" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_in6_aliasreq" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IN6_ALIASREQ 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct nd_opt_adv_interval" "ac_cv_type_struct_nd_opt_adv_interval" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_nd_opt_adv_interval" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_ND_OPT_ADV_INTERVAL 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct rt_addrinfo" "ac_cv_type_struct_rt_addrinfo" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_rt_addrinfo" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_RT_ADDRINFO 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct nd_opt_homeagent_info" "ac_cv_type_struct_nd_opt_homeagent_info" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_nd_opt_homeagent_info" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_ND_OPT_HOMEAGENT_INFO 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct nd_opt_adv_interval" "ac_cv_type_struct_nd_opt_adv_interval" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_nd_opt_adv_interval" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_ND_OPT_ADV_INTERVAL 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_SA_LEN 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct sockaddr_in" "sin_len" "ac_cv_member_struct_sockaddr_in_sin_len" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_member_struct_sockaddr_in_sin_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_member_struct_sockaddr_un_sun_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct sockaddr_in6" "sin6_scope_id" "ac_cv_member_struct_sockaddr_in6_sin6_scope_id" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_member_struct_sockaddr_in6_sin6_scope_id" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct sockaddr_dl" "sdl_len" "ac_cv_member_struct_sockaddr_dl_sdl_len" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_member_struct_sockaddr_dl_sdl_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_DL_SDL_LEN 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct if6_aliasreq" "ifra_lifetime" "ac_cv_member_struct_if6_aliasreq_ifra_lifetime" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_member_struct_if6_aliasreq_ifra_lifetime" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct nd_opt_adv_interval" "nd_opt_ai_type" "ac_cv_member_struct_nd_opt_adv_interval_nd_opt_ai_type" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_member_struct_nd_opt_adv_interval_nd_opt_ai_type" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_ND_OPT_ADV_INTERVAL_ND_OPT_AI_TYPE 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "struct in_pktinfo" "ac_cv_type_struct_in_pktinfo" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_in_pktinfo" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IN_PKTINFO 1 _ACEOF ac_fn_c_check_type "$LINENO" "struct icmphdr" "ac_cv_type_struct_icmphdr" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_type_struct_icmphdr" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_ICMPHDR 1 _ACEOF if test "${enable_irdp}" != "no"; then $as_echo "#define HAVE_IRDP /**/" >>confdefs.h fi else if test "${enable_irdp}" = "yes"; then as_fn_error $? "'IRDP requires in_pktinfo at the moment!'" "$LINENO" 5 fi fi else if test "${enable_irdp}" = "yes"; then as_fn_error $? "'IRDP requires in_pktinfo at the moment!'" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IP_PKTINFO" >&5 $as_echo_n "checking for IP_PKTINFO... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int opt = IP_PKTINFO; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_IP_PKTINFO 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IP_RECVDSTADDR" >&5 $as_echo_n "checking for IP_RECVDSTADDR... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int opt = IP_RECVDSTADDR; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_IP_RECVDSTADDR 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IP_RECVIF" >&5 $as_echo_n "checking for IP_RECVIF... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int opt = IP_RECVIF; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_IP_RECVIF 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "${enable_rusage}" != "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getrusage is available" >&5 $as_echo_n "checking whether getrusage is available... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_RUSAGE /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ac_fn_c_check_decl "$LINENO" "CLOCK_MONOTONIC" "ac_cv_have_decl_CLOCK_MONOTONIC" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_have_decl_CLOCK_MONOTONIC" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 $as_echo_n "checking for clock_gettime in -lrt... " >&6; } if ${ac_cv_lib_rt_clock_gettime+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_rt_clock_gettime=yes else ac_cv_lib_rt_clock_gettime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 $as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : LIBS="$LIBS -lrt" fi $as_echo "#define HAVE_CLOCK_MONOTONIC /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${enable_capabilities}" != "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether prctl PR_SET_KEEPCAPS is available" >&5 $as_echo_n "checking whether prctl PR_SET_KEEPCAPS is available... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_PR_SET_KEEPCAPS /**/" >>confdefs.h quagga_ac_keepcaps="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test x"${quagga_ac_keepcaps}" = x"yes"; then for ac_header in sys/capability.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default" if test "x$ac_cv_header_sys_capability_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_CAPABILITY_H 1 _ACEOF fi done fi if test x"${ac_cv_header_sys_capability_h}" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_init in -lcap" >&5 $as_echo_n "checking for cap_init in -lcap... " >&6; } if ${ac_cv_lib_cap_cap_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char cap_init (); int main () { return cap_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_cap_cap_init=yes else ac_cv_lib_cap_cap_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_cap_init" >&5 $as_echo "$ac_cv_lib_cap_cap_init" >&6; } if test "x$ac_cv_lib_cap_cap_init" = xyes; then : $as_echo "#define HAVE_LCAPS 1" >>confdefs.h LIBCAP="-lcap" quagga_ac_lcaps="yes" fi else for ac_header in priv.h do : ac_fn_c_check_header_mongrel "$LINENO" "priv.h" "ac_cv_header_priv_h" "$ac_includes_default" if test "x$ac_cv_header_priv_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PRIV_H 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking Solaris style privileges are available" >&5 $as_echo_n "checking Solaris style privileges are available... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { getpflags(PRIV_AWARE); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_SOLARIS_CAPABILITIES 1" >>confdefs.h quagga_ac_scaps="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi done fi if test x"${quagga_ac_scaps}" = x"yes" \ -o x"${quagga_ac_lcaps}" = x"yes"; then $as_echo "#define HAVE_CAPABILITIES 1" >>confdefs.h fi fi # starting point: no aliasing scheme yet... ax_sys_weak_alias=no # Figure out what kind of aliasing may be supported... # Test whether compiler accepts __attribute__ form of weak aliasing { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts function __attribute__((weak,alias()))" >&5 $as_echo_n "checking whether $CC accepts function __attribute__((weak,alias()))... " >&6; } if ${ax_cv_sys_weak_alias_attribute+:} false; then : $as_echo_n "(cached) " >&6 else # We add -Werror if it's gcc to force an error exit if the weak attribute # isn't understood if test $GCC = yes; then : save_CFLAGS=$CFLAGS CFLAGS=-Werror fi # Try linking with a weak alias... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ void __weakf(int c) {} void weakf(int c) __attribute__((weak, alias("__weakf"))); int main () { weakf(0) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ax_cv_sys_weak_alias_attribute=yes else ax_cv_sys_weak_alias_attribute=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext # Restore original CFLAGS if test $GCC = yes; then : CFLAGS=$save_CFLAGS fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_sys_weak_alias_attribute" >&5 $as_echo "$ax_cv_sys_weak_alias_attribute" >&6; } # What was the result of the test? if test $ax_cv_sys_weak_alias_attribute = yes; then : test $ax_sys_weak_alias = no && ax_sys_weak_alias=attribute $as_echo "#define HAVE_SYS_WEAK_ALIAS_ATTRIBUTE 1" >>confdefs.h fi # Test whether compiler accepts #pragma form of weak aliasing { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports #pragma weak" >&5 $as_echo_n "checking whether $CC supports #pragma weak... " >&6; } if ${ax_cv_sys_weak_alias_pragma+:} false; then : $as_echo_n "(cached) " >&6 else # Try linking with a weak alias... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern void weakf(int c); #pragma weak weakf = __weakf void __weakf(int c) {} int main () { weakf(0) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ax_cv_sys_weak_alias_pragma=yes else ax_cv_sys_weak_alias_pragma=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_sys_weak_alias_pragma" >&5 $as_echo "$ax_cv_sys_weak_alias_pragma" >&6; } # What was the result of the test? if test $ax_cv_sys_weak_alias_pragma = yes; then : test $ax_sys_weak_alias = no && ax_sys_weak_alias=pragma $as_echo "#define HAVE_SYS_WEAK_ALIAS_PRAGMA 1" >>confdefs.h fi # Test whether compiler accepts _HP_SECONDARY_DEF pragma from HP... { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports #pragma _HP_SECONDARY_DEF" >&5 $as_echo_n "checking whether $CC supports #pragma _HP_SECONDARY_DEF... " >&6; } if ${ax_cv_sys_weak_alias_hpsecondary+:} false; then : $as_echo_n "(cached) " >&6 else # Try linking with a weak alias... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern void weakf(int c); #pragma _HP_SECONDARY_DEF __weakf weakf void __weakf(int c) {} int main () { weakf(0) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ax_cv_sys_weak_alias_hpsecondary=yes else ax_cv_sys_weak_alias_hpsecondary=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_sys_weak_alias_hpsecondary" >&5 $as_echo "$ax_cv_sys_weak_alias_hpsecondary" >&6; } # What was the result of the test? if test $ax_cv_sys_weak_alias_hpsecondary = yes; then : test $ax_sys_weak_alias = no && ax_sys_weak_alias=hpsecondary $as_echo "#define HAVE_SYS_WEAK_ALIAS_HPSECONDARY 1" >>confdefs.h fi # Test whether compiler accepts "_CRI duplicate" pragma from Cray { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports #pragma _CRI duplicate" >&5 $as_echo_n "checking whether $CC supports #pragma _CRI duplicate... " >&6; } if ${ax_cv_sys_weak_alias_criduplicate+:} false; then : $as_echo_n "(cached) " >&6 else # Try linking with a weak alias... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern void weakf(int c); #pragma _CRI duplicate weakf as __weakf void __weakf(int c) {} int main () { weakf(0) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ax_cv_sys_weak_alias_criduplicate=yes else ax_cv_sys_weak_alias_criduplicate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_sys_weak_alias_criduplicate" >&5 $as_echo "$ax_cv_sys_weak_alias_criduplicate" >&6; } # What was the result of the test? if test $ax_cv_sys_weak_alias_criduplicate = yes; then : test $ax_sys_weak_alias = no && ax_sys_weak_alias=criduplicate $as_echo "#define HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE 1" >>confdefs.h fi # Do we actually support aliasing? { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create weak aliases with $CC" >&5 $as_echo_n "checking how to create weak aliases with $CC... " >&6; } if ${ax_cv_sys_weak_alias+:} false; then : $as_echo_n "(cached) " >&6 else ax_cv_sys_weak_alias=$ax_sys_weak_alias fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_sys_weak_alias" >&5 $as_echo "$ax_cv_sys_weak_alias" >&6; } # OK, set a #define if test $ax_cv_sys_weak_alias != no; then : $as_echo "#define HAVE_SYS_WEAK_ALIAS 1" >>confdefs.h fi # Can aliases cross object file boundaries? # Check to see if weak aliases can cross object file boundaries { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports weak aliases across object file boundaries" >&5 $as_echo_n "checking whether $CC supports weak aliases across object file boundaries... " >&6; } if ${ax_cv_sys_weak_alias_crossfile+:} false; then : $as_echo_n "(cached) " >&6 else if test $ax_cv_sys_weak_alias = no; then : ax_cv_sys_weak_alias_crossfile=no else # conftest1 contains our weak alias definition... cat >conftest1.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest1.$ac_ext cat >>conftest1.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifndef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE extern void weakf(int c); #if defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) #pragma weak weakf = __weakf #elif defined(HAVE_SYS_WEAK_ALIAS_HPSECONDARY) #pragma _HP_SECONDARY_DEF __weakf weakf #elif defined(HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE) #pragma _CRI duplicate weakf as __weakf #endif #endif void __weakf(int c) {} #ifdef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE void weakf(int c) __attribute((weak, alias("__weakf"))); #endif _ACEOF # And conftest2 contains our main routine that calls it cat >conftest2.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >> conftest2.$ac_ext cat >>conftest2.$ac_ext <<_ACEOF /* end confdefs.h. */ extern void weakf(int c); int main () { weakf(0); return 0; } _ACEOF # We must remove the object files (if any) ourselves... rm -f conftest2.$ac_objext conftest$ac_exeext # Change ac_link to compile *2* files together save_aclink=$ac_link ac_link=`echo "$ac_link" | \ sed -e 's/conftest\(\.\$ac_ext\)/conftest1\1 conftest2\1/'` # Since we created the files ourselves, don't use SOURCE argument if ac_fn_c_try_link "$LINENO"; then : ax_cv_sys_weak_alias_crossfile=yes else ax_cv_sys_weak_alias_crossfile=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext # Restore ac_link ac_link=$save_aclink # We must remove the object files (if any) and C files ourselves... rm -f conftest1.$ac_ext conftest2.$ac_ext \ conftest1.$ac_objext conftest2.$ac_objext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_sys_weak_alias_crossfile" >&5 $as_echo "$ax_cv_sys_weak_alias_crossfile" >&6; } # What were the results of the test? if test $ax_cv_sys_weak_alias_crossfile = yes; then : $as_echo "#define HAVE_SYS_WEAK_ALIAS_CROSSFILE 1" >>confdefs.h fi # OK, remember the results WEAK_ALIAS=$ax_cv_sys_weak_alias WEAK_ALIAS_CROSSFILE=$ax_cv_sys_weak_alias_crossfile if test x"${enable_backtrace}" != x"no" ; then backtrace_ok=no ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default" if test "x$ac_cv_header_execinfo_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5 $as_echo_n "checking for library containing backtrace... " >&6; } if ${ac_cv_search_backtrace+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char backtrace (); int main () { return backtrace (); ; return 0; } _ACEOF for ac_lib in '' execinfo; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib -lm $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_backtrace=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_backtrace+:} false; then : break fi done if ${ac_cv_search_backtrace+:} false; then : else ac_cv_search_backtrace=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace" >&5 $as_echo "$ac_cv_search_backtrace" >&6; } ac_res=$ac_cv_search_backtrace if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_GLIBC_BACKTRACE /**/" >>confdefs.h $as_echo "#define HAVE_STACK_TRACE /**/" >>confdefs.h backtrace_ok=yes fi fi if test x"${enable_backtrace}" = x"yes" -a x"${backtrace_ok}" = x"no"; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to find backtrace support See \`config.log' for more details" "$LINENO" 5; } fi fi ac_fn_c_check_header_compile "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif " if test "x$ac_cv_header_malloc_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mallinfo is available" >&5 $as_echo_n "checking whether mallinfo is available... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct mallinfo ac_x; ac_x = mallinfo (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_MALLINFO /**/" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi CONFDATE=`date '+%Y%m%d'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking directory to use for state file" >&5 $as_echo_n "checking directory to use for state file... " >&6; } if test "${prefix}" = "NONE"; then quagga_statedir_prefix=""; else quagga_statedir_prefix=${prefix} fi if test "${localstatedir}" = '${prefix}/var'; then for QUAGGA_STATE_DIR in ${quagga_statedir_prefix}/var/run ${quagga_statedir_prefix}/var/adm ${quagga_statedir_prefix}/etc /var/run /var/adm /etc /dev/null; do test -d $QUAGGA_STATE_DIR && break done quagga_statedir=$QUAGGA_STATE_DIR else quagga_statedir=${localstatedir} fi if test $quagga_statedir = "/dev/null"; then as_fn_error $? "'STATE DIRECTORY NOT FOUND! FIX OR SPECIFY --localstatedir!'" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${quagga_statedir}" >&5 $as_echo "${quagga_statedir}" >&6; } cat >>confdefs.h <<_ACEOF #define PATH_ZEBRA_PID "$quagga_statedir/zebra.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_RIPD_PID "$quagga_statedir/ripd.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_RIPNGD_PID "$quagga_statedir/ripngd.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_BGPD_PID "$quagga_statedir/bgpd.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_OSPFD_PID "$quagga_statedir/ospfd.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_OSPF6D_PID "$quagga_statedir/ospf6d.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_NHRPD_PID "$quagga_statedir/nhrpd.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_ISISD_PID "$quagga_statedir/isisd.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_PIMD_PID "$quagga_statedir/pimd.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_WATCHQUAGGA_PID "$quagga_statedir/watchquagga.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define ZEBRA_SERV_PATH "$quagga_statedir/zserv.api" _ACEOF cat >>confdefs.h <<_ACEOF #define ZEBRA_VTYSH_PATH "$quagga_statedir/zebra.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define RIP_VTYSH_PATH "$quagga_statedir/ripd.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define RIPNG_VTYSH_PATH "$quagga_statedir/ripngd.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define BGP_VTYSH_PATH "$quagga_statedir/bgpd.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define OSPF_VTYSH_PATH "$quagga_statedir/ospfd.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define OSPF6_VTYSH_PATH "$quagga_statedir/ospf6d.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define NHRP_VTYSH_PATH "$quagga_statedir/nhrpd.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define ISIS_VTYSH_PATH "$quagga_statedir/isisd.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define PIM_VTYSH_PATH "$quagga_statedir/pimd.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define DAEMON_VTY_DIR "$quagga_statedir" _ACEOF $as_echo "#define QUAGGA_NO_DEPRECATED_INTERFACES 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working htonl" >&5 $as_echo_n "checking for working htonl... " >&6; } if ${ac_cv_htonl_works+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #if HAVE_NET_IF_H # include #endif #if HAVE_NET_IF_VAR_H # include #endif #if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif #if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif int main () { htonl (0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_htonl_works=yes else ac_cv_htonl_works=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_htonl_works" >&5 $as_echo "$ac_cv_htonl_works" >&6; } ac_config_files="$ac_config_files Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile pimd/Makefile nhrpd/Makefile redhat/Makefile pkgsrc/Makefile fpm/Makefile redhat/quagga.spec redhat/quagga.sysconfig lib/version.h isisd/topology/Makefile pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh" ac_config_files="$ac_config_files solaris/Makefile" ac_config_files="$ac_config_files vtysh/extract.pl" ## Hack, but working solution to avoid rebuilding of quagga.info. ## It's already in CVS until texinfo 4.7 is more common. 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, we kill variables containing newlines. # 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. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}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 "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} 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}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_LATEX_TRUE}" && test -z "${HAVE_LATEX_FALSE}"; then as_fn_error $? "conditional \"HAVE_LATEX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PANDOC_TRUE}" && test -z "${HAVE_PANDOC_FALSE}"; then as_fn_error $? "conditional \"HAVE_PANDOC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DEV_BUILD_TRUE}" && test -z "${DEV_BUILD_FALSE}"; then as_fn_error $? "conditional \"DEV_BUILD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PROTOBUF_TRUE}" && test -z "${HAVE_PROTOBUF_FALSE}"; then as_fn_error $? "conditional \"HAVE_PROTOBUF\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${GIT_VERSION_TRUE}" && test -z "${GIT_VERSION_FALSE}"; then as_fn_error $? "conditional \"GIT_VERSION\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${VTYSH_TRUE}" && test -z "${VTYSH_FALSE}"; then as_fn_error $? "conditional \"VTYSH\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_NETLINK_TRUE}" && test -z "${HAVE_NETLINK_FALSE}"; then as_fn_error $? "conditional \"HAVE_NETLINK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ZEBRA_TRUE}" && test -z "${ZEBRA_FALSE}"; then as_fn_error $? "conditional \"ZEBRA\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BGPD_TRUE}" && test -z "${BGPD_FALSE}"; then as_fn_error $? "conditional \"BGPD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${RIPD_TRUE}" && test -z "${RIPD_FALSE}"; then as_fn_error $? "conditional \"RIPD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OSPFD_TRUE}" && test -z "${OSPFD_FALSE}"; then as_fn_error $? "conditional \"OSPFD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${NHRPD_TRUE}" && test -z "${NHRPD_FALSE}"; then as_fn_error $? "conditional \"NHRPD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WATCHQUAGGA_TRUE}" && test -z "${WATCHQUAGGA_FALSE}"; then as_fn_error $? "conditional \"WATCHQUAGGA\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OSPFCLIENT_TRUE}" && test -z "${OSPFCLIENT_FALSE}"; then as_fn_error $? "conditional \"OSPFCLIENT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${RIPNGD_TRUE}" && test -z "${RIPNGD_FALSE}"; then as_fn_error $? "conditional \"RIPNGD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OSPF6D_TRUE}" && test -z "${OSPF6D_FALSE}"; then as_fn_error $? "conditional \"OSPF6D\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ISISD_TRUE}" && test -z "${ISISD_FALSE}"; then as_fn_error $? "conditional \"ISISD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PIMD_TRUE}" && test -z "${PIMD_FALSE}"; then as_fn_error $? "conditional \"PIMD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $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} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= 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 IFS=$as_save_IFS ;; 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 $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; 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 if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # 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 ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # 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'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by Quagga $as_me 1.2.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent 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_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Quagga config.status 1.2.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. 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=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; 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 || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile' ac_aux_dir='$ac_aux_dir' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; "qpb/Makefile") CONFIG_FILES="$CONFIG_FILES qpb/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" ;; "watchquagga/Makefile") CONFIG_FILES="$CONFIG_FILES watchquagga/Makefile" ;; "ospf6d/Makefile") CONFIG_FILES="$CONFIG_FILES ospf6d/Makefile" ;; "isisd/Makefile") CONFIG_FILES="$CONFIG_FILES isisd/Makefile" ;; "vtysh/Makefile") CONFIG_FILES="$CONFIG_FILES vtysh/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "ospfclient/Makefile") CONFIG_FILES="$CONFIG_FILES ospfclient/Makefile" ;; "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; "m4/Makefile") CONFIG_FILES="$CONFIG_FILES m4/Makefile" ;; "pimd/Makefile") CONFIG_FILES="$CONFIG_FILES pimd/Makefile" ;; "nhrpd/Makefile") CONFIG_FILES="$CONFIG_FILES nhrpd/Makefile" ;; "redhat/Makefile") CONFIG_FILES="$CONFIG_FILES redhat/Makefile" ;; "pkgsrc/Makefile") CONFIG_FILES="$CONFIG_FILES pkgsrc/Makefile" ;; "fpm/Makefile") CONFIG_FILES="$CONFIG_FILES fpm/Makefile" ;; "redhat/quagga.spec") CONFIG_FILES="$CONFIG_FILES redhat/quagga.spec" ;; "redhat/quagga.sysconfig") CONFIG_FILES="$CONFIG_FILES redhat/quagga.sysconfig" ;; "lib/version.h") CONFIG_FILES="$CONFIG_FILES lib/version.h" ;; "isisd/topology/Makefile") CONFIG_FILES="$CONFIG_FILES isisd/topology/Makefile" ;; "pkgsrc/bgpd.sh") CONFIG_FILES="$CONFIG_FILES pkgsrc/bgpd.sh" ;; "pkgsrc/ospf6d.sh") CONFIG_FILES="$CONFIG_FILES pkgsrc/ospf6d.sh" ;; "pkgsrc/ospfd.sh") CONFIG_FILES="$CONFIG_FILES pkgsrc/ospfd.sh" ;; "pkgsrc/ripd.sh") CONFIG_FILES="$CONFIG_FILES pkgsrc/ripd.sh" ;; "pkgsrc/ripngd.sh") CONFIG_FILES="$CONFIG_FILES pkgsrc/ripngd.sh" ;; "pkgsrc/zebra.sh") CONFIG_FILES="$CONFIG_FILES pkgsrc/zebra.sh" ;; "solaris/Makefile") CONFIG_FILES="$CONFIG_FILES solaris/Makefile" ;; "vtysh/extract.pl") CONFIG_FILES="$CONFIG_FILES vtysh/extract.pl" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; 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 against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries 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[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #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. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # 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. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;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&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf 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. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_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 # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. 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 " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain=$ac_aux_dir/ltmain.sh # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; "vtysh/extract.pl":F) chmod +x vtysh/extract.pl ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # 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 || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi echo " Quagga configuration -------------------- quagga version : ${PACKAGE_VERSION} host operating system : ${host_os} source code location : ${srcdir} compiler : ${CC} compiler flags : ${CFLAGS} make : ${MAKE-make} linker flags : ${LDFLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} state file directory : ${quagga_statedir} config file directory : `eval echo \`echo ${sysconfdir}\`` example directory : `eval echo \`echo ${exampledir}\`` user to run as : ${enable_user} group to run as : ${enable_group} group for vty sockets : ${enable_vty_group} config file mask : ${enable_configfile_mask} log file mask : ${enable_logfile_mask} zebra protobuf enabled : ${have_protobuf:-no} The above user and group must have read/write access to the state file directory and to the config files in the config file directory." if test x"$quagga_cv_gnu_make" = x"no"; then echo " Warning: The ${MAKE-make} programme detected, either in your path or via the MAKE variable, is not GNU Make. GNU make may be installed as gmake on some systems. and is required to complete a build of Quagga " > /dev/stderr fi quagga-1.2.4/configure.ac000077500000000000000000001501651325323223500152640ustar00rootroot00000000000000## ## Configure template file for Quagga. ## autoconf will generate configure script. ## ## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro ## Portions Copyright (c) 2003 Paul Jakma ## AC_PREREQ(2.60) AC_INIT(Quagga, 1.2.4, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) dnl ----------------------------------- dnl Get hostname and other information. dnl ----------------------------------- AC_CANONICAL_BUILD() AC_CANONICAL_HOST() AC_CANONICAL_TARGET() # Disable portability warnings -- our automake code (in particular # common.am) uses some constructs specific to gmake. AM_INIT_AUTOMAKE([1.6 -Wno-portability]) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])]) AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS(config.h) AC_PATH_PROG(PERL, perl) AC_CHECK_PROG([GAWK],[gawk],[gawk],[not-in-PATH]) if test "x$GAWK" = "xnot-in-PATH" ; then AC_MSG_ERROR([GNU awk is required for lib/memtype.h made by memtypes.awk. BSD awk complains: awk: gensub doesn't support backreferences (subst "\1") ]) fi AC_ARG_VAR([GAWK],[GNU AWK]) dnl default is to match previous behavior exampledir=${sysconfdir} AC_ARG_ENABLE([exampledir], AS_HELP_STRING([--enable-exampledir], [specify alternate directory for examples]), exampledir="$enableval",) dnl XXX add --exampledir to autoconf standard directory list somehow AC_SUBST(exampledir) dnl default is to match previous behavior pkgsrcrcdir="" pkgsrcdir="" AC_ARG_ENABLE([pkgsrcrcdir], AS_HELP_STRING([--enable-pkgsrcrcdir], [specify directory for rc.d scripts]), pkgsrcrcdir="$enableval"; pkgsrcdir="pkgsrc",) dnl XXX add --pkgsrcrcdir to autoconf standard directory list somehow AC_SUBST(pkgsrcdir) AC_SUBST(pkgsrcrcdir) 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 CC and friends dnl -------------------- AC_LANG([C]) AC_PROG_CC AC_PROG_CPP AM_PROG_CC_C_O AC_PROG_EGREP PKG_PROG_PKG_CONFIG AC_PROG_CC_C99 dnl libtool prereq. AC_USE_SYSTEM_EXTENSIONS dnl ------- dnl libtool dnl ------- LT_INIT dnl create libtool now, so we can test version below for dnl fstack-protector-strong LT_OUTPUT dnl autoconf 2.59 appears not to support AC_PROG_SED dnl AC_PROG_SED AC_CHECK_PROG([SED],[sed],[sed],[/bin/false]) dnl Check for pdflatex and latexmk, in case someone wants to build dnl PDFs from TeX (as used to be case for HACKING) AC_CHECK_PROG([PDFLATEX],[pdflatex],[pdflatex],[/bin/false]) AC_CHECK_PROG([LATEXMK],[latexmk],[latexmk],[/bin/false]) if test "x$PDFLATEX" = "x/bin/false" -o "x$LATEXMK" = "x/bin/false"; then AC_MSG_WARN([Will not be able to make PDF versions of TeX documents]) else HAVE_LATEX=true fi AM_CONDITIONAL([HAVE_LATEX], [test "x$HAVE_LATEX" = "xtrue"]) dnl for making HACKING.pdf from HACKING.md using pandoc AC_CHECK_PROG([PANDOC],[pandoc],[pandoc],[/bin/false]) if test "x$PDFLATEX" = "x/bin/false" -o "x$PANDOC" = "x/bin/false"; then AC_MSG_WARN([Will not be able to make PDF versions of MD documents]) else HAVE_PANDOC=true fi AM_CONDITIONAL([HAVE_PANDOC], [test "x$HAVE_PANDOC" = "xtrue"]) if test "x${GCC}" != "xyes" ; then AC_MSG_CHECKING([whether we are using SunPro compiler]) AC_EGREP_CPP([^__SUNPRO_C.*0x5(7|8|9)], ["__SUNPRO_C" __SUNPRO_C], [COMPILER="SUNPRO" AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])] ) fi dnl --------------------------------------------- dnl If CLFAGS doesn\'t exist set default value dnl AC_PROG_CC will have set minimal default dnl already, eg "-O2 -g" for gcc, "-g" for others dnl (Wall is gcc specific... have to make sure dnl gcc is being used before setting it) dnl dnl Sun Studio 10 / SunPro 5.7 is also supported, dnl so lets set some sane CFLAGS for it. dnl --------------------------------------------- AC_DEFUN([AC_C_FLAG], [{ AC_LANG_PUSH(C) ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS $1" AC_MSG_CHECKING([[whether $CC supports $1]]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[]])], [ AC_MSG_RESULT([yes]) m4_if([$3], [], [], [ CFLAGS="$ac_c_flag_save" $3 ]) ], [ CFLAGS="$ac_c_flag_save" AC_MSG_RESULT([no]) $2 ]) AC_LANG_POP(C) }]) AC_MSG_CHECKING([which default CFLAGS to set]) if test "x${cflags_specified}" = "x" ; then case ${COMPILER} in "SUNPRO") AC_MSG_RESULT([Sun Studio]) AC_C_FLAG([-g]) AC_C_FLAG([-xO4]) AC_C_FLAG([-xspace]) AC_C_FLAG([-xstrconst]) AC_C_FLAG([-xc99]) AC_C_FLAG([-errfmt]) AC_C_FLAG([-xipo]) dnl AC_C_FLAG([-xlinkopt=2]) SPARC only dnl dnl AC_C_FLAG([-xcode=pic32])dnl ;; *) AC_MSG_RESULT([autodetecting]) AC_C_FLAG([-diag-error 10006]) AC_C_FLAG([-g]) AC_C_FLAG([-Os], [ AC_C_FLAG([-O2]) ]) dnl fstack-protector-strong gives __stack_chk_fail_local dnl being an 'Undefined symbol' on OpenIndiana hipster, with gcc 6. dnl gcc -shared is being used to do the link, however the error is dnl from ld. Disable. An issue with libtool < 2.4.6 dropping the dnl -fstack-protector-strong argument from the shared link. AC_MSG_CHECKING([whether libtool can support fstack-protector]) if test x"$(./libtool --version | awk 'NR == 1 { print $NF }' \ | awk -F. '{ \ if ($(NF-2) < 2) print 0; \ else if ($(NF-2) > 2) print 1; \ else if ($(NF-1) < 4) print 0; \ else if ($(NF-1) > 4) print 1; \ else if ($NF < 6) print 0; \ else print 1; \ }')" = "x1" ; then AC_MSG_RESULT([yes]) AC_C_FLAG([-fstack-protector-strong]) AC_C_FLAG([--param=ssp-buffer-size=4]) else AC_MSG_RESULT([no]) AC_MSG_WARN([upgrade to libtool >= 2.4.6!]) fi AC_C_FLAG([-D_FORTIFY_SOURCE=2]) AC_C_FLAG([-Wformat]) AC_C_FLAG([-Wformat-security]) AC_C_FLAG([-fpie]) AC_C_FLAG([-fno-omit-frame-pointer]) AC_C_FLAG([-Wall]) AC_C_FLAG([-Wextra]) AC_C_FLAG([-Wmissing-prototypes]) AC_C_FLAG([-Wmissing-declarations]) AC_C_FLAG([-Wpointer-arith]) AC_C_FLAG([-Wbad-function-cast]) AC_C_FLAG([-Wwrite-strings]) if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then AC_C_FLAG([-Wcast-qual]) AC_C_FLAG([-Wstrict-prototypes]) AC_C_FLAG([-Wmissing-noreturn]) AC_C_FLAG([-Wmissing-format-attribute]) AC_C_FLAG([-Wunreachable-code]) AC_C_FLAG([-Wpacked]) AC_C_FLAG([-Wpadded]) else AC_C_FLAG([-Wno-unused-result]) fi AC_C_FLAG([-Wno-unused-parameter]) AC_C_FLAG([-Wno-missing-field-initializers]) # ICC emits a broken warning for const char *x = a ? "b" : "c"; # for some reason the string consts get 'promoted' to char *, # triggering a const to non-const conversion warning. AC_C_FLAG([-diag-disable 3179]) ;; esac else AC_MSG_RESULT([CFLAGS supplied by user]) fi if test x"${enable_werror}" = x"yes" ; then WERROR="-Werror" fi AC_SUBST(WERROR) dnl -------------- dnl Check programs dnl -------------- AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_CHECK_TOOL(AR, ar) dnl --------------------------- dnl We, perhaps unfortunately, dnl depend on GNU Make specific dnl constructs. dnl Give the user a warning if dnl not GNU Make. dnl --------------------------- AC_CACHE_CHECK([if ${MAKE-make} is GNU make], [quagga_cv_gnu_make], [quagga_cv_gnu_make=no if ${MAKE-make} --version 2>/dev/null | \ grep '^GNU Make ' >/dev/null ; then quagga_cv_gnu_make=yes; fi ] ) dnl ----------------- dnl System extensions dnl ----------------- AC_GNU_SOURCE dnl ---------------------- dnl Packages configuration dnl ---------------------- AC_ARG_WITH(pkg-extra-version, AS_HELP_STRING([--with-pkg-extra-version=VER], [add extra version field, for packagers/distributions]), [EXTRAVERSION=$withval],) AC_ARG_WITH(pkg-git-version, AS_HELP_STRING([--with-pkg-git-version], [add git information to MOTD and build version string]), [ test "x$withval" != "xno" && with_pkg_git_version="yes" ]) AC_ARG_ENABLE(vtysh, AS_HELP_STRING([--disable-vtysh], [do not build integrated vty shell for Quagga])) AC_ARG_ENABLE(doc, AS_HELP_STRING([--disable-doc], [do not build docs])) AC_ARG_ENABLE(zebra, AS_HELP_STRING([--disable-zebra], [do not build zebra daemon])) AC_ARG_ENABLE(bgpd, AS_HELP_STRING([--disable-bgpd], [do not build bgpd])) AC_ARG_ENABLE(ripd, AS_HELP_STRING([--disable-ripd], [do not build ripd])) AC_ARG_ENABLE(ripngd, AS_HELP_STRING([--disable-ripngd], [do not build ripngd])) AC_ARG_ENABLE(ospfd, AS_HELP_STRING([--disable-ospfd], [do not build ospfd])) AC_ARG_ENABLE(ospf6d, AS_HELP_STRING([--disable-ospf6d], [do not build ospf6d])) AC_ARG_ENABLE(nhrpd, AS_HELP_STRING([--disable-nhrpd], [do not build nhrpd])) AC_ARG_ENABLE(watchquagga, AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga])) AC_ARG_ENABLE(isisd, AS_HELP_STRING([--disable-isisd], [do not build isisd])) AC_ARG_ENABLE(pimd, AS_HELP_STRING([--disable-pimd], [do not build pimd])) AC_ARG_ENABLE(bgp-announce, AS_HELP_STRING([--disable-bgp-announce,], [turn off BGP route announcement])) AC_ARG_ENABLE(snmp, AS_HELP_STRING([--enable-snmp=ARG], [enable SNMP support (smux or agentx)])) AC_ARG_WITH(libpam, AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh])) AC_ARG_ENABLE(tcp-zebra, AS_HELP_STRING([--enable-tcp-zebra], [enable TCP/IP socket connection between zebra and protocol daemon])) AC_ARG_ENABLE(ospfapi, AS_HELP_STRING([--disable-ospfapi], [do not build OSPFAPI to access the OSPF LSA Database])) AC_ARG_ENABLE(ospfclient, AS_HELP_STRING([--disable-ospfclient], [do not build OSPFAPI client for OSPFAPI, (this is the default if --disable-ospfapi is set)])) AC_ARG_ENABLE(multipath, AS_HELP_STRING([--enable-multipath=ARG], [enable multipath function, ARG must be digit])) AC_ARG_ENABLE(user, AS_HELP_STRING([--enable-user=USER], [user to run Quagga suite as (default quagga)])) AC_ARG_ENABLE(group, AS_HELP_STRING([--enable-group=GROUP], [group to run Quagga suite as (default quagga)])) AC_ARG_ENABLE(vty_group, AS_HELP_STRING([--enable-vty-group=ARG], [set vty sockets to have specified group as owner])) AC_ARG_ENABLE(configfile_mask, AS_HELP_STRING([--enable-configfile-mask=ARG], [set mask for config files])) AC_ARG_ENABLE(logfile_mask, AS_HELP_STRING([--enable-logfile-mask=ARG], [set mask for log files])) AC_ARG_ENABLE(rtadv, AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature])) AC_ARG_ENABLE(irdp, AS_HELP_STRING([--enable-irdp], [enable IRDP server support in zebra])) AC_ARG_ENABLE(isis_topology, AS_HELP_STRING([--enable-isis-topology], [enable IS-IS topology generator])) AC_ARG_ENABLE(capabilities, AS_HELP_STRING([--disable-capabilities], [disable using POSIX capabilities])) AC_ARG_ENABLE(rusage, AS_HELP_STRING([--disable-rusage], [disable using getrusage])) AC_ARG_ENABLE(gcc_ultra_verbose, AS_HELP_STRING([--enable-gcc-ultra-verbose], [enable ultra verbose GCC warnings])) AC_ARG_ENABLE(linux24_tcp_md5, AS_HELP_STRING([--enable-linux24-tcp-md5], [enable support for old, Linux-2.4 RFC2385 patch])) AC_ARG_ENABLE(gcc-rdynamic, AS_HELP_STRING([--enable-gcc-rdynamic], [enable linking with -rdynamic for better backtraces (default if gcc)])) AC_ARG_ENABLE(backtrace, AS_HELP_STRING([--disable-backtrace,], [disable crash backtraces (default autodetect)])) AC_ARG_ENABLE(time-check, AS_HELP_STRING([--disable-time-check], [disable slow thread warning messages])) AC_ARG_ENABLE(pcreposix, AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions])) AC_ARG_ENABLE(fpm, AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support])) AC_ARG_ENABLE(werror, AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)])) AC_ARG_ENABLE([protobuf], AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support])) AC_ARG_ENABLE([dev_build], AS_HELP_STRING([--enable-dev-build], [build for development])) if test x"${enable_gcc_rdynamic}" != x"no" ; then if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then LDFLAGS="${LDFLAGS} -rdynamic" fi fi if test x"${enable_time_check}" != x"no" ; then if test x"${enable_time_check}" = x"yes" -o x"${enable_time_check}" = x ; then AC_DEFINE(CONSUMED_TIME_CHECK,5000000,Consumed Time Check) else AC_DEFINE_UNQUOTED(CONSUMED_TIME_CHECK,$enable_time_check,Consumed Time Check) fi fi if test "${enable_fpm}" = "yes"; then AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support) fi if test "x${enable_dev_build}" = "xyes"; then AC_DEFINE(DEV_BUILD,,Build for development) fi AM_CONDITIONAL([DEV_BUILD], [test "x$enable_dev_build" = "xyes"]) # # Logic for protobuf support. # if test "$enable_protobuf" = "yes"; then have_protobuf=yes # Check for protoc-c AC_CHECK_PROG([PROTOC_C], [protoc-c], [protoc-c], [/bin/false]) if test "x$PROTOC_C" = "x/bin/false"; then have_protobuf=no else found_protobuf_c=no PKG_CHECK_MODULES([PROTOBUF_C], libprotobuf-c >= 0.14, [found_protobuf_c=yes], [AC_MSG_RESULT([pkg-config did not find libprotobuf-c])]) if test "x$found_protobuf_c" = "xyes"; then LDFLAGS="$LDFLAGS $PROTOBUF_C_LIBS" CFLAGS="$CFLAGS $PROTOBUF_C_CFLAGS" else AC_CHECK_HEADER([google/protobuf-c/protobuf-c.h], [], [have_protobuf=no; AC_MSG_RESULT([Couldn't find google/protobuf-c.h])]) fi fi fi # Fail if the user explicity enabled protobuf support and we couldn't # find the compiler or libraries. if test "x$have_protobuf" = "xno" && test "x$enable_protobuf" = "xyes"; then AC_MSG_ERROR([Protobuf enabled explicitly but can't find libraries/tools]) fi if test "x$have_protobuf" = "xyes"; then AC_DEFINE(HAVE_PROTOBUF,, protobuf) fi AM_CONDITIONAL([HAVE_PROTOBUF], [test "x$have_protobuf" = "xyes"]) # # End of logic for protobuf support. # if test "${enable_tcp_zebra}" = "yes"; then AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) fi if test "${enable_linux24_tcp_md5}" = "yes"; then AC_DEFINE(HAVE_TCP_MD5_LINUX24,,Old Linux 2.4 TCP MD5 Signature Patch) fi AC_MSG_CHECKING(if zebra should be configurable to send Route Advertisements) if test "${enable_rtadv}" != "no"; then AC_MSG_RESULT(yes) AC_DEFINE(HAVE_RTADV,,Enable IPv6 Routing Advertisement support) else AC_MSG_RESULT(no) fi if test "${enable_irdp}" = "yes"; then AC_DEFINE(HAVE_IRDP,, IRDP ) fi if test "${enable_isisd}" != "no" && test "${enable_isis_topology}" = yes; then AC_DEFINE(TOPOLOGY_GENERATE,,Enable IS-IS topology generator code) ISIS_TOPOLOGY_INCLUDES="-I\$(srcdir)/topology" ISIS_TOPOLOGY_DIR="topology" ISIS_TOPOLOGY_LIB="./topology/libtopology.a" fi AC_SUBST(ISIS_TOPOLOGY_INCLUDES) AC_SUBST(ISIS_TOPOLOGY_DIR) AC_SUBST(ISIS_TOPOLOGY_LIB) if test x"${enable_user}" = x"no"; then enable_user="" else if test x"${enable_user}" = x"yes" || test x"${enable_user}" = x""; then enable_user="quagga" fi AC_DEFINE_UNQUOTED(QUAGGA_USER, "${enable_user}", Quagga User) fi if test x"${enable_group}" = x"no"; then enable_group="" else if test x"${enable_group}" = x"yes" || test x"${enable_group}" = x""; then enable_group="quagga" fi AC_DEFINE_UNQUOTED(QUAGGA_GROUP, "${enable_group}", Quagga Group) fi if test x"${enable_vty_group}" = x"yes" ; then AC_MSG_ERROR([--enable-vty-group requires a group as argument, not yes]) elif test x"${enable_vty_group}" != x""; then if test x"${enable_vty_group}" != x"no"; then AC_DEFINE_UNQUOTED(VTY_GROUP, "${enable_vty_group}", VTY Sockets Group) fi fi AC_SUBST([enable_user]) AC_SUBST([enable_group]) AC_SUBST([enable_vty_group]) enable_configfile_mask=${enable_configfile_mask:-0600} AC_DEFINE_UNQUOTED(CONFIGFILE_MASK, ${enable_configfile_mask}, Mask for config files) enable_logfile_mask=${enable_logfile_mask:-0600} AC_DEFINE_UNQUOTED(LOGFILE_MASK, ${enable_logfile_mask}, Mask for log files) MPATH_NUM=1 case "${enable_multipath}" in 0) MPATH_NUM=64 ;; [[1-9]|[1-9][0-9]|[1-9][0-9][0-9]]) MPATH_NUM="${enable_multipath}" ;; "") ;; *) AC_MSG_FAILURE([Please specify digit to enable multipath ARG]) ;; esac AC_DEFINE_UNQUOTED(MULTIPATH_NUM, $MPATH_NUM, Maximum number of paths for a route) dnl ----------------------------------- dnl Add extra version string to package dnl name, string and version fields. dnl ----------------------------------- if test "x${EXTRAVERSION}" != "x" ; then VERSION="${VERSION}${EXTRAVERSION}" PACKAGE_VERSION="${PACKAGE_VERSION}${EXTRAVERSION}" PACKAGE_STRING="${PACKAGE_STRING}${EXTRAVERSION}" fi if test "x$with_pkg_git_version" = "xyes"; then if test -d "${srcdir}/.git"; then AC_DEFINE(GIT_VERSION, [1], [include git version info]) else with_pkg_git_version="no" AC_MSG_WARN([--with-pkg-git-version given, but this is not a git checkout]) fi fi AM_CONDITIONAL([GIT_VERSION], [test "x$with_pkg_git_version" = "xyes"]) dnl ------------------------------------ dnl Check C keywords and standard types dnl ------------------------------------ AC_C_CONST AC_C_INLINE AC_C_RESTRICT AC_C_VOLATILE AC_HEADER_STDC AC_HEADER_TIME AC_HEADER_SYS_WAIT AC_HEADER_STDBOOL dnl AC_TYPE_PID_T AC_TYPE_UID_T AC_TYPE_MODE_T AC_TYPE_SIZE_T AC_STRUCT_TM dnl ------------------------- dnl Check other header files. dnl ------------------------- AC_CHECK_HEADERS([stropts.h sys/ksym.h sys/times.h sys/select.h \ sys/types.h linux/version.h netdb.h asm/types.h \ sys/cdefs.h sys/param.h limits.h signal.h \ sys/socket.h netinet/in.h time.h sys/time.h features.h]) dnl Utility macro to avoid retyping includes all the time m4_define([QUAGGA_INCLUDES], [#ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #include #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_TYPES_H # include #endif /* sys/conf.h depends on param.h on FBSD at least */ #if HAVE_SYS_PARAM_H # include #endif /* Required for MAXSIG */ #if HAVE_SIGNAL_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #ifdef __APPLE__ # define __APPLE_USE_RFC_3542 #endif #if HAVE_NETINET_IN_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ ])dnl dnl HAVE_NET_IF_H must be discovered by the time the longer AC_CHECK_HEADERS dnl round below execution begins, otherwise it doesn't properly detect dnl HAVE_NETINET6_IN6_VAR_H, HAVE_NET_IF_VAR_H and HAVE_STRUCT_IN6_ALIASREQ dnl on FreeBSD (BZ#408). AC_CHECK_HEADERS([net/if.h], [], [], QUAGGA_INCLUDES) m4_define([QUAGGA_INCLUDES], QUAGGA_INCLUDES [#if HAVE_NET_IF_H # include #endif ])dnl dnl Same applies for HAVE_NET_IF_VAR_H, which HAVE_NETINET6_ND6_H and dnl HAVE_NETINET_IN_VAR_H depend upon. But if_var.h depends on if.h, hence dnl an additional round for it. AC_CHECK_HEADERS([net/if_var.h], [], [], QUAGGA_INCLUDES) m4_define([QUAGGA_INCLUDES], QUAGGA_INCLUDES [#if HAVE_NET_IF_VAR_H # include #endif ])dnl AC_CHECK_HEADERS([sys/un.h netinet/in_systm.h netinet/in_var.h \ net/if_dl.h net/netopt.h net/route.h \ inet/nd.h arpa/inet.h netinet/ip_icmp.h \ fcntl.h stddef.h sys/ioctl.h syslog.h wchar.h wctype.h \ sys/sysctl.h sys/sockio.h kvm.h sys/conf.h], [], [], QUAGGA_INCLUDES) AC_CHECK_HEADERS([ucontext.h], [], [], [#ifndef __USE_GNU #define __USE_GNU #endif /* __USE_GNU */ QUAGGA_INCLUDES ]) m4_define([UCONTEXT_INCLUDES], [#include ])dnl AC_CHECK_MEMBERS([ucontext_t.uc_mcontext.uc_regs], [], [], [UCONTEXT_INCLUDES]) AC_CHECK_MEMBERS([ucontext_t.uc_mcontext.regs], [AC_CHECK_MEMBERS([ucontext_t.uc_mcontext.regs.nip], [], [], [UCONTEXT_INCLUDES])], [], [UCONTEXT_INCLUDES]) AC_CHECK_MEMBERS([ucontext_t.uc_mcontext.gregs], [], [], [UCONTEXT_INCLUDES]) m4_define([QUAGGA_INCLUDES], QUAGGA_INCLUDES [#if HAVE_SYS_UN_H # include #endif #if HAVE_NETINET_IN_SYSTM_H # include #endif #if HAVE_NETINET_IN_VAR_H # include #endif #if HAVE_NET_IF_DL_H # include #endif #if HAVE_NET_NETOPT_H # include #endif #if HAVE_NET_ROUTE_H # include #endif #if HAVE_INET_ND_H # include #endif #if HAVE_ARPA_INET_H # include #endif /* Required for IDRP */ #if HAVE_NETINET_IP_ICMP_H # include #endif ])dnl dnl V6 headers are checked below, after we check for v6 dnl Some systems (Solaris 2.x) require libnsl (Network Services Library) case "$host" in [*-sunos5.[6-7]*] | [*-solaris2.[6-7]*]) opsys=sol2-6 AC_DEFINE(SUNOS_56, 1, SunOS 5.6 to 5.7) AC_DEFINE(SUNOS_5, 1, SunOS 5) AC_CHECK_LIB(xnet, main) CURSES=-lcurses SOLARIS="solaris" ;; [*-sunos5.[8-9]] \ | [*-sunos5.1[0-9]] \ | [*-sunos5.1[0-9].[0-9]] \ | [*-solaris2.[8-9]] \ | [*-solaris2.1[0-9]] \ | [*-solaris2.1[0-9].[0-9]]) opsys=sol8 AC_DEFINE(SUNOS_59, 1, [SunOS 5.8 up]) AC_DEFINE(SUNOS_5, 1, [SunOS 5]) AC_CHECK_LIB(socket, main) AC_CHECK_LIB(nsl, main) AC_CHECK_LIB(umem, main) AC_CHECK_FUNCS([printstack], [AC_DEFINE([HAVE_PRINTSTACK],1,[Solaris printstack]) AC_DEFINE([HAVE_STACK_TRACE],1,[Stack symbols decode functionality]) ]) CURSES=-lcurses SOLARIS="solaris" ;; *-sunos5* | *-solaris2*) AC_DEFINE(SUNOS_5,,SunOS 5, Unknown SunOS) AC_CHECK_LIB(socket, main) AC_CHECK_LIB(nsl, main) CURSES=-lcurses SOLARIS="solaris" ;; *-linux*) opsys=gnu-linux AC_DEFINE(GNU_LINUX,,GNU Linux) ;; *-openbsd*) opsys=openbsd AC_DEFINE(OPEN_BSD,,OpenBSD) ;; esac AC_SYS_LARGEFILE dnl --------------------- dnl Integrated VTY option dnl --------------------- case "${enable_vtysh}" in "no") VTYSH="";; *) VTYSH="vtysh"; AC_DEFINE(VTYSH,,VTY shell) dnl Vtysh uses libreadline, which looks for termcap functions at dnl configure time. We follow readlines search order. dnl The required procedures are in libtermcap on NetBSD, in dnl [TODO] on Linux, and in [TODO] on Solaris. AC_CHECK_LIB(termcap, tputs, LIBREADLINE="$LIBREADLINE -ltermcap", [AC_CHECK_LIB(tinfo, tputs, LIBREADLINE="$LIBREADLINE -ltinfo", [AC_CHECK_LIB(curses, tputs, LIBREADLINE="$LIBREADLINE -lcurses", [AC_CHECK_LIB(ncurses, tputs, LIBREADLINE="$LIBREADLINE -lncurses")] )] )] ) AC_CHECK_LIB(readline, main, LIBREADLINE="-lreadline $LIBREADLINE",, "$LIBREADLINE") if test $ac_cv_lib_readline_main = no; then AC_MSG_ERROR([vtysh needs libreadline but was not found and usable 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 AC_CHECK_LIB(readline, rl_completion_matches, LIBREADLINE="$LIBREADLINE",, "$LIBREADLINE") if test $ac_cv_lib_readline_rl_completion_matches = no; then AC_DEFINE(rl_completion_matches,completion_matches,Old readline) fi ;; "no" ) VTYSH="";; esac AC_SUBST(LIBREADLINE) AM_CONDITIONAL(VTYSH, test "x$VTYSH" = "xvtysh") dnl ---------- dnl PAM module dnl dnl Quagga detects the PAM library it is built against by checking for a dnl functional pam_misc.h (Linux-PAM) or openpam.h (OpenPAM) header. pam_misc.h dnl is known to #include pam_appl.h, the standard header of a PAM library, and dnl openpam.h doesn't do that, although depends on the header too. Hence a dnl little assistance to AC_CHECK_HEADER is necessary for the proper detection dnl of OpenPAM. dnl ---------- if test "$with_libpam" = "yes"; then AC_CHECK_HEADER([security/pam_misc.h], [AC_DEFINE(HAVE_PAM_MISC_H,,Have pam_misc.h) AC_DEFINE(PAM_CONV_FUNC,misc_conv,Have misc_conv) pam_conv_func="misc_conv" ], [], QUAGGA_INCLUDES) AC_CHECK_HEADER([security/openpam.h], [AC_DEFINE(HAVE_OPENPAM_H,,Have openpam.h) AC_DEFINE(PAM_CONV_FUNC,openpam_ttyconv,Have openpam_ttyconv) pam_conv_func="openpam_ttyconv" ], [], QUAGGA_INCLUDES[#include ]) if test -z "$ac_cv_header_security_pam_misc_h$ac_cv_header_security_openpam_h" ; then AC_MSG_WARN([*** pam support will not be built ***]) with_libpam="no" fi fi if test "$with_libpam" = "yes"; then dnl took this test from proftpds 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, $pam_conv_func, [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, $pam_conv_func, [AC_DEFINE(USE_PAM,,Use PAM for authentication) LIBPAM="-lpam -ldl"], [AC_DEFINE(USE_PAM,,Use PAM for authentication) 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_FUNC_CHOWN AC_FUNC_FNMATCH AC_FUNC_FORK AC_FUNC_MEMCMP AC_FUNC_MKTIME AC_FUNC_STRFTIME AC_FUNC_STAT AC_FUNC_SELECT_ARGTYPES AC_FUNC_STRFTIME dnl Avoid AC_FUNC_STRNLEN because it pulls in AC_SYSTEM_EXTENSIONS which dnl can lead to strange side effects. So we just check for strnlen dnl directly, see below. dnl AC_FUNC_STRNLENdnl AC_FUNC_VPRINTF dnl ------------------------------- dnl bgpd needs pow() and hence libm dnl ------------------------------- TMPLIBS="$LIBS" AC_CHECK_HEADER([math.h], [AC_CHECK_LIB([m], [pow], [LIBM="-lm" LIBS="$LIBS $LIBM" AC_DEFINE(HAVE_LIBM,, Have libm) AC_CHECK_FUNCS(pow,[],[LIBM=""]) ]) ]) if test x"$LIBM" = x ; then AC_MSG_WARN([Unable to find working pow function - bgpd may not link]) fi LIBS="$TMPLIBS" AC_SUBST(LIBM) dnl --------------- dnl other functions dnl --------------- AC_CHECK_FUNCS([dup2 ftruncate getcwd gethostbyname getpagesize gettimeofday \ inet_ntoa inet_aton strnlen \ memchr memmove memset select socket \ strcasecmp strchr strcspn strdup strerror \ strncasecmp strndup strrchr strspn strstr \ strtol strtoul strlcat strlcpy \ daemon snprintf vsnprintf \ if_nametoindex if_indextoname getifaddrs \ uname fcntl getgrouplist]) AC_CHECK_HEADER([asm-generic/unistd.h], [AC_CHECK_DECL(__NR_setns, AC_DEFINE(HAVE_NETNS,, Have netns),, QUAGGA_INCLUDES [#include ]) AC_CHECK_FUNCS(setns, AC_DEFINE(HAVE_SETNS,, Have setns))] ) 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 AC_MSG_RESULT(netlink) RT_METHOD=rt_netlink.o AC_DEFINE(HAVE_NETLINK,,netlink) netlink=yes else AC_MSG_RESULT(Route socket) KERNEL_METHOD="kernel_socket.o" RT_METHOD="rt_socket.o" fi AC_SUBST(RT_METHOD) AC_SUBST(KERNEL_METHOD) AM_CONDITIONAL([HAVE_NETLINK], [test "x$netlink" = "xyes"]) dnl -------------------------- dnl Determine IS-IS I/O method dnl -------------------------- AC_DEFINE(ISIS_METHOD_PFPACKET, 1, [ constant value for isis method pfpacket ]) AC_DEFINE(ISIS_METHOD_DLPI, 2, [ constant value for isis method dlpi ]) AC_DEFINE(ISIS_METHOD_BPF, 3, [ constant value for isis method bpf ]) AC_CHECK_HEADER(net/bpf.h) AC_CHECK_HEADER(sys/dlpi.h) AC_MSG_CHECKING(zebra IS-IS I/O method) if test x"$opsys" = x"gnu-linux"; then AC_MSG_RESULT(pfpacket) ISIS_METHOD_MACRO="ISIS_METHOD_PFPACKET" elif test x"$opsys" = x"sol2-6" -o x"$opsys" = x"sol8"; then AC_MSG_RESULT(DLPI) ISIS_METHOD_MACRO="ISIS_METHOD_DLPI" else if test $ac_cv_header_net_bpf_h = no; then if test $ac_cv_header_sys_dlpi_h = no; then AC_MSG_RESULT(none) AC_MSG_WARN([*** IS-IS support will not be built ***]) ISISD="" else AC_MSG_RESULT(DLPI) fi ISIS_METHOD_MACRO="ISIS_METHOD_DLPI" else AC_MSG_RESULT(BPF) ISIS_METHOD_MACRO="ISIS_METHOD_BPF" fi fi AC_DEFINE_UNQUOTED(ISIS_METHOD, $ISIS_METHOD_MACRO, [ selected method for isis, == one of the constants ]) dnl ------------------------------------ dnl check for broken CMSG_FIRSTHDR macro dnl ------------------------------------ AC_MSG_CHECKING(for broken CMSG_FIRSTHDR) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif main() { struct msghdr msg; char buf[4]; msg.msg_control = buf; msg.msg_controllen = 0; if (CMSG_FIRSTHDR(&msg) != NULL) exit(0); exit (1); }]])],[AC_MSG_RESULT(yes - using workaround) AC_DEFINE(HAVE_BROKEN_CMSG_FIRSTHDR,,Broken CMSG_FIRSTHDR)], [AC_MSG_RESULT(no)],[AC_MSG_RESULT(no)]) dnl ------------------------------ dnl check kernel route read method dnl ------------------------------ AC_CACHE_CHECK([route read method], [quagga_cv_rtread_method], [if test "x$netlink" = xyes; then quagga_cv_rtread_method="netlink" else for quagga_cv_rtread_method in /dev/ip /dev/null; do test x`ls $quagga_cv_rtread_method 2>/dev/null` = x"$quagga_cv_rtread_method" && break done case $quagga_cv_rtread_method in "/dev/ip") case "$host" in *-freebsd*) quagga_cv_rtread_method="sysctl";; *) quagga_cv_rtread_method="getmsg";; esac;; *) quagga_cv_rtread_method="sysctl";; esac fi]) RTREAD_METHOD=rtread_${quagga_cv_rtread_method}.o AC_SUBST(RTREAD_METHOD) dnl ----------------------------- dnl check interface lookup method dnl ----------------------------- IOCTL_METHOD=ioctl.o AC_MSG_CHECKING(interface looking up method) if test "$netlink" = yes; then AC_MSG_RESULT(netlink) IF_METHOD=if_netlink.o elif test "$opsys" = "sol2-6";then AC_MSG_RESULT(Solaris GIF) IF_METHOD=if_ioctl.o elif test "$opsys" = "sol8";then AC_MSG_RESULT(Solaris GLIF) IF_METHOD=if_ioctl_solaris.o IOCTL_METHOD=ioctl_solaris.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 AC_SUBST(IF_METHOD) AC_SUBST(IOCTL_METHOD) dnl --------------------------------------------------------------- dnl figure out how to specify an interface in multicast sockets API dnl --------------------------------------------------------------- AC_CHECK_MEMBERS([struct ip_mreqn.imr_ifindex], [], [], QUAGGA_INCLUDES) AC_CHECK_HEADERS([linux/mroute.h], [], [], [ #if HAVE_NETINET_IN_H #include #endif]) AC_MSG_CHECKING([for BSD struct ip_mreq hack]) AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H #include #endif],[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__DragonFly__) || defined(__sun) return (0); #else #error No support for BSD struct ip_mreq hack detected #endif],[AC_MSG_RESULT(yes) AC_DEFINE(HAVE_BSD_STRUCT_IP_MREQ_HACK,,[Can pass ifindex in struct ip_mreq])], AC_MSG_RESULT(no)) AC_MSG_CHECKING([for RFC3678 protocol-independed API]) AC_TRY_COMPILE([ #include #include ], [struct group_req gr; int sock; setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr)); ], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_RFC3678,1,[Have RFC3678 protocol-independed API])], AC_MSG_RESULT(no)) dnl --------------------------------------------------------------- dnl figure out how to check link-state dnl --------------------------------------------------------------- AC_CHECK_HEADER([net/if.h], [AC_CHECK_HEADER( [net/if_media.h], [m4_define([LINK_DETECT_INCLUDES], QUAGGA_INCLUDES [#include ]) AC_CHECK_MEMBERS( [struct ifmediareq.ifm_status], AC_DEFINE(HAVE_BSD_LINK_DETECT,,[BSD link-detect]), [], LINK_DETECT_INCLUDES)], [], QUAGGA_INCLUDES)], [], QUAGGA_INCLUDES ) dnl --------------------------------------------------------------- dnl Additional, newer way to check link-state using ifi_link_state. dnl Not available in all BSD's when ifmediareq available dnl --------------------------------------------------------------- AC_CHECK_HEADER([net/if.h], AC_CHECK_MEMBERS([struct if_data.ifi_link_state], AC_DEFINE(HAVE_BSD_IFI_LINK_STATE,,[BSD ifi_link_state available]), [], QUAGGA_INCLUDES), ,) dnl ------------------------ dnl TCP_MD5SIG socket option dnl ------------------------ AC_CHECK_HEADER([netinet/tcp.h], [m4_define([MD5_INCLUDES], QUAGGA_INCLUDES [#include ]) AC_CHECK_DECLS([TCP_MD5SIG], [], [], MD5_INCLUDES)], [], QUAGGA_INCLUDES) if test $ac_cv_have_decl_TCP_MD5SIG = no; then AC_CHECK_HEADER([linux/tcp.h], [m4_define([MD5_INCLUDES], QUAGGA_INCLUDES [#include ]) AC_CHECK_DECLS([TCP_MD5SIG], [], [], MD5_INCLUDES)]) fi dnl ----------------------------- dnl check ipforward detect method dnl ----------------------------- AC_CACHE_CHECK([ipforward method], [quagga_cv_ipforward_method], [if test x$cross_compiling = xyes; then if test x"$opsys" = x"gnu-linux"; then quagga_cv_ipforward_method=/proc/net/snmp else quagga_cv_ipforward_method=/dev/ip fi else for quagga_cv_ipforward_method in /proc/net/snmp /dev/ip /dev/null; do test x`ls $quagga_cv_ipforward_method 2>/dev/null` = x"$quagga_cv_ipforward_method" && break done fi case $quagga_cv_ipforward_method in "/proc/net/snmp") quagga_cv_ipforward_method="proc";; "/dev/ip") case "$host" in *-freebsd*) quagga_cv_ipforward_method="sysctl";; *) quagga_cv_ipforward_method="solaris";; esac;; *) quagga_cv_ipforward_method="sysctl";; esac]) IPFORWARD=ipforward_${quagga_cv_ipforward_method}.o 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) dnl --------- dnl KAME IPv6 dnl --------- if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then AC_DEFINE(KAME,1,KAME IPv6) AC_MSG_RESULT(KAME) dnl ------------------------------------ dnl Solaris 9, 10 and potentially higher dnl ------------------------------------ elif test x"$opsys" = x"sol8"; then AC_DEFINE(SOLARIS_IPV6, 1, Solaris IPv6) AC_MSG_RESULT(Solaris IPv6) dnl ---------- dnl Linux IPv6 dnl ---------- elif test x"$opsys" = x"gnu-linux"; then AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack) AC_MSG_RESULT(Linux IPv6) else AC_MSG_ERROR([Failed to detect IPv6 stack]) fi dnl this is unconditial, for compatibility AC_DEFINE(HAVE_IPV6,1,IPv6) dnl ------------------ dnl IPv6 header checks dnl ------------------ AC_CHECK_HEADERS([netinet6/in6.h netinet/in6_var.h netinet/icmp6.h \ netinet6/in6_var.h netinet6/nd6.h], [], [], QUAGGA_INCLUDES) m4_define([QUAGGA_INCLUDES],dnl QUAGGA_INCLUDES [#if HAVE_NETINET6_IN6_H #include #endif #if HAVE_NETINET_IN6_VAR_H #include #endif #if HAVE_NETINET_ICMP6_H # include #endif #if HAVE_NETINET6_IN6_VAR_H # include #endif #if HAVE_NETINET6_ND6_H # include #endif ])dnl dnl disable doc check if test "${enable_doc}" = "no";then DOC="" else DOC="doc" fi dnl -------------------- dnl Daemon disable check dnl -------------------- if test "${enable_zebra}" = "no";then ZEBRA="" else ZEBRA="zebra" fi AM_CONDITIONAL(ZEBRA, test "x$ZEBRA" = "xzebra") if test "${enable_bgpd}" = "no";then BGPD="" else BGPD="bgpd" fi AM_CONDITIONAL(BGPD, test "x$BGPD" = "xbgpd") if test "${enable_ripd}" = "no";then RIPD="" else RIPD="ripd" fi AM_CONDITIONAL(RIPD, test "x$RIPD" = "xripd") if test "${enable_ospfd}" = "no";then OSPFD="" else OSPFD="ospfd" fi AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd") if test x"$opsys" != x"gnu-linux"; then dnl NHRPd works currently with Linux only. enable_nhrpd="no" fi if test "${enable_nhrpd}" = "no";then NHRPD="" else NHRPD="nhrpd" fi AM_CONDITIONAL(NHRPD, test "x$NHRPD" = "xnhrpd") if test "${enable_watchquagga}" = "no";then WATCHQUAGGA="" else WATCHQUAGGA="watchquagga" fi AM_CONDITIONAL(WATCHQUAGGA, test "x$WATCHQUAGGA" = "xwatchquagga") OSPFCLIENT="" if test "${enable_ospfapi}" != "no";then AC_DEFINE(SUPPORT_OSPF_API,,OSPFAPI) if test "${enable_ospfclient}" != "no";then OSPFCLIENT="ospfclient" fi fi AM_CONDITIONAL(OSPFCLIENT, test "x$OSPFCLIENT" = "xospfclient") case "${enable_ripngd}" in "no" ) RIPNGD="";; * ) RIPNGD="ripngd";; esac AM_CONDITIONAL(RIPNGD, test "x$RIPNGD" = "xripngd") case "${enable_ospf6d}" in "no" ) OSPF6D="";; * ) OSPF6D="ospf6d";; esac AM_CONDITIONAL(OSPF6D, test "x$OSPF6D" = "xospf6d") case "${enable_isisd}" in "no" ) ISISD="";; * ) ISISD="isisd";; esac AM_CONDITIONAL(ISISD, test "x$ISISD" = "xisisd") case "${enable_pimd}" in "no" ) PIMD="";; * ) PIMD="pimd";; esac AM_CONDITIONAL(PIMD, test "x$PIMD" = "xpimd") if test "${enable_bgp_announce}" = "no";then AC_DEFINE(DISABLE_BGP_ANNOUNCE,1,Disable BGP installation to zebra) else AC_DEFINE(DISABLE_BGP_ANNOUNCE,0,Disable BGP installation to zebra) fi AC_SUBST(DOC) AC_SUBST(ZEBRA) AC_SUBST(BGPD) AC_SUBST(RIPD) AC_SUBST(RIPNGD) AC_SUBST(OSPFD) AC_SUBST(OSPF6D) AC_SUBST(NHRPD) AC_SUBST(WATCHQUAGGA) AC_SUBST(ISISD) AC_SUBST(PIMD) AC_SUBST(SOLARIS) AC_SUBST(VTYSH) AC_SUBST(CURSES) AC_SUBST(OSPFCLIENT) AC_SUBST(OSPFAPI) 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) dnl --------------------------- dnl check system has PCRE regexp dnl --------------------------- if test "x$enable_pcreposix" = "xyes"; then AC_CHECK_LIB(pcreposix, pcreposix_regexec, ,[enable_pcreposix=no AC_MSG_WARN([*** falling back to other regex library ***]) ]) fi if test "x$enable_pcreposix" != "xyes"; then dnl --------------------------- dnl check system has GNU regexp 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"]) fi AC_SUBST(HAVE_LIBPCREPOSIX) AC_SUBST(LIB_REGEX) dnl ------------------ dnl check C-Ares library dnl ------------------ if test "${enable_nhrpd}" != "no";then PKG_CHECK_MODULES([CARES], [libcares]) fi dnl ------------------ dnl check Net-SNMP library dnl ------------------ if test "${enable_snmp}" != ""; then AC_PATH_TOOL([NETSNMP_CONFIG], [net-snmp-config], [no]) if test x"$NETSNMP_CONFIG" = x"no"; then AC_MSG_ERROR([--enable-snmp given but unable to find net-snmp-config]) fi LIBS="$LIBS `${NETSNMP_CONFIG} --agent-libs`" CFLAGS="`${NETSNMP_CONFIG} --base-cflags` $CFLAGS" AC_MSG_CHECKING([whether we can link to Net-SNMP]) AC_LINK_IFELSE([AC_LANG_PROGRAM([ int main(void); ], [ { return 0; } ])],[AC_MSG_RESULT(yes)],[ AC_MSG_RESULT(no) AC_MSG_ERROR([--enable-snmp given but not usable])]) AC_DEFINE(HAVE_SNMP,,SNMP) case "${enable_snmp}" in yes) SNMP_METHOD=agentx ;; smux|agentx) SNMP_METHOD="${enable_snmp}" ;; *) AC_MSG_ERROR([--enable-snmp given with an unknown method (${enable_snmp}). Use smux or agentx]) ;; esac AH_TEMPLATE([SNMP_SMUX], [Use SNMP SMUX to interface with snmpd]) AH_TEMPLATE([SNMP_AGENTX], [Use SNMP AgentX to interface with snmpd]) AC_DEFINE_UNQUOTED(AS_TR_CPP(SNMP_${SNMP_METHOD}),,SNMP method to interface with snmpd) fi dnl --------------------------- dnl sockaddr and netinet checks dnl --------------------------- AC_CHECK_TYPES([struct sockaddr, struct sockaddr_in, struct sockaddr_in6, struct sockaddr_un, struct sockaddr_dl, socklen_t, struct vifctl, struct mfcctl, struct sioc_sg_req, vifi_t, struct sioc_vif_req, struct igmpmsg, struct ifaliasreq, struct if6_aliasreq, struct in6_aliasreq, struct nd_opt_adv_interval, struct rt_addrinfo, struct nd_opt_homeagent_info, struct nd_opt_adv_interval], [], [], QUAGGA_INCLUDES) AC_CHECK_MEMBERS([struct sockaddr.sa_len, struct sockaddr_in.sin_len, struct sockaddr_un.sun_len, struct sockaddr_in6.sin6_scope_id, struct sockaddr_dl.sdl_len, struct if6_aliasreq.ifra_lifetime, struct nd_opt_adv_interval.nd_opt_ai_type], [], [], QUAGGA_INCLUDES) dnl --------------------------- dnl IRDP/pktinfo/icmphdr checks dnl --------------------------- AC_CHECK_TYPES([struct in_pktinfo], [AC_CHECK_TYPES([struct icmphdr], [if test "${enable_irdp}" != "no"; then AC_DEFINE(HAVE_IRDP,, IRDP) fi], [if test "${enable_irdp}" = "yes"; then AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!']) fi], [QUAGGA_INCLUDES])], [if test "${enable_irdp}" = "yes"; then AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!']) fi], [QUAGGA_INCLUDES]) dnl ----------------------- dnl checking for IP_PKTINFO dnl ----------------------- AC_MSG_CHECKING(for IP_PKTINFO) AC_TRY_COMPILE([#include ], [ int opt = IP_PKTINFO; ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_IP_PKTINFO, 1, [Have IP_PKTINFO]) ], [ AC_MSG_RESULT(no) ]) dnl --------------------------- dnl checking for IP_RECVDSTADDR dnl --------------------------- AC_MSG_CHECKING(for IP_RECVDSTADDR) AC_TRY_COMPILE([#include ], [ int opt = IP_RECVDSTADDR; ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_IP_RECVDSTADDR, 1, [Have IP_RECVDSTADDR]) ], [ AC_MSG_RESULT(no) ]) dnl ---------------------- dnl checking for IP_RECVIF dnl ---------------------- AC_MSG_CHECKING(for IP_RECVIF) AC_TRY_COMPILE([#include ], [ int opt = IP_RECVIF; ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_IP_RECVIF, 1, [Have IP_RECVIF]) ], [ AC_MSG_RESULT(no) ]) dnl -------------------------------------- dnl checking for getrusage struct and call dnl -------------------------------------- if test "${enable_rusage}" != "no"; then 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)) fi dnl -------------------------------------- dnl checking for clock_time monotonic struct and call dnl -------------------------------------- AC_CHECK_DECL(CLOCK_MONOTONIC, [AC_CHECK_LIB(rt, clock_gettime, [LIBS="$LIBS -lrt"]) AC_DEFINE(HAVE_CLOCK_MONOTONIC,, Have monotonic clock) ], [AC_MSG_RESULT(no)], [QUAGGA_INCLUDES]) dnl ------------------- dnl capabilities checks dnl ------------------- if test "${enable_capabilities}" != "no"; then AC_MSG_CHECKING(whether prctl PR_SET_KEEPCAPS is available) AC_TRY_COMPILE([#include ],[prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_PR_SET_KEEPCAPS,,prctl) quagga_ac_keepcaps="yes"], AC_MSG_RESULT(no) ) if test x"${quagga_ac_keepcaps}" = x"yes"; then AC_CHECK_HEADERS(sys/capability.h) fi if test x"${ac_cv_header_sys_capability_h}" = x"yes"; then AC_CHECK_LIB(cap, cap_init, [AC_DEFINE(HAVE_LCAPS,1,Capabilities) LIBCAP="-lcap" quagga_ac_lcaps="yes"] ) else AC_CHECK_HEADERS(priv.h, [AC_MSG_CHECKING(Solaris style privileges are available) AC_TRY_COMPILE([#include ],[getpflags(PRIV_AWARE);], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SOLARIS_CAPABILITIES,1,getpflags) quagga_ac_scaps="yes"], AC_MSG_RESULT(no) ) ] ) fi if test x"${quagga_ac_scaps}" = x"yes" \ -o x"${quagga_ac_lcaps}" = x"yes"; then AC_DEFINE(HAVE_CAPABILITIES,1,capabilities) fi fi AC_SUBST(LIBCAP) dnl --------------------------------------------------------------------------- dnl http://www.gnu.org/software/autoconf-archive/ax_sys_weak_alias.html dnl Check for and set one of the following = 1 dnl HAVE_SYS_WEAK_ALIAS_ATTRIBUTE dnl HAVE_SYS_WEAK_ALIAS_PRAGMA dnl HAVE_SYS_WEAK_ALIAS_HPSECONDARY dnl HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE dnl If any scheme is found, set dnl HAVE_SYS_WEAK_ALIAS=1 dnl The following variable is set to text value dnl WEAK_ALIAS = "attribute" || "pragma" || "hpsecondary" || "criduplicate" || "no" dnl If weak alias can cross object file boundaries dnl WEAK_ALIAS_CROSSFILE = "yes" || "no" dnl --------------------------------------------------------------------------- AX_SYS_WEAK_ALIAS dnl --------------------------- dnl check for glibc 'backtrace' dnl --------------------------- if test x"${enable_backtrace}" != x"no" ; then backtrace_ok=no AC_CHECK_HEADER([execinfo.h], [ AC_SEARCH_LIBS([backtrace], [execinfo], [ AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace]) AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding]) backtrace_ok=yes ],, [-lm]) ]) if test x"${enable_backtrace}" = x"yes" -a x"${backtrace_ok}" = x"no"; then dnl user explicitly requested backtrace but we failed to find support AC_MSG_FAILURE([failed to find backtrace support]) fi fi dnl ----------------------------------------- dnl check for malloc mallinfo struct and call dnl this must try and link using LIBS, in dnl order to check no alternative allocator dnl has been specified, which might not provide dnl mallinfo, e.g. such as Umem on Solaris. dnl ----------------------------------------- AC_CHECK_HEADER([malloc.h], [AC_MSG_CHECKING(whether mallinfo is available) AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct mallinfo ac_x; ac_x = mallinfo ();]])], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_MALLINFO,,mallinfo)], AC_MSG_RESULT(no) ) ], [], QUAGGA_INCLUDES) dnl ---------- dnl configure date dnl ---------- CONFDATE=`date '+%Y%m%d'` AC_SUBST(CONFDATE) dnl ------------------------------ dnl set paths for state directory dnl ------------------------------ AC_MSG_CHECKING(directory to use for state file) if test "${prefix}" = "NONE"; then quagga_statedir_prefix=""; else quagga_statedir_prefix=${prefix} fi if test "${localstatedir}" = '${prefix}/var'; then for QUAGGA_STATE_DIR in ${quagga_statedir_prefix}/var/run dnl ${quagga_statedir_prefix}/var/adm dnl ${quagga_statedir_prefix}/etc dnl /var/run dnl /var/adm dnl /etc dnl /dev/null; do test -d $QUAGGA_STATE_DIR && break done quagga_statedir=$QUAGGA_STATE_DIR else quagga_statedir=${localstatedir} fi if test $quagga_statedir = "/dev/null"; then AC_MSG_ERROR('STATE DIRECTORY NOT FOUND! FIX OR SPECIFY --localstatedir!') fi AC_MSG_RESULT(${quagga_statedir}) AC_SUBST(quagga_statedir) AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$quagga_statedir/zebra.pid",zebra PID) AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$quagga_statedir/ripd.pid",ripd PID) AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$quagga_statedir/ripngd.pid",ripngd PID) AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID) AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID) AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID) AC_DEFINE_UNQUOTED(PATH_NHRPD_PID, "$quagga_statedir/nhrpd.pid",nhrpd PID) AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID) AC_DEFINE_UNQUOTED(PATH_PIMD_PID, "$quagga_statedir/pimd.pid",pimd PID) AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID) AC_DEFINE_UNQUOTED(ZEBRA_SERV_PATH, "$quagga_statedir/zserv.api",zebra api socket) AC_DEFINE_UNQUOTED(ZEBRA_VTYSH_PATH, "$quagga_statedir/zebra.vty",zebra vty socket) AC_DEFINE_UNQUOTED(RIP_VTYSH_PATH, "$quagga_statedir/ripd.vty",rip vty socket) AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$quagga_statedir/ripngd.vty",ripng vty socket) AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket) AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket) AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket) AC_DEFINE_UNQUOTED(NHRP_VTYSH_PATH, "$quagga_statedir/nhrpd.vty",nhrpd vty socket) AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket) AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket) AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory) dnl ------------------------------- dnl Quagga sources should always be dnl current wrt interfaces. Dont dnl allow deprecated interfaces to dnl be exposed. dnl ------------------------------- AC_DEFINE(QUAGGA_NO_DEPRECATED_INTERFACES, 1, Hide deprecated interfaces) dnl --------------------------- dnl Check htonl works correctly dnl --------------------------- AC_MSG_CHECKING(for working htonl) AC_CACHE_VAL(ac_cv_htonl_works, [AC_LINK_IFELSE([AC_LANG_PROGRAM([QUAGGA_INCLUDES],[htonl (0);])], [ac_cv_htonl_works=yes], [ac_cv_htonl_works=no]) ] ) AC_MSG_RESULT($ac_cv_htonl_works) AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile pimd/Makefile nhrpd/Makefile redhat/Makefile pkgsrc/Makefile fpm/Makefile redhat/quagga.spec redhat/quagga.sysconfig lib/version.h isisd/topology/Makefile pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh]) AC_CONFIG_FILES([solaris/Makefile]) AC_CONFIG_FILES([vtysh/extract.pl],[chmod +x vtysh/extract.pl]) ## Hack, but working solution to avoid rebuilding of quagga.info. ## It's already in CVS until texinfo 4.7 is more common. AC_OUTPUT echo " Quagga configuration -------------------- quagga version : ${PACKAGE_VERSION} host operating system : ${host_os} source code location : ${srcdir} compiler : ${CC} compiler flags : ${CFLAGS} make : ${MAKE-make} linker flags : ${LDFLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} state file directory : ${quagga_statedir} config file directory : `eval echo \`echo ${sysconfdir}\`` example directory : `eval echo \`echo ${exampledir}\`` user to run as : ${enable_user} group to run as : ${enable_group} group for vty sockets : ${enable_vty_group} config file mask : ${enable_configfile_mask} log file mask : ${enable_logfile_mask} zebra protobuf enabled : ${have_protobuf:-no} The above user and group must have read/write access to the state file directory and to the config files in the config file directory." if test x"$quagga_cv_gnu_make" = x"no"; then echo " Warning: The ${MAKE-make} programme detected, either in your path or via the MAKE variable, is not GNU Make. GNU make may be installed as gmake on some systems. and is required to complete a build of Quagga " > /dev/stderr fi quagga-1.2.4/depcomp000077500000000000000000000560161325323223500143500ustar00rootroot00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2014 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, see . # 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 . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} 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 # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # 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 cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc 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. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## 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). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - 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 -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # 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. ## 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. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -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 -ne 0; then 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 ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # 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 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, 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. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; 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. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # 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 ;; #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 preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--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 test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | 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 $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | 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 preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--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 -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [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 preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # 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 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: quagga-1.2.4/doc/000077500000000000000000000000001325323223500135305ustar00rootroot00000000000000quagga-1.2.4/doc/BGP-TypeCode000066400000000000000000000017521325323223500156020ustar00rootroot00000000000000 BGP-4[+] UPDATE Attribute TypeCode list Value Attribute References ========================================================================= 1 ORIGIN [RFC 4271] 2 AS_PATH [RFC 4271] 3 NEXT_HOP [RFC 4271] 4 MULTI_EXIT_DISC [RFC 4271] 5 LOCAL_PREF [RFC 4271] 6 ATOMIC_AGGREGATE [RFC 4271] 7 AGGREGATOR [RFC 4271] 8 COMMUNITIES [RFC 1997] 9 ORIGINATOR_ID [RFC 4456] 10 CLUSTER_LIST [RFC 4456] 11 DPA [draft-ietf-idr-bgp-dpa-05.txt(expired)] 12 ADVERTISER [RFC 1863] 13 RCID_PATH [RFC 1863] 14 MP_REACH_NLRI [RFC 4760] 15 MP_UNREACH_NLRI [RFC 4760] 16 EXT_COMMUNITIES [RFC 4360] 17 AS4_PATH [RFC 4893] 18 AS4_AGGREGATOR [RFC 4893] ========================================================================= quagga-1.2.4/doc/Makefile.am000066400000000000000000000060251325323223500155670ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. # Dia, the version i have at least, doesn't do very good EPS output # (some of the text is scaled strangely). So this will work, but # it is probably better to use something like gimp to convert the # dia exported PNG files to EPS manually. # # Here we use 'convert' from the well known 'ImageMagick' package # to do conversion from png to eps/pdf for figures. # PDF form is required for quagga.pdf, using PDFTex at least. # # TeX implementation, which we depend on already anyway. # # dia -> (dia) -> png -> (convert) -> eps -> (epstopdf) -> pdf SUFFIXES = .png .eps .dia .pdf DIATOPNG = dia -t png -e DIATOEPS = dia -t eps -e PNGTOEPS = convert -antialias -contrast -despeckle PNGTOPDF = $(PNGTOEPS) EPSTOPDF = epstopdf # The figure sources figures_names_parts = -normal-processing -rs-processing figures_sources = $(figures_names_parts:%=fig%.dia) figures_png = $(figures_names_parts:%=fig%.png) figures_pdf = $(figures_names_parts:%=fig%.pdf) figures_eps = $(figures_names_parts:%=fig%.eps) figures_txt = $(figures_names_parts:%=fig%.txt) # rather twisted logic because we have to build PDFs of the EPS figures for # PDFTex and yet build one PDF, quagga.pdf, from texi source. Which means we # cant rely on a single automatic rule for *.pdf, eg the one automatically # provided by automake. If you are an automake wizard, please feel free to # compact it somehow. #quagga.pdf: $(info_TEXINFOS) $(quagga_TEXINFOS) # $(TEXI2PDF) -o "$@" $< || true info_TEXINFOS = quagga.texi quagga_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 routeserver.texi defines.texi $(figures_png) \ snmptrap.texi ospf_fundamentals.texi isisd.texi nhrpd.texi \ $(figures_txt) .png.eps: $(PNGTOEPS) $< "$@" .png.pdf: $(PNGTOPDF) $< "$@" .dia.png: $(DIATOPNG) "$@" $< man_MANS = if PIMD man_MANS += pimd.8 endif if BGPD man_MANS += bgpd.8 endif if ISISD man_MANS += isisd.8 endif if OSPF6D man_MANS += ospf6d.8 endif if OSPFCLIENT man_MANS += ospfclient.8 endif if OSPFD man_MANS += ospfd.8 endif if RIPD man_MANS += ripd.8 endif if RIPNGD man_MANS += ripngd.8 endif if NHRPD man_MANS += nhrpd.8 endif if VTYSH man_MANS += vtysh.1 endif if WATCHQUAGGA man_MANS += watchquagga.8 endif if ZEBRA man_MANS += zebra.8 endif AM_MAKEINFOHTMLFLAGS = --css-include=$(srcdir)/texinfo.css EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ ripngd.8 nhrpd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) \ texinfo.tex texinfo.css draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ CLEANFILES = *.{fn,fns,cp,cps,ky,kys} DISTCLEANFILES = quagga.info* # do nothing for DVI, so we don't have to generate or distribute EPS # figures dvi: # nothing quagga-1.2.4/doc/Makefile.in000066400000000000000000001006411325323223500155770ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @PIMD_TRUE@am__append_1 = pimd.8 @BGPD_TRUE@am__append_2 = bgpd.8 @ISISD_TRUE@am__append_3 = isisd.8 @OSPF6D_TRUE@am__append_4 = ospf6d.8 @OSPFCLIENT_TRUE@am__append_5 = ospfclient.8 @OSPFD_TRUE@am__append_6 = ospfd.8 @RIPD_TRUE@am__append_7 = ripd.8 @RIPNGD_TRUE@am__append_8 = ripngd.8 @NHRPD_TRUE@am__append_9 = nhrpd.8 @VTYSH_TRUE@am__append_10 = vtysh.1 @WATCHQUAGGA_TRUE@am__append_11 = watchquagga.8 @ZEBRA_TRUE@am__append_12 = zebra.8 subdir = doc ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/version.texi \ $(srcdir)/stamp-vti $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = AM_V_DVIPS = $(am__v_DVIPS_@AM_V@) am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@) am__v_DVIPS_0 = @echo " DVIPS " $@; am__v_DVIPS_1 = AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@) am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@) am__v_MAKEINFO_0 = @echo " MAKEINFO" $@; am__v_MAKEINFO_1 = AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@) am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@) am__v_INFOHTML_0 = @echo " INFOHTML" $@; am__v_INFOHTML_1 = AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@) am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@) am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@; am__v_TEXI2DVI_1 = AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@) am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@) am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@; am__v_TEXI2PDF_1 = AM_V_texinfo = $(am__v_texinfo_@AM_V@) am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@) am__v_texinfo_0 = -q am__v_texinfo_1 = AM_V_texidevnull = $(am__v_texidevnull_@AM_V@) am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@) am__v_texidevnull_0 = > /dev/null am__v_texidevnull_1 = INFO_DEPS = quagga.info am__TEXINFO_TEX_DIR = $(srcdir) DVIS = quagga.dvi PDFS = quagga.pdf PSS = quagga.ps HTMLS = quagga.html TEXINFOS = quagga.texi TEXI2DVI = texi2dvi TEXI2PDF = $(TEXI2DVI) --pdf --batch MAKEINFOHTML = $(MAKEINFO) --html DVIPS = dvips am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(man8dir)" am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(quagga_TEXINFOS) $(srcdir)/Makefile.in mdate-sh \ texinfo.tex DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # Dia, the version i have at least, doesn't do very good EPS output # (some of the text is scaled strangely). So this will work, but # it is probably better to use something like gimp to convert the # dia exported PNG files to EPS manually. # # Here we use 'convert' from the well known 'ImageMagick' package # to do conversion from png to eps/pdf for figures. # PDF form is required for quagga.pdf, using PDFTex at least. # # TeX implementation, which we depend on already anyway. # # dia -> (dia) -> png -> (convert) -> eps -> (epstopdf) -> pdf SUFFIXES = .png .eps .dia .pdf DIATOPNG = dia -t png -e DIATOEPS = dia -t eps -e PNGTOEPS = convert -antialias -contrast -despeckle PNGTOPDF = $(PNGTOEPS) EPSTOPDF = epstopdf # The figure sources figures_names_parts = -normal-processing -rs-processing figures_sources = $(figures_names_parts:%=fig%.dia) figures_png = $(figures_names_parts:%=fig%.png) figures_pdf = $(figures_names_parts:%=fig%.pdf) figures_eps = $(figures_names_parts:%=fig%.eps) figures_txt = $(figures_names_parts:%=fig%.txt) # rather twisted logic because we have to build PDFs of the EPS figures for # PDFTex and yet build one PDF, quagga.pdf, from texi source. Which means we # cant rely on a single automatic rule for *.pdf, eg the one automatically # provided by automake. If you are an automake wizard, please feel free to # compact it somehow. #quagga.pdf: $(info_TEXINFOS) $(quagga_TEXINFOS) # $(TEXI2PDF) -o "$@" $< || true info_TEXINFOS = quagga.texi quagga_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 routeserver.texi defines.texi $(figures_png) \ snmptrap.texi ospf_fundamentals.texi isisd.texi nhrpd.texi \ $(figures_txt) man_MANS = $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_10) $(am__append_11) $(am__append_12) AM_MAKEINFOHTMLFLAGS = --css-include=$(srcdir)/texinfo.css EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ ripngd.8 nhrpd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) \ texinfo.tex texinfo.css CLEANFILES = *.{fn,fns,cp,cps,ky,kys} DISTCLEANFILES = quagga.info* all: all-am .SUFFIXES: .SUFFIXES: .png .eps .dia .pdf .dvi .ps $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs quagga.info: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ rm -rf $$backupdir && mkdir $$backupdir && \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ `test -f 'quagga.texi' || echo '$(srcdir)/'`quagga.texi; \ then \ rc=0; \ else \ rc=$$?; \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc quagga.dvi: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ `test -f 'quagga.texi' || echo '$(srcdir)/'`quagga.texi quagga.pdf: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ `test -f 'quagga.texi' || echo '$(srcdir)/'`quagga.texi quagga.html: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) `test -f 'quagga.texi' || echo '$(srcdir)/'`quagga.texi; \ then \ rm -rf $@ && mv $(@:.html=.htp) $@; \ else \ rm -rf $(@:.html=.htp); exit 1; \ fi $(srcdir)/version.texi: $(srcdir)/stamp-vti $(srcdir)/stamp-vti: quagga.texi $(top_srcdir)/configure @(dir=.; test -f ./quagga.texi || dir=$(srcdir); \ set `$(SHELL) $(srcdir)/mdate-sh $$dir/quagga.texi`; \ echo "@set UPDATED $$1 $$2 $$3"; \ echo "@set UPDATED-MONTH $$2 $$3"; \ echo "@set EDITION $(VERSION)"; \ echo "@set VERSION $(VERSION)") > vti.tmp$$$$ && \ (cmp -s vti.tmp$$$$ $(srcdir)/version.texi \ || (echo "Updating $(srcdir)/version.texi" && \ cp vti.tmp$$$$ $(srcdir)/version.texi.tmp$$$$ && \ mv $(srcdir)/version.texi.tmp$$$$ $(srcdir)/version.texi)) && \ rm -f vti.tmp$$$$ $(srcdir)/version.texi.$$$$ @cp $(srcdir)/version.texi $@ mostlyclean-vti: -rm -f vti.tmp* $(srcdir)/version.texi.tmp* maintainer-clean-vti: -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi .dvi.ps: $(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(DVIPS) $(AM_V_texinfo) -o $@ $< uninstall-dvi-am: @$(NORMAL_UNINSTALL) @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \ rm -f "$(DESTDIR)$(dvidir)/$$f"; \ done uninstall-html-am: @$(NORMAL_UNINSTALL) @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \ rm -rf "$(DESTDIR)$(htmldir)/$$f"; \ done uninstall-info-am: @$(PRE_UNINSTALL) @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \ list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \ if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \ then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \ done; \ else :; fi @$(NORMAL_UNINSTALL) @list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \ echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ else :; fi); \ done uninstall-pdf-am: @$(NORMAL_UNINSTALL) @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \ rm -f "$(DESTDIR)$(pdfdir)/$$f"; \ done uninstall-ps-am: @$(NORMAL_UNINSTALL) @list='$(PSS)'; test -n "$(psdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \ rm -f "$(DESTDIR)$(psdir)/$$f"; \ done dist-info: $(INFO_DEPS) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; \ for base in $$list; do \ case $$base in \ $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$base; then d=.; else d=$(srcdir); fi; \ base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \ for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \ if test -f $$file; then \ relfile=`expr "$$file" : "$$d/\(.*\)"`; \ test -f "$(distdir)/$$relfile" || \ cp -p $$file "$(distdir)/$$relfile"; \ else :; fi; \ done; \ done mostlyclean-aminfo: -rm -rf quagga.t2d quagga.t2p clean-aminfo: -test -z "quagga.dvi quagga.pdf quagga.ps quagga.html" \ || rm -rf quagga.dvi quagga.pdf quagga.ps quagga.html maintainer-clean-aminfo: @list='$(INFO_DEPS)'; for i in $$list; do \ i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \ echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ done install-man1: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-man8: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.8[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: for dir in "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) 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-aminfo clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi-am: $(DVIS) html: html-am html-am: $(HTMLS) info: info-am info-am: $(INFO_DEPS) install-data-am: install-info-am install-man install-dvi: install-dvi-am install-dvi-am: $(DVIS) @$(NORMAL_INSTALL) @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \ $(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \ done install-exec-am: install-html: install-html-am install-html-am: $(HTMLS) @$(NORMAL_INSTALL) @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ $(am__strip_dir) \ d2=$$d$$p; \ if test -d "$$d2"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \ $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \ else \ list2="$$list2 $$d2"; \ fi; \ done; \ test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done; } install-info: install-info-am install-info-am: $(INFO_DEPS) @$(NORMAL_INSTALL) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \ $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \ fi; \ for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$file; then d=.; else d=$(srcdir); fi; \ file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \ for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \ $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \ if test -f $$ifile; then \ echo "$$ifile"; \ else : ; fi; \ done; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done @$(POST_INSTALL) @if $(am__can_run_installinfo); then \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\ done; \ else : ; fi install-man: install-man1 install-man8 install-pdf: install-pdf-am install-pdf-am: $(PDFS) @$(NORMAL_INSTALL) @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done install-ps: install-ps-am install-ps-am: $(PSS) @$(NORMAL_INSTALL) @list='$(PSS)'; test -n "$(psdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-vti mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-aminfo mostlyclean-generic \ mostlyclean-libtool mostlyclean-vti pdf: pdf-am pdf-am: $(PDFS) ps: ps-am ps-am: $(PSS) uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ uninstall-man uninstall-pdf-am uninstall-ps-am uninstall-man: uninstall-man1 uninstall-man8 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-aminfo clean-generic \ clean-libtool cscopelist-am ctags-am dist-info distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man1 install-man8 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-vti mostlyclean \ mostlyclean-aminfo mostlyclean-generic mostlyclean-libtool \ mostlyclean-vti pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-dvi-am uninstall-html-am \ uninstall-info-am uninstall-man uninstall-man1 uninstall-man8 \ uninstall-pdf-am uninstall-ps-am .PRECIOUS: Makefile .png.eps: $(PNGTOEPS) $< "$@" .png.pdf: $(PNGTOPDF) $< "$@" .dia.png: $(DIATOPNG) "$@" $< draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ # do nothing for DVI, so we don't have to generate or distribute EPS # figures dvi: # nothing # 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: quagga-1.2.4/doc/appendix.texi000066400000000000000000000274131325323223500162420ustar00rootroot00000000000000@node Packet Binary Dump Format @appendix Packet Binary Dump Format Quagga 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_ET, the common header format will contain an additional microsecond field (RFC6396 2011). @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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Microsecond | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @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 #define MSG_PROTOCOL_BGP4MP_ET 17 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 #define BGP4MP_ENTRY 2 #define BGP4MP_SNAPSHOT 3 @end group @end example quagga-1.2.4/doc/basic.texi000066400000000000000000000406721325323223500155150ustar00rootroot00000000000000@node Basic commands @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 * Terminal Mode Commands:: Common commands used in a VTY * Common Invocation Options:: Starting the daemons * Virtual Terminal Interfaces:: Interacting with the daemons @end menu @node Config Commands @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 @w{} @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 @w{} @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 @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 trap @var{level}} {} @deffnx Command {no log trap} {} These commands are deprecated and are present only for historical compatibility. The log trap command sets the current logging level for all enabled logging destinations, and it sets the default for all future logging commands that do not specify a level. The normal default logging level is debugging. The @code{no} form of the command resets the default level for future logging commands to debugging, but it does not change the logging level of existing logging destinations. @end deffn @deffn Command {log stdout} {} @deffnx Command {log stdout @var{level}} {} @deffnx Command {no log stdout} {} Enable logging output to stdout. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated @code{log trap} command) will be used. The @code{no} form of the command disables logging to stdout. The @code{level} argument must have one of these values: emergencies, alerts, critical, errors, warnings, notifications, informational, or debugging. Note that the existing code logs its most important messages with severity @code{errors}. @end deffn @deffn Command {log file @var{filename}} {} @deffnx Command {log file @var{filename} @var{level}} {} @deffnx Command {no log file} {} If you want to log into a file, please specify @code{filename} as in this example: @example log file /var/log/quagga/bgpd.log informational @end example If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated @code{log trap} command) will be used. The @code{no} form of the command disables logging to a file. Note: if you do not configure any file logging, and a daemon crashes due to a signal or an assertion failure, it will attempt to save the crash information in a file named /var/tmp/quagga..crashlog. For security reasons, this will not happen if the file exists already, so it is important to delete the file after reporting the crash information. @end deffn @deffn Command {log syslog} {} @deffnx Command {log syslog @var{level}} {} @deffnx Command {no log syslog} {} Enable logging output to syslog. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated @code{log trap} command) will be used. The @code{no} form of the command disables logging to syslog. @end deffn @deffn Command {log monitor} {} @deffnx Command {log monitor @var{level}} {} @deffnx Command {no log monitor} {} Enable logging output to vty terminals that have enabled logging using the @code{terminal monitor} command. By default, monitor logging is enabled at the debugging level, but this command (or the deprecated @code{log trap} command) can be used to change the monitor logging level. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated @code{log trap} command) will be used. The @code{no} form of the command disables logging to terminal monitors. @end deffn @deffn Command {log facility @var{facility}} {} @deffnx Command {no log facility} {} This command changes the facility used in syslog messages. The default facility is @code{daemon}. The @code{no} form of the command resets the facility to the default @code{daemon} facility. @end deffn @deffn Command {log record-priority} {} @deffnx Command {no log record-priority} {} To include the severity in all messages logged to a file, to stdout, or to a terminal monitor (i.e. anything except syslog), use the @code{log record-priority} global configuration command. To disable this option, use the @code{no} form of the command. By default, the severity level is not included in logged messages. Note: some versions of syslogd (including Solaris) can be configured to include the facility and level in the messages emitted. @end deffn @deffn Command {log timestamp precision @var{<0-6>}} {} @deffnx Command {no log timestamp precision} {} This command sets the precision of log message timestamps to the given number of digits after the decimal point. Currently, the value must be in the range 0 to 6 (i.e. the maximum precision is microseconds). To restore the default behavior (1-second accuracy), use the @code{no} form of the command, or set the precision explicitly to 0. @example @group log timestamp precision 3 @end group @end example In this example, the precision is set to provide timestamps with millisecond accuracy. @end deffn @deffn Command {log commands} {} This command enables the logging of all commands typed by a user to all enabled log destinations. The note that logging includes full command lines, including passwords. Once set, command logging can only be turned off by restarting the daemon. @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 {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 @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 Terminal Mode Commands @section Terminal Mode Commands @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} {} Show a list of currently connected vty sessions. @end deffn @deffn Command {list} {} List all available commands. @end deffn @deffn Command {show version} {} Show the current version of @value{PACKAGE_NAME} and its build host information. @end deffn @deffn Command {show logging} {} Shows the current configuration of the logging system. This includes the status of all logging destinations. @end deffn @deffn Command {logmsg @var{level} @var{message}} {} Send a message to all logging destinations that are enabled for messages of the given severity. @end deffn @node Common Invocation Options @section Common Invocation Options @c COMMON_OPTIONS @c OPTIONS section of the man page These options apply to all @value{PACKAGE_NAME} 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 @value{PACKAGE_NAME} to implement a routing looking glass. One machine can be used to collect differing routing views from differing points in the network. @item -A @var{address} @itemx --vty_addr=@var{address} Set the VTY local address to bind to. If set, the VTY socket will only be bound to this address. @item -P @var{port} @itemx --vty_port=@var{port} Set the VTY TCP port number. If set to 0 then the TCP VTY sockets will not be opened. @item -u @var{user} @itemx --vty_addr=@var{user} Set the user and group to run as. @item -v @itemx --version Print program version. @end table @node Virtual Terminal Interfaces @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 @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 @value{PACKAGE_NAME} (version @value{VERSION}) @value{COPYRIGHT_STR} 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 @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 @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 @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 @subsubsection VTY Other Modes @c to be written (gpoul) This page is for describing other modes. @node VTY CLI Commands @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 @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 @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. @item C-v @kindex C-v Interpret following character literally. Do not treat it specially. This can be used to, e.g., type in a literal @kbd{?} rather than do help completion. @end table @node CLI Advanced Commands @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 @key{?} 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. To enter an actual @kbd{?} character rather show completions, e.g. to enter into a regexp, use @kbd{@key{C}-v ?}. @end table quagga-1.2.4/doc/bgpd.8000066400000000000000000000056431325323223500145450ustar00rootroot00000000000000.TH BGPD 8 "25 November 2004" "Quagga BGPD daemon" "Version 0.97.3" .SH NAME bgpd \- a BGPv4, BGPv4\+, BGPv4\- routing engine for use with Quagga routing software .SH SYNOPSIS .B bgpd [ .B \-dhrSv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-p .I bgp-port-number ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B bgpd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B bgpd command: .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\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\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 identifier 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\fIbgp-port-number\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\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the bgpd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBbgpd\fR. .TP \fB\-S\fR, \fB\-\-skip_runas\fR Skip setting the process effective user and group. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .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 to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\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" .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR nhrpd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B bgpd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-1.2.4/doc/bgpd.texi000066400000000000000000002176341325323223500153540ustar00rootroot00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @c Portions: @c Copyright @copyright{} 2015 Hewlett Packard Enterprise Development LP @c See file quagga.texi for copying conditions. @node BGP @chapter BGP @acronym{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 @cite{RFC1771, A Border Gateway Protocol 4 (BGP-4)}. Many extensions have been added to @cite{RFC1771}. @cite{RFC2858, Multiprotocol Extensions for BGP-4} provides multiprotocol support to BGP-4. @menu * Starting BGP:: * BGP router:: * BGP MED:: * 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:: * BGP Configuration Examples:: @end menu @node Starting BGP @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. @item -l @itemx --listenon Specify a specific IP address for bgpd to listen on, rather than its default of INADDR_ANY / IN6ADDR_ANY. This can be useful to constrain bgpd to an internal address, or to run multiple bgpd processes on one host. @end table @node BGP router @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:: * BGP route flap dampening:: @end menu @node BGP distance @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. To have this command applied to existing routes requires a hard clear. @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 @subsection BGP decision process The decision process Quagga BGP uses to select routes is as follows: @table @asis @item 1. Weight check prefer higher local weight routes to lower routes. @item 2. Local preference check prefer higher local preference routes to lower. @item 3. Local route check Prefer local routes (statics, aggregates, redistributed) to received routes. @item 4. AS path length check Prefer shortest hop-count AS_PATHs. @item 5. Origin check Prefer the lowest origin type route. That is, prefer IGP origin routes to EGP, to Incomplete routes. @item 6. MED check Where routes with a MED were received from the same AS, prefer the route with the lowest MED. @xref{BGP MED}. @item 7. External check Prefer the route received from an external, eBGP peer over routes received from other types of peers. @item 8. IGP cost check Prefer the route with the lower IGP cost. @item 9. Multi-path check If multi-pathing is enabled, then check whether the routes not yet distinguished in preference may be considered equal. If @ref{bgp bestpath as-path multipath-relax} is set, all such routes are considered equal, otherwise routes received via iBGP with identical AS_PATHs or routes received from eBGP neighbours in the same AS are considered equal. @item 10 Already-selected external check Where both routes were received from eBGP peers, then prefer the route which is already selected. Note that this check is not applied if @ref{bgp bestpath compare-routerid} is configured. This check can prevent some cases of oscillation. @item 11. Router-ID check Prefer the route with the lowest @w{router-ID}. If the route has an @w{ORIGINATOR_ID} attribute, through iBGP reflection, then that router ID is used, otherwise the @w{router-ID} of the peer the route was received from is used. @item 12. Cluster-List length check The route with the shortest cluster-list length is used. The cluster-list reflects the iBGP reflection path the route has taken. @item 13. Peer address Prefer the route received from the peer with the higher transport layer address, as a last-resort tie-breaker. @end table @deffn {BGP} {bgp bestpath as-path confed} {} This command specifies that the length of confederation path sets and sequences should should be taken into account during the BGP best path decision process. @end deffn @deffn {BGP} {bgp bestpath as-path multipath-relax} {} @anchor{bgp bestpath as-path multipath-relax} This command specifies that BGP decision process should consider paths of equal AS_PATH length candidates for multipath computation. Without the knob, the entire AS_PATH must match for multipath computation. @end deffn @deffn {BGP} {bgp bestpath compare-routerid} {} @anchor{bgp bestpath compare-routerid} Ensure that when comparing routes where both are equal on most metrics, including local-pref, AS_PATH length, IGP cost, MED, that the tie is broken based on router-ID. If this option is enabled, then the already-selected check, where already selected eBGP routes are preferred, is skipped. If a route has an @w{ORIGINATOR_ID} attribute because it has been reflected, that @w{ORIGINATOR_ID} will be used. Otherwise, the router-ID of the peer the route was received from will be used. The advantage of this is that the route-selection (at this point) will be more deterministic. The disadvantage is that a few or even one lowest-ID router may attract all trafic to otherwise-equal paths because of this check. It may increase the possibility of MED or IGP oscillation, unless other measures were taken to avoid these. The exact behaviour will be sensitive to the iBGP and reflection topology. @end deffn @node BGP route flap dampening @subsection BGP route flap dampening @deffn {BGP} {bgp dampening @var{<1-45>} @var{<1-20000>} @var{<1-20000>} @var{<1-255>}} {} This command enables BGP route-flap dampening and specifies dampening parameters. @table @asis @item @asis{half-life} Half-life time for the penalty @item @asis{reuse-threshold} Value to start reusing a route @item @asis{suppress-threshold} Value to start suppressing a route @item @asis{max-suppress} Maximum duration to suppress a stable route @end table The route-flap damping algorithm is compatible with @cite{RFC2439}. The use of this command is not recommended nowadays, see @uref{http://www.ripe.net/ripe/docs/ripe-378,,RIPE-378}. @end deffn @node BGP MED @section BGP MED The BGP MED (Multi_Exit_Discriminator) attribute has properties which can cause subtle convergence problems in BGP. These properties and problems have proven to be hard to understand, at least historically, and may still not be widely understood. The following attempts to collect together and present what is known about MED, to help operators and Quagga users in designing and configuring their networks. The BGP @acronym{MED, Multi_Exit_Discriminator} attribute is intended to allow one AS to indicate its preferences for its ingress points to another AS. The MED attribute will not be propagated on to another AS by the receiving AS - it is `non-transitive' in the BGP sense. E.g., if AS X and AS Y have 2 different BGP peering points, then AS X might set a MED of 100 on routes advertised at one and a MED of 200 at the other. When AS Y selects between otherwise equal routes to or via AS X, AS Y should prefer to take the path via the lower MED peering of 100 with AS X. Setting the MED allows an AS to influence the routing taken to it within another, neighbouring AS. In this use of MED it is not really meaningful to compare the MED value on routes where the next AS on the paths differs. E.g., if AS Y also had a route for some destination via AS Z in addition to the routes from AS X, and AS Z had also set a MED, it wouldn't make sense for AS Y to compare AS Z's MED values to those of AS X. The MED values have been set by different administrators, with different frames of reference. The default behaviour of BGP therefore is to not compare MED values across routes received from different neighbouring ASes. In Quagga this is done by comparing the neighbouring, left-most AS in the received AS_PATHs of the routes and only comparing MED if those are the same. @c TeXInfo uses the old, non-UTF-8 capable, pdftex, and so @c doesn't render TeX the unicode precedes character correctly in PDF, etc. @c Using a TeX code on the other hand doesn't work for non-TeX outputs @c (plaintext, e.g.). So, use an output-conditional macro. @iftex @macro mprec{} @math{\\prec} @end macro @end iftex @ifnottex @macro mprec{} @math{≺} @end macro @end ifnottex Unfortunately, this behaviour of MED, of sometimes being compared across routes and sometimes not, depending on the properties of those other routes, means MED can cause the order of preference over all the routes to be undefined. That is, given routes A, B, and C, if A is preferred to B, and B is preferred to C, then a well-defined order should mean the preference is transitive (in the sense of orders @footnote{For some set of objects to have an order, there @emph{must} be some binary ordering relation that is defined for @emph{every} combination of those objects, and that relation @emph{must} be transitive. I.e.@:, if the relation operator is @mprec{}, and if a @mprec{} b and b @mprec{} c then that relation must carry over and it @emph{must} be that a @mprec{} c for the objects to have an order. The ordering relation may allow for equality, i.e. a @mprec{} b and b @mprec{} a may both be true amd imply that a and b are equal in the order and not distinguished by it, in which case the set has a partial order. Otherwise, if there is an order, all the objects have a distinct place in the order and the set has a total order.}) and that A would be preferred to C. However, when MED is involved this need not be the case. With MED it is possible that C is actually preferred over A. So A is preferred to B, B is preferred to C, but C is preferred to A. This can be true even where BGP defines a deterministic ``most preferred'' route out of the full set of A,B,C. With MED, for any given set of routes there may be a deterministically preferred route, but there need not be any way to arrange them into any order of preference. With unmodified MED, the order of preference of routes literally becomes undefined. That MED can induce non-transitive preferences over routes can cause issues. Firstly, it may be perceived to cause routing table churn locally at speakers; secondly, and more seriously, it may cause routing instability in iBGP topologies, where sets of speakers continually oscillate between different paths. The first issue arises from how speakers often implement routing decisions. Though BGP defines a selection process that will deterministically select the same route as best at any given speaker, even with MED, that process requires evaluating all routes together. For performance and ease of implementation reasons, many implementations evaluate route preferences in a pair-wise fashion instead. Given there is no well-defined order when MED is involved, the best route that will be chosen becomes subject to implementation details, such as the order the routes are stored in. That may be (locally) non-deterministic, e.g.@: it may be the order the routes were received in. This indeterminism may be considered undesirable, though it need not cause problems. It may mean additional routing churn is perceived, as sometimes more updates may be produced than at other times in reaction to some event . This first issue can be fixed with a more deterministic route selection that ensures routes are ordered by the neighbouring AS during selection. @xref{bgp deterministic-med}. This may reduce the number of updates as routes are received, and may in some cases reduce routing churn. Though, it could equally deterministically produce the largest possible set of updates in response to the most common sequence of received updates. A deterministic order of evaluation tends to imply an additional overhead of sorting over any set of n routes to a destination. The implementation of deterministic MED in Quagga scales significantly worse than most sorting algorithms at present, with the number of paths to a given destination. That number is often low enough to not cause any issues, but where there are many paths, the deterministic comparison may quickly become increasingly expensive in terms of CPU. Deterministic local evaluation can @emph{not} fix the second, more major, issue of MED however. Which is that the non-transitive preference of routes MED can cause may lead to routing instability or oscillation across multiple speakers in iBGP topologies. This can occur with full-mesh iBGP, but is particularly problematic in non-full-mesh iBGP topologies that further reduce the routing information known to each speaker. This has primarily been documented with iBGP route-reflection topologies. However, any route-hiding technologies potentially could also exacerbate oscillation with MED. This second issue occurs where speakers each have only a subset of routes, and there are cycles in the preferences between different combinations of routes - as the undefined order of preference of MED allows - and the routes are distributed in a way that causes the BGP speakers to 'chase' those cycles. This can occur even if all speakers use a deterministic order of evaluation in route selection. E.g., speaker 4 in AS A might receive a route from speaker 2 in AS X, and from speaker 3 in AS Y; while speaker 5 in AS A might receive that route from speaker 1 in AS Y. AS Y might set a MED of 200 at speaker 1, and 100 at speaker 3. I.e, using ASN:ID:MED to label the speakers: @example /---------------\ X:2------|--A:4-------A:5--|-Y:1:200 Y:3:100--|-/ | \---------------/ @end example Assuming all other metrics are equal (AS_PATH, ORIGIN, 0 IGP costs), then based on the RFC4271 decision process speaker 4 will choose X:2 over Y:3:100, based on the lower ID of 2. Speaker 4 advertises X:2 to speaker 5. Speaker 5 will continue to prefer Y:1:200 based on the ID, and advertise this to speaker 4. Speaker 4 will now have the full set of routes, and the Y:1:200 it receives from 5 will beat X:2, but when speaker 4 compares Y:1:200 to Y:3:100 the MED check now becomes active as the ASes match, and now Y:3:100 is preferred. Speaker 4 therefore now advertises Y:3:100 to 5, which will also agrees that Y:3:100 is preferred to Y:1:200, and so withdraws the latter route from 4. Speaker 4 now has only X:2 and Y:3:100, and X:2 beats Y:3:100, and so speaker 4 implicitly updates its route to speaker 5 to X:2. Speaker 5 sees that Y:1:200 beats X:2 based on the ID, and advertises Y:1:200 to speaker 4, and the cycle continues. The root cause is the lack of a clear order of preference caused by how MED sometimes is and sometimes is not compared, leading to this cycle in the preferences between the routes: @example /---> X:2 ---beats---> Y:3:100 --\ | | | | \---beats--- Y:1:200 <---beats---/ @end example This particular type of oscillation in full-mesh iBGP topologies can be avoided by speakers preferring already selected, external routes rather than choosing to update to new a route based on a post-MED metric (e.g. router-ID), at the cost of a non-deterministic selection process. Quagga implements this, as do many other implementations, so long as it is not overridden by setting @ref{bgp bestpath compare-routerid}, and see also @ref{BGP decision process}, . However, more complex and insidious cycles of oscillation are possible with iBGP route-reflection, which are not so easily avoided. These have been documented in various places. See, e.g., @cite{McPherson, D. and Gill, V. and Walton, D., "Border Gateway Protocol (BGP) Persistent Route Oscillation Condition", IETF RFC3345}, and @cite{Flavel, A. and M. Roughan, "Stable and flexible iBGP", ACM SIGCOMM 2009}, and @cite{Griffin, T. and G. Wilfong, "On the correctness of IBGP configuration", ACM SIGCOMM 2002} for concrete examples and further references. There is as of this writing @emph{no} known way to use MED for its original purpose; @emph{and} reduce routing information in iBGP topologies; @emph{and} be sure to avoid the instability problems of MED due the non-transitive routing preferences it can induce; in general on arbitrary networks. There may be iBGP topology specific ways to reduce the instability risks, even while using MED, e.g.@: by constraining the reflection topology and by tuning IGP costs between route-reflector clusters, see RFC3345 for details. In the near future, the Add-Path extension to BGP may also solve MED oscillation while still allowing MED to be used as intended, by distributing "best-paths per neighbour AS". This would be at the cost of distributing at least as many routes to all speakers as a full-mesh iBGP would, if not more, while also imposing similar CPU overheads as the "Deterministic MED" feature at each Add-Path reflector. More generally, the instability problems that MED can introduce on more complex, non-full-mesh, iBGP topologies may be avoided either by: @itemize @item Setting @ref{bgp always-compare-med}, however this allows MED to be compared across values set by different neighbour ASes, which may not produce coherent desirable results, of itself. @item Effectively ignoring MED by setting MED to the same value (e.g.@: 0) using @ref{routemap set metric} on all received routes, in combination with setting @ref{bgp always-compare-med} on all speakers. This is the simplest and most performant way to avoid MED oscillation issues, where an AS is happy not to allow neighbours to inject this problematic metric. @end itemize As MED is evaluated after the AS_PATH length check, another possible use for MED is for intra-AS steering of routes with equal AS_PATH length, as an extension of the last case above. As MED is evaluated before IGP metric, this can allow cold-potato routing to be implemented to send traffic to preferred hand-offs with neighbours, rather than the closest hand-off according to the IGP metric. Note that even if action is taken to address the MED non-transitivity issues, other oscillations may still be possible. E.g., on IGP cost if iBGP and IGP topologies are at cross-purposes with each other - see the Flavel and Roughan paper above for an example. Hence the guideline that the iBGP topology should follow the IGP topology. @deffn {BGP} {bgp deterministic-med} {} @anchor{bgp deterministic-med} Carry out route-selection in way that produces deterministic answers locally, even in the face of MED and the lack of a well-defined order of preference it can induce on routes. Without this option the preferred route with MED may be determined largely by the order that routes were received in. Setting this option will have a performance cost that may be noticeable when there are many routes for each destination. Currently in Quagga it is implemented in a way that scales poorly as the number of routes per destination increases. The default is that this option is not set. @end deffn Note that there are other sources of indeterminism in the route selection process, specifically, the preference for older and already selected routes from eBGP peers, @xref{BGP decision process}. @deffn {BGP} {bgp always-compare-med} {} @anchor{bgp always-compare-med} Always compare the MED on routes, even when they were received from different neighbouring ASes. Setting this option makes the order of preference of routes more defined, and should eliminate MED induced oscillations. If using this option, it may also be desirable to use @ref{routemap set metric} to set MED to 0 on routes received from external neighbours. This option can be used, together with @ref{routemap set metric} to use MED as an intra-AS metric to steer equal-length AS_PATH routes to, e.g., desired exit points. @end deffn @node BGP network @section BGP network @menu * BGP route:: * Route Aggregation:: * Redistribute to BGP:: @end menu @node BGP route @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{bgpd} 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 @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 include 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 @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 @section BGP Peer @menu * Defining Peer:: * BGP Peer commands:: * Peer filtering:: @end menu @node Defining Peer @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 @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. To specify IPv4 session addresses, see the @code{neighbor @var{peer} update-source} command below. This command is deprecated and may be removed in a future release. Its use should be avoided. @end deffn @deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {} @deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {} This command specifies an announced route's nexthop as being equivalent to the address of the bgp router if it is learned via eBGP. If the optional keyword @code{all} is specified the modifiation is done also for routes learned via iBGP. @end deffn @deffn {BGP} {neighbor @var{peer} update-source @var{}} {} @deffnx {BGP} {no neighbor @var{peer} update-source} {} Specify the IPv4 source address to use for the @acronym{BGP} session to this neighbour, may be specified as either an IPv4 address directly or as an interface name (in which case the @command{zebra} daemon MUST be running in order for @command{bgpd} to be able to retrieve interface state). @example @group router bgp 64555 neighbor foo update-source 192.168.0.1 neighbor bar update-source lo0 @end group @end example @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 @deffn {BGP} {neighbor @var{peer} local-as @var{as-number}} {} @deffnx {BGP} {neighbor @var{peer} local-as @var{as-number} no-prepend} {} @deffnx {BGP} {neighbor @var{peer} local-as @var{as-number} no-prepend replace-as} {} @deffnx {BGP} {no neighbor @var{peer} local-as} {} Specify an alternate AS for this BGP process when interacting with the specified peer. With no modifiers, the specified local-as is prepended to the received AS_PATH when receiving routing updates from the peer, and prepended to the outgoing AS_PATH (after the process local AS) when transmitting local routes to the peer. If the no-prepend attribute is specified, then the supplied local-as is not prepended to the received AS_PATH. If the replace-as attribute is specified, then only the supplied local-as is prepended to the AS_PATH when transmitting local-route updates to this peer. Note that replace-as can only be specified if no-prepend is. This command is only allowed for eBGP peers. @end deffn @deffn {BGP} {neighbor @var{peer} ttl-security hops @var{number}} {} @deffnx {BGP} {no neighbor @var{peer} ttl-security hops @var{number}} {} This command enforces Generalized TTL Security Mechanism (GTSM), as specified in RFC 5082. With this command, only neighbors that are the specified number of hops away will be allowed to become neighbors. This command is mututally exclusive with @command{ebgp-multihop}. @end deffn @node Peer filtering @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 @deffn {BGP} {bgp route-reflector allow-outbound-policy} {} By default, attribute modification via route-map policy out is not reflected on reflected routes. This option allows the modifications to be reflected as well. Once enabled, it affects all reflected routes. @end deffn @c ----------------------------------------------------------------------- @node BGP Peer Group @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 @section BGP Address Family Multiprotocol BGP enables BGP to carry routing information for multiple Network Layer protocols. BGP supports multiple Address Family Identifier (AFI), namely IPv4 and IPv6. Support is also provided for multiple sets of per-AFI information via Subsequent Address Family Identifiers (SAFI). In addition to unicast information, VPN information @cite{RFC4364} and @cite{RFC4659}, and Encapsulation information @cite{RFC5512} is supported. @deffn {Command} {show ip bgp vpnv4 all} {} @deffnx {Command} {show ipv6 bgp vpn all} {} Print active IPV4 or IPV6 routes advertised via the VPN SAFI. @end deffn @deffn {Command} {show ip bgp encap all} {} @deffnx {Command} {show ipv6 bgp encap all} {} Print active IPV4 or IPV6 routes advertised via the Encapsulation SAFI. @end deffn @deffn {Command} {show bgp ipv4 encap summary} {} @deffnx {Command} {show bgp ipv4 vpn summary} {} @deffnx {Command} {show bgp ipv6 encap summary} {} @deffnx {Command} {show bgp ipv6 vpn summary} {} Print a summary of neighbor connections for the specified AFI/SAFI combination. @end deffn @c ----------------------------------------------------------------------- @node Autonomous System @section Autonomous System The @acronym{AS,Autonomous System} number is one of the essential element of BGP. BGP is a distance vector routing protocol, and the AS-Path framework provides distance vector metric and loop detection to BGP. @cite{RFC1930, Guidelines for creation, selection, and registration of an Autonomous System (AS)} provides some background on the concepts of an AS. The AS number is a two octet value, ranging in value from 1 to 65535. The 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 @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 @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 @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 @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}} {} Prepend the given string of AS numbers to the AS_PATH. @end deffn @deffn {Route Map} {set as-path prepend last-as @var{num}} {} Prepend the existing last AS number (the leftmost ASN) to the AS_PATH. @end deffn @node Private AS Numbers @subsection Private AS Numbers @c ----------------------------------------------------------------------- @node BGP Communities Attribute @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 @cite{RFC1997, BGP Communities Attribute} and @cite{RFC1998, 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 @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 @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 @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 @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 @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 and 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 @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 @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 @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 @section Displaying BGP Routes @menu * Show IP BGP:: * More Show IP BGP:: @end menu @node Show IP BGP @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 @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 ip bgp dampened-paths} {} Display paths suppressed due to dampening @end deffn @deffn {Command} {show ip bgp flap-statistics} {} Display flap statistics of routes @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 @section Capability Negotiation When adding IPv6 routing information exchange feature to BGP. There were some proposals. @acronym{IETF,Internet Engineering Task Force} @acronym{IDR, Inter Domain Routing} @acronym{WG, Working group} adopted a proposal called Multiprotocol Extension for BGP. The specification is described in @cite{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 did not have the feature to detect remote peer's capabilities, e.g. whether it can handle prefix types other than IPv4 unicast routes. This was a big problem using Multiprotocol Extension for BGP to operational network. @cite{RFC2842, Capabilities Advertisement with BGP-4} adopted a feature called Capability Negotiation. @command{bgpd} use this Capability Negotiation to detect the remote peer's capabilities. If the peer is only configured as IPv4 unicast neighbor, @command{bgpd} does not send these Capability Negotiation packets (at least not unless other optional BGP features require capability negotation). By default, Quagga 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, Quagga 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 @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 @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 @samp{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 @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 displayed. ``network'' and ``aggregate-address'' argument is displayed as ``A.B.C.D M.M.M.M'' Quagga: network 10.0.0.0/8 Cisco: network 10.0.0.0 Quagga: 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 @command{bgp config-type cisco} is specified, community attribute is not sent to the neighbor by default. To send community attribute user has to specify @command{neighbor A.B.C.D send-community} command. @example ! 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 ! @end example @deffn {Command} {bgp config-type zebra} {} Quagga style BGP configuration. This is default. @end deffn @node BGP instance and view @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 @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 @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 @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 @section Dump BGP packets and table @deffn Command {dump bgp all @var{path} [@var{interval}]} {} @deffnx Command {dump bgp all-et @var{path} [@var{interval}]} {} @deffnx Command {no dump bgp all [@var{path}] [@var{interval}]} {} Dump all BGP packet and events to @var{path} file. If @var{interval} is set, a new file will be created for echo @var{interval} of seconds. The path @var{path} can be set with date and time formatting (strftime). The type ‘all-et’ enables support for Extended Timestamp Header (@pxref{Packet Binary Dump Format}). (@pxref{Packet Binary Dump Format}) @end deffn @deffn Command {dump bgp updates @var{path} [@var{interval}]} {} @deffnx Command {dump bgp updates-et @var{path} [@var{interval}]} {} @deffnx Command {no dump bgp updates [@var{path}] [@var{interval}]} {} Dump only BGP updates messages to @var{path} file. If @var{interval} is set, a new file will be created for echo @var{interval} of seconds. The path @var{path} can be set with date and time formatting (strftime). The type ‘updates-et’ enables support for Extended Timestamp Header (@pxref{Packet Binary Dump Format}). @end deffn @deffn Command {dump bgp routes-mrt @var{path}} {} @deffnx Command {dump bgp routes-mrt @var{path} @var{interval}} {} @deffnx Command {no dump bgp route-mrt [@var{path}] [@var{interval}]} {} Dump whole BGP routing table to @var{path}. This is heavy process. The path @var{path} can be set with date and time formatting (strftime). If @var{interval} is set, a new file will be created for echo @var{interval} of seconds. @end deffn Note: the interval variable can also be set using hours and minutes: 04h20m00. @node BGP Configuration Examples @section BGP Configuration Examples Example of a session to an upstream, advertising only one prefix to it. @example router bgp 64512 bgp router-id 10.236.87.1 network 10.236.87.0/24 neighbor upstream peer-group neighbor upstream remote-as 64515 neighbor upstream capability dynamic neighbor upstream prefix-list pl-allowed-adv out neighbor 10.1.1.1 peer-group upstream neighbor 10.1.1.1 description ACME ISP ! ip prefix-list pl-allowed-adv seq 5 permit 82.195.133.0/25 ip prefix-list pl-allowed-adv seq 10 deny any @end example A more complex example. With upstream, peer and customer sessions. Advertising global prefixes and NO_EXPORT prefixes and providing actions for customer routes based on community values. Extensive use of route-maps and the 'call' feature to support selective advertising of prefixes. This example is intended as guidance only, it has NOT been tested and almost certainly containts silly mistakes, if not serious flaws. @example router bgp 64512 bgp router-id 10.236.87.1 network 10.123.456.0/24 network 10.123.456.128/25 route-map rm-no-export neighbor upstream capability dynamic neighbor upstream route-map rm-upstream-out out neighbor cust capability dynamic neighbor cust route-map rm-cust-in in neighbor cust route-map rm-cust-out out neighbor cust send-community both neighbor peer capability dynamic neighbor peer route-map rm-peer-in in neighbor peer route-map rm-peer-out out neighbor peer send-community both neighbor 10.1.1.1 remote-as 64515 neighbor 10.1.1.1 peer-group upstream neighbor 10.2.1.1 remote-as 64516 neighbor 10.2.1.1 peer-group upstream neighbor 10.3.1.1 remote-as 64517 neighbor 10.3.1.1 peer-group cust-default neighbor 10.3.1.1 description customer1 neighbor 10.3.1.1 prefix-list pl-cust1-network in neighbor 10.4.1.1 remote-as 64518 neighbor 10.4.1.1 peer-group cust neighbor 10.4.1.1 prefix-list pl-cust2-network in neighbor 10.4.1.1 description customer2 neighbor 10.5.1.1 remote-as 64519 neighbor 10.5.1.1 peer-group peer neighbor 10.5.1.1 prefix-list pl-peer1-network in neighbor 10.5.1.1 description peer AS 1 neighbor 10.6.1.1 remote-as 64520 neighbor 10.6.1.1 peer-group peer neighbor 10.6.1.1 prefix-list pl-peer2-network in neighbor 10.6.1.1 description peer AS 2 ! ip prefix-list pl-default permit 0.0.0.0/0 ! ip prefix-list pl-upstream-peers permit 10.1.1.1/32 ip prefix-list pl-upstream-peers permit 10.2.1.1/32 ! ip prefix-list pl-cust1-network permit 10.3.1.0/24 ip prefix-list pl-cust1-network permit 10.3.2.0/24 ! ip prefix-list pl-cust2-network permit 10.4.1.0/24 ! ip prefix-list pl-peer1-network permit 10.5.1.0/24 ip prefix-list pl-peer1-network permit 10.5.2.0/24 ip prefix-list pl-peer1-network permit 192.168.0.0/24 ! ip prefix-list pl-peer2-network permit 10.6.1.0/24 ip prefix-list pl-peer2-network permit 10.6.2.0/24 ip prefix-list pl-peer2-network permit 192.168.1.0/24 ip prefix-list pl-peer2-network permit 192.168.2.0/24 ip prefix-list pl-peer2-network permit 172.16.1/24 ! ip as-path access-list asp-own-as permit ^$ ip as-path access-list asp-own-as permit _64512_ ! ! ################################################################# ! Match communities we provide actions for, on routes receives from ! customers. Communities values of :X, with X, have actions: ! ! 100 - blackhole the prefix ! 200 - set no_export ! 300 - advertise only to other customers ! 400 - advertise only to upstreams ! 500 - set no_export when advertising to upstreams ! 2X00 - set local_preference to X00 ! ! blackhole the prefix of the route ip community-list standard cm-blackhole permit 64512:100 ! ! set no-export community before advertising ip community-list standard cm-set-no-export permit 64512:200 ! ! advertise only to other customers ip community-list standard cm-cust-only permit 64512:300 ! ! advertise only to upstreams ip community-list standard cm-upstream-only permit 64512:400 ! ! advertise to upstreams with no-export ip community-list standard cm-upstream-noexport permit 64512:500 ! ! set local-pref to least significant 3 digits of the community ip community-list standard cm-prefmod-100 permit 64512:2100 ip community-list standard cm-prefmod-200 permit 64512:2200 ip community-list standard cm-prefmod-300 permit 64512:2300 ip community-list standard cm-prefmod-400 permit 64512:2400 ip community-list expanded cme-prefmod-range permit 64512:2... ! ! Informational communities ! ! 3000 - learned from upstream ! 3100 - learned from customer ! 3200 - learned from peer ! ip community-list standard cm-learnt-upstream permit 64512:3000 ip community-list standard cm-learnt-cust permit 64512:3100 ip community-list standard cm-learnt-peer permit 64512:3200 ! ! ################################################################### ! Utility route-maps ! ! These utility route-maps generally should not used to permit/deny ! routes, i.e. they do not have meaning as filters, and hence probably ! should be used with 'on-match next'. These all finish with an empty ! permit entry so as not interfere with processing in the caller. ! route-map rm-no-export permit 10 set community additive no-export route-map rm-no-export permit 20 ! route-map rm-blackhole permit 10 description blackhole, up-pref and ensure it cant escape this AS set ip next-hop 127.0.0.1 set local-preference 10 set community additive no-export route-map rm-blackhole permit 20 ! ! Set local-pref as requested route-map rm-prefmod permit 10 match community cm-prefmod-100 set local-preference 100 route-map rm-prefmod permit 20 match community cm-prefmod-200 set local-preference 200 route-map rm-prefmod permit 30 match community cm-prefmod-300 set local-preference 300 route-map rm-prefmod permit 40 match community cm-prefmod-400 set local-preference 400 route-map rm-prefmod permit 50 ! ! Community actions to take on receipt of route. route-map rm-community-in permit 10 description check for blackholing, no point continuing if it matches. match community cm-blackhole call rm-blackhole route-map rm-community-in permit 20 match community cm-set-no-export call rm-no-export on-match next route-map rm-community-in permit 30 match community cme-prefmod-range call rm-prefmod route-map rm-community-in permit 40 ! ! ##################################################################### ! Community actions to take when advertising a route. ! These are filtering route-maps, ! ! Deny customer routes to upstream with cust-only set. route-map rm-community-filt-to-upstream deny 10 match community cm-learnt-cust match community cm-cust-only route-map rm-community-filt-to-upstream permit 20 ! ! Deny customer routes to other customers with upstream-only set. route-map rm-community-filt-to-cust deny 10 match community cm-learnt-cust match community cm-upstream-only route-map rm-community-filt-to-cust permit 20 ! ! ################################################################### ! The top-level route-maps applied to sessions. Further entries could ! be added obviously.. ! ! Customers route-map rm-cust-in permit 10 call rm-community-in on-match next route-map rm-cust-in permit 20 set community additive 64512:3100 route-map rm-cust-in permit 30 ! route-map rm-cust-out permit 10 call rm-community-filt-to-cust on-match next route-map rm-cust-out permit 20 ! ! Upstream transit ASes route-map rm-upstream-out permit 10 description filter customer prefixes which are marked cust-only call rm-community-filt-to-upstream on-match next route-map rm-upstream-out permit 20 description only customer routes are provided to upstreams/peers match community cm-learnt-cust ! ! Peer ASes ! outbound policy is same as for upstream route-map rm-peer-out permit 10 call rm-upstream-out ! route-map rm-peer-in permit 10 set community additive 64512:3200 @end example quagga-1.2.4/doc/defines.texi000066400000000000000000000006641325323223500160460ustar00rootroot00000000000000@c -*- texinfo -*- @c Set variables @set PACKAGE_NAME Quagga @set PACKAGE_TARNAME quagga @set PACKAGE_STRING Quagga 1.2.0 @set AUTHORS Kunihiro Ishiguro, et al. @set COPYRIGHT_YEAR 1999-2005 @set COPYRIGHT_STR Copyright @copyright{} @value{COPYRIGHT_YEAR} @value{AUTHORS} @c These may vary with installation environment. @set INSTALL_PREFIX_ETC /etc/quagga @set INSTALL_PREFIX_SBIN /usr/sbin @set INSTALL_PREFIX_STATE /var/run/quagga quagga-1.2.4/doc/draft-zebra-00.ms000066400000000000000000000121351325323223500165110ustar00rootroot00000000000000.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. quagga-1.2.4/doc/draft-zebra-00.txt000066400000000000000000000131651325323223500167150ustar00rootroot00000000000000 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] quagga-1.2.4/doc/fig-normal-processing.dia000066400000000000000000001700561325323223500204250ustar00rootroot00000000000000 #A4# #Best Path Selection# #Local RIB# #From Peer A# #From Peer B# #From Peer C# #From Peer D# #To Peer A# #To Peer B# #To Peer C# #To Peer D# #D# #C# #B# #A# #A# #B# #C# #D# #X# #“Out†Filter for Peer X# ## #“In†Filter for Peer X# #X# quagga-1.2.4/doc/fig-normal-processing.png000066400000000000000000000724061325323223500204540ustar00rootroot00000000000000‰PNG  IHDR‡V”ü ¢sBITÛáOà pHYsÐй‹çŸ IDATxœìy\TÕûÇŸ{gc†}@%\5ÑT´4JÍ}ͰÜÒŒ’2-Ó,ñkYÚϬÌÔ2·J%ÍÂ]sTdsؘ}½÷÷ÇÅq„feæ¼ÿðuϹçžç¼ç~î9÷œç`$IÑ2r¹<55õòåË………ùùùF¯¿{÷î]ºt4hPJJ ‹Å2zý„õPWW·iÓ¦ .°Ùìÿý׈5‡………††¢vd`H•­žžž””ÄårÍ`+88xÇŽ f°…@˜‚ ¶nݺråJ‰DLG?…´Ò†‚ƒƒüñÇÑ£G›¢r„@ªŒh‘S§N%$$$Ù‰NOqsäàD§ÝJ©JuY&K­¯¤Ra–žž>räH£[A ,ËêÕ«?ûì3ðÝÕoˆ‹w Ž3X¿BR!¨Î,½û­\\ŠÚQ‡©2B7 22’ËåÎqqÙè鉛ذ¢¶v·P|ç·cbƒ„ù¸~ýúÀU*uØoÝ^0¡%’(Ê^[]p 88øöíÛ®®®&´…0 ¦~Ø":*›7oær¹ýX¬TÓK2ਫ਼žýX,.—»yófÓD ÌÇŠ+T*•_ØÓJ2`xH¿Õl(.—ûõ×_›ÖÂ4 UFèæÊ•+°ÔÕ•f.‹4€¥®®Ó„m V«333 °ç[f0‡a´€óµ£ Re„n ôfóÓ×3¡ÌQ¦Û ¬¬L*•²œèL7óXtvïæ1‡0.H•º9{ö,˜bzW+Pæ(Ó„mP\\¬V«éžf³Ètò€œœ³YD¤ÊarpZCŒÐ ¤Ê@X 8`Í7nœI­jÛÂqÜÝÝ=11±¼¼ÜDæ 0 ›8q¢‰êG „e™9sfs-Ã0ŒZ&®V"L_ ?Þ¥KM®³³³‰üÐ@Y$IR,ß¿ݺu ,HKK3…­½{÷RìpŸ¼ò"ËïyK{@ ÏFZú¯ƒûìƒ>˜;wî»ï¾›ššzèС3gÎèóãOž<$I&&&òùüÜÜܼ¼<.—»páÂVò›;Ù„_ýµwïÞ={öœ:uêéÓ§›ü:{£;²Ã瀼&ËlÚ¼_$%I‹Mm @Øì €ó·þWý÷hñÃßHÂЭˆW+XD˜G°‡ª}vpì””ªs­P(öìÙsñâÅððpX½zõÆßyçÍož>}ºJ¥JNNž={öŒ3¨ã–>•×ÔÔ¸¹¹ÁãñŽ=º~ýúƒ@FFFFFFVVVPP,\¸ð­·ÞR(ÙÙÙ:ó™L¦¶“MP©Tû÷ï§œœ:uêÆ<¸téÒVÿ#lç®SE÷wò:×dÉÏÍeyÇšnL;_©¼.—Ó1LE’E¢×]\La°aª ö]ÿÃéýÿ£3ík6Œƒÿó ÷žJ~.¨e5 7Ö‹îïté±À1äU oO…ÖÅKk¦Æ_˜——×Ò(ü Aƒ¨.—+•J###©dddä½{÷4Å¢££€N§79n Í{€««kLLÌÑ£G©­Çrss)G©Ë…B¡R©äñx-åS4N6áÌ™3UUUñññ•••~~~;wÞ·oŸª2Õ]älÒä˜T›ˆD°ÒÍí3>ÿš\^ Tve0Œk°mjŠI¨j¹ûvfiwÌ æÒã­ºËË4iµ¤¢þú'¢û;Ø=9uXÛÖô¶.^ÚXƒ0µá½ÇŸúC$‰a˜þ—7¡¥÷êcÛ¶m>>>šLooï–ò[·BMrÓþÓ”””jO8·´»ËL¡Íj€ƒ"Ç“8œË2Ù)©ô Xü¡›™b "6€TX(ªÍÁ0IªyÅGíO•Á!àºkwUC¾v¦JÄ­ÏüP”÷ƒK¯%ŽA úk³þâe ÂÔU rrrÊÍÍíÛ·/äääP£Æ%66jjjôÉo‰DòçŸþôÓOóæÍ£rŠ‹‹CCC÷íÛ÷ÑGÕë@óî²ãjó©´B­žíââˆaÓÙìSRé!‘(ÅÍ ¬A ô„Wt‚Ÿ[þèöW¢Ú[2a±ƒKH;ê©>10`8`4 0êkÌÁµŽiXcÎã€=Τ=.‰7»üqhõ,öTUÎT?.I4»üqhõ,ùTU$šŽ²Iw¤øÖËëÛ–w÷¢Ñ*:·iÜ s‹ý¬æäDµ¤€$ø™x'üIsxF(;¤„BRtXto‡Z¢{ßæÐ]ôºó5™ I…GÐ({Qx‡Œ/¹ù¯ø¨øëúD³ê¸¨„Å’’¿0º³s×)ì°¹¸ƒ§¥=27( ¢í#.ØÏàtõ¶ËsØ.I²)À™nîþXãì0B^WŸñŠ¥€°$$!¼³EZ|„UëyFcÑýõ)YS|¼:¿¢ó¬gç±F“4<óuo«`3ˆó÷¸ôxÓwl:'*Ù%P{@%xØŽùŠTDÒ¶F1*Šˆæ¶æ}/¼ód'TNä2v7ÍìÑ’P ‹”õ÷”õyÊú{Êú{„œ¯³ Ã#2±8>>^ÿ("FŠ"Ò!ï$ÑÖ-¡l »þñvB‡^Bà1Ÿå3@“ÜýVÁ˶ ?†Ó9];åD½ç9t‡KÏE-´Éµ¦Å¾%*#¬ wг<“¤šŸñ>¡h°¨OÄ”uw·6¶t©2¢­ UFX;4o÷þ_hf¸¨%•õY«:àÐÂæ  uWß% %•Äì&s»nþþþlÏ>jeÛ6h1•¢ÎäLš4ÉlF©2¢ÀòÂ]“”•Ÿçïµ ?õ™ªÅe“˜[ìz—^Z›a8Ã5,88X.¸+mÈ'Ô2ó¸%æßU)ååúÎGXH•º>|8”ªTæ4J™‹ŠÒkÞ%rÓ³·&)ÈùRYŸg>ψfˆîý$«8¯I:‡Íré”@w ¥rèìÎÝÑÁÁ¡W¯^$©æ•üeǨh$ÑÑÑæ1‡0.H•ºa2™pK¡xfI#B™ó÷×±’Ãéîþ‡3#l“„‚%™T‰Íé¡AQsM µ:€éÙ›ó\2†»ôx‹Êd¸EP)))ðèær=¢ŽH}ÅE^É_NNNK–,1µ-„)@ªŒÐM\\lihP›Ë¢`KCƒÆtshή1k5I•¨¤>{™œC ´ dµü«ïÙØ8p–»ûÀ¯4¡Ú;¥¢lj¦zM:u„ j•ôö¿¯ðJþ2Ѳ{•œ_r3õÁ àóÏ?ïÞ½»)¬ L Z¯ŒÐ@ ˆŒŒär¹s\\6zzšúõXQ[»[( ¾sç‡Ãi©dCöZqÁMÒ-v½SÈ«&öЂ$j/$É«3“î9ä;–ßí"’âÃõY«<‡þÈòDåðùü‰'ž=K‘Å\}çˆÃ#¥RÆ“‹Ë€F£¥¦¦&'£¸ñ¤Êˆ9uêTBBI’èô7·AAtã‡h-U©.Ëd©õõT* ÃÒÓÓGŽÙJyR-瞪Ù/£;z<¤ù’‡@˜ÁoDy?h’.=Þr‰\Ú¤ I¨ªÿyÉ{Äþ'‹ú`ÿþýßÿýùóç=z‹joÑ+¶ G*5jË–-¨—Ü¡AªŒhôôô¤¤$.—k[ÁÁÁ;vìHHHxfI• °æôdR%¥’ ·p¯öa4–‰D @^y±ö¿Eš!h–Ï@Ï¡?ê |!«¸àà?Tg%Aܽ{—Ï׬}xzzöìÙ“ ɇèÐ UF<¹\žššzùòåÂÂÂüü|£×ß½{÷.]º 4(%%…ÅÒWY©BMÒ¹ë×~Ý7Bµ¤¢æÔ$MpMš£÷Èßí3V3Ât UFtTø)ÒGÇ4I¸¯‚FYЄmCÊÚssµ·ÓÍ+~'Ó;Æ¢N!l4ÑQq‹þX{?ùúk«µâ9 FF³é‰$p"—!IF˜¤ÊˆŽ Fwv¸ ÙT’P ùïS›¥#ÆEVzR;œœCÀ0vÄ< úƒ°a*#:0 ÷žœ¨'+@µ·„w·´Rh*QIýµ'¡×iÎn±O³#Æ©2¢cãÜ}†CÀpMRtÿgyå% úƒ°1Hµœå]âñÞÎôøÎlq==a H•Ì-ö3š“_cŠ$øY2žE]BØ 7Ö+ëïi’œÞ+‘ôaó UFtxp¦›û€€Ñ¨$!«åg~`¢ †»BR|TRô‡&éü¢s·iôa UFØL¯h—^‹5IyÕѽôa¨ò²ŸÄ]§»„¸Å|jAvRe„à1Ÿå3@“ÜýVÁ»aAR%®»²œ|¼#2Fsðˆû£;[Ö+„=€Ta+`¸Û€Ô'a‡I5?ã}BÑ`QŸ•úkŸ¨„Eš¤k¿é®(¸4 UFØ4o÷þO–¬¨%õ×Vk´ z"~¸OÊ=¡I:…Np yÅ‚þ ì ¤Ê›‚å7„>W“”•?ü­¥Â*ÁCsø„èP(ëînmÔ$ná®}WµR0.H•¶†Kä;L(MRpk“²>¯y1BVÛpsƒýBt… îê»$¡ ’ƒí·mG†0'hw „ ¢—ÕœœH(…T’îâ=òFwÍVwŸÎõ›2Ì­Çë÷P @<~ ’u—–ÈÊÏ=ÎÆ<â6£-Ofõ•6Í9ÐUk‹JX\¯µÄü<è³F¹»8áþ ³{‡°RD÷Ö’dpî>I2Âü ¾2Âf©¿þ©¤ð &éû¹SÈ+T_ùüϯus΀‹µc*dÁsai–/_$I*j®ñÎÏRMå3={{Ûáè¥ anP_a³¸öù€¡µš¥áÆgÔZ—@/F§ûT&‡Î·Œsk‚Õò3Þ×H2Îtsø%’d„E@ªŒ°Y0Ë}àWÝ‘J’* ÿj2‹½3Ñ ÇŸ¿nŒ:Ë9ˆ° h8ð3V¨¥Õi w°æäoQ§ö ReÄ3Ëåk×®3fLXXfÂÂÂÆŒ³víZ¹\ntçéœ.®}Vj’Êúû›Læ¦ÉqEªl÷¼;É[^}U“dG$±üž7º•ÝŽæ}WF´FzzzRR—Ë5ƒ­ààà;v$$$½f~Æ é£ã:O©Iڟ寓h¯\{åèîÕ¿|Ø üÿÏòà9t`Fî®ØF;B˜¤Êˆ9uêTBBI’èô7·AAtºÑ­”ªT—e²ÔúúG*†aééé#GŽ4® R)ª95I%z¤ó쉪ÉB•«q-":N4ñ ç_<\w£9x{úwð4®M;b9õZÂñéÏ4Áð¸BR!¨Î,½û­\\j¢v„0H•º‘‘‘\.wŽ‹ËFOOSê VÔÖî ƒƒƒïܹÃẫ<©–«„Eª†|¥ _Õ¯äç©e5:K^®Y* 5ТÃcÄp¯¿<™šÏÉ4¯øLïãZÑ´#Ÿ®SBû}lô^xSH¢({muÁcµ#„ù1~×alÞ¼™Ëåöc±RM/É€¤zzÞV(²¹ÜÍ›7òÉ'í«‡ón|¦¬¿¯•è¹Å²+_ H•íŽ(NæIàD.5º$ÃãvÄöˆ é·Úä’ Òoµ„ŸÇåæÒŽÍöBèæÊ•+°ÔÕ•f.‹4€¥®®Óíg¹»ôZÂp‹Ðÿ4áË r,cßÖ$üãÙo˜Âu3ûG$a˜™Z†Ñü#’À°v„° H•ºQ(ЛÉ4§QÊeºÝÐ]BÝnòõ§CàHÐc—+-Y¶/ØtA¬ÛyM’[£tÓÚj̸P73Û#Ò•·eÎÀv„°è»2B7†@MHˆ™ízӸĆ¢¬ÏÞýVV~¾•ýIÀÿ,Ÿ«&Í6(€°$4L=Âû¨£–J*Uä«ßÈ—˜ÈÕŽLÖ±?ŠIÉ8،׎æõ•¶ í‡Çàÿó±å7¸¥2.ôzsz…° }]/k$>ÝSuó¡Ô‚þ M@ªŒ°}Ïy>ÿƒ×ð_Y>t@Ÿ–í„ÎNù]œïi’\i—ŸÿAÿõë€æabÆgR«Ú¶pwwwOLL,//7!&“uäÈ£›@t˜^}=ãwNú´$ó^ÓáJôiÙà0øÑnÿi’B•k¨ýA—™3gêŒzöÙgŸéYƒ•F’$†aÇïÒ¥‹&×ÙÙ98Ø„éh,’$)‹ïß¿¿nݺ°°°´´4S ©¯¯ß¹sç¾}ûjjjœœœŒkÅʹZte`h\[¯²ïÊÍ¡~×¾mÉ‘œëÆTÈ‚/ÖŽ1‘E„5@Ç”£|Žh>U¨Iú©šW”š=£Ld}Wn+í{^@yy¹@ €Â±cÇæå5þͽ¼¼¼¼¼ô©ÁJ„©q½r—.]""Ú°˜Äp´-ÆÄÄøùù%&&šÔPŸ>}~úé§²²²îÝ»?ó*[¢¨¶ð·k¿¼—Ô7¨Ÿ¥}±*åA•5Azq®»3x® ~UUÕ‰'JKKkkkŸ}}ÄËË+00ðÅ_ôõõµ´/ Æý¢öìëõƒ”ôÑí~^h’íS4k¦gDÁ0ì·ß~{ï½÷Ö¯_?wî\±X¼xñâC‡±X¬·Þzkýúõ8Þ8žžž¾|ùòµk×Θ1cܸq999ãÇÿí·ßèz„iôððP«·ñ©®®^¶lÙñãÇU*Õ‹/¾øý÷ßSo:-å7q²%<N§Ûá#i|ï û®ýºôࢾÁýLªÍT7Wƒ Žw¡Ór8 ÌM—Ë:•Ë::_ÿ/mãÞԎرÐÇãñrrr‡ fR[VõŠãååÞ™ÓgA,*§H^, ³¬Wˆ–0Ñóª%ñj‹S£^ÖÔÔ¸¹=ÙHÇÏÏOs¼fÍšõë×ÇÇÇ@rrrQQQvv¶H$š>}º¯¯ï;ï¼CKIIY¹reeeåŠ+Nž<ùî»ïVUU%'''%%é'ýäÉ“QQQ@’dbb¢››[nn®Z­ž4iÒÂ… :ÔR~s'›£V«óóó—.]úÞ{ïÙa:†ã´˜™Û.l½Á;Á5¹6Ïqq!$ùH¥ÊÉn)jõÖÛ/9[µmo1à´°yo{ôéÏòò±´G&AΫ®»™™¿skZZZPPP·nÝLdèܹsiiiÖóŠC½Ž¼ Ïò}sœg½Ò3»~¥B´ˆ‰žW­ˆW+XD˜UyèЧf=h·¨””Jç Åž={.^¼«W¯Þ¸q£æ‡%''OŸ>]¥R%''Ïž={ÆŒÔqKŸÊ©÷‚ x<ÞÑ£Gׯ_ðàAÈÈÈÈÈÈÈÊÊ €… ¾õÖ[ …";;[g>“ÉÔv²9=zô ¼téÒ–þú¶ õúÉ—ðÀÔÚ¼ÉóIpÿ3R锪ªßE"kVåÓ§O“$2q–ÿHÓNr´,,/ÿ‘ã õÅ>}ú´‰TùáÇiiiVõŠ£yYûKUDˆ‹È{„š´êHÃÔ'a 4ÛÝÙ#xŒØ\ ·jÏ…ÑŸW­‹—6Ö LÿÇyyy-ÂÔø^Éår¥RiddcšÈÈÈ{÷ž¬1ˆŽŽj°Zû¸%4ï®®®111G=z4äææÀÔ©S©Ë…B¡R©äñx-åS4N6'///,,¬®®îÂ… /¾øâûï¿?cÆŒV³I4¯Ÿšóô›‡88€Ð+µ¥P©Tào;ßùÅ'ü™šc ¬ðGûudý!â7;Æþ`>]§I„B!.ò²Åü»JiUç¾YÚ/s`ôçUëâ¥5SÞ¼šŒÂS“·õ¿¼¹O:ߨWŒmÛ¶ùø@­[ÚóaÜç•áâeNajƒ*3Œ9sæ$''oß¾] ¬[·nñâÅíö£%ÂÃçNºlÙ2LJ "‘H233'L˜ÐRþ3{½………$I*ŠŠŠŠŸþ900°S§Níóíù¯½ß 1 IDAT¶ï±´9®¬Œ¨'ˆ:µº‹uØÏoƒC[+ùá¿ïÞô& G±© ÀѵÍK:mø‘Õ¦ç•áâeNajÛÜM›6-\¸°oß¾L&sÁ‚&š<µk×®5kÖ¬X±¢¬¬ÌÝÝ=::züøñ­ä·Îرc©&“Ù«W¯C‡é³RËnÑÜëí®µ¦¨W«o*Ñ,«;~ÉÜ}þá¹·ãßi_<Âf6äf­ Ž\fi_¬ýµÙpñ2›0Ñ¡Õø/MN999íÞ½{÷îÝ­k鸕j›Àb±¾øâ‹/¾øBÏ|ýýG˜š@D÷•ʽBá'uuûE¢?}}½hmëø>ª+yÿðò¸ÐÁo[ìÞÎá Âp y2•L¦”É”2™J&WÊ´’Òòer•Lªlÿgì['^’P)*9ßÙ#²Ç°]ïX#þ(&""¢ù“¿%ñÒÆJ„ õO¡yëÜ ßµ»€ƒã±,V,‹åO§oª¯_UW·]¿M¸Rtéڣ̉}&Í8Ï™Ån·KD»)o(Ûxò‹&3ôÁ‹­W GÈ„EšcµB ®»ÃöˆÂi¬vWh“˜z‰E@ªÜ.¾{ÕÒ.ľk{uΞ 0Ñý=ÏÅeS}}º´m›åáNë©”jåþë¿¥çýóæ…/ö‹ch£3„YÒuh/ÿçþwjÃŇçõ¿ 샄UGàxûŒ˜œ$¡V‰% kŠþxtk#¯øHİ –ç³/~L‡~dYäye  œ½ SJ÷]ûU穾Áý¶LÞ¶eÒ6SÜâY?%옹»wPíœ:I݆ôõó÷¾žSv˘þ!zàîäþybêÊÑ«õ°y¥÷ø!†M¶ÂpÃÅÅ«o—ØÏ{.’4<(¹±Á  ;–z^Y¨¯l/¾õgó!83¼oî‰ ²K–»{wß:ù»³Î|wak¥ R“ÿ úþ’ ^¹hè½Bšò »xYf!Üù)#¼}I’$U*š£cÐK^ÑçBR­–UW:úšÚCD›x±×ؾÁÑ_ü».›{½õ’AnÁ‹‡¾mDӾݦ—ån«¯8gÄ:­K=¯¬¤ÊvAóOÓÝßïÕÖ€Š$â¾R™¯TÀR×6TÂ{!lÄà.Cö]Û»7sLÕ8q†òôý“— .Îè?{ZÌ ý_Ú~¸ôÝ‚!‹B¯¬¤Êvö‹§©ïïÝB¡æ˜ã}Y¬…θöîiÍ¢³æœ÷R¯±Û.|{æþ)Ÿƒ2•ì§Ë?¿“¶pèÛÃÃ^À Å•W|q݆ôõÛ¦þ`©Ò$A(øµu·²q÷øÿ}W'©Óäß*½™ôëœq‘‰ó‡,pslÝS$ÀŽKßéú|[°Y=ˆ?pšP*ÄŠ ölËÿykØüåõwnÀƒ7€¤´D-•0\Ý9Ý{Þød™_ühÿ^¢³]Ìì¤E8?e„áCô„B^w+Ë(þ´‚X.ú%s÷¡*…v>†aM±4ƪ1k4†áF« hŽitggçüÃæz2¼f+ÇfžWí©²í304nZŒl“…cøØÈ—‡u¾ëêÎ?nRªãˆ$‘vûÈ™§_{cBŸ×èZÞ‰äB«ä_ü»~ëämð™ÁtéÞíõ·o¬z;lþrŒNwðñ™4‡:Kc9`8ÞçÓ¯ëneUžþ»âÔ±ØÍ?›ßI„N”jåќû®îlÖ79Ûy@lçØm¾ÕÎ|sð瘜g` [z^µ¤Ê¶O¨§­mÅáÌb/Ž_šõêÖsß\)º¤ÉÉ…[Ï}}4ç°&T§R­ÔôorÊn¾ù‡e<&IQñCÇ<£ãJþüU%¹t µLJÈåj…̳ß@N·ˆËó'ªÄ"œÎB!Ç™v5BTüðÁ÷_JÃ…¾(ÅÁÛWZQöà‡/e5•:5É{àÐòô´Êsÿ(øµn½úD,þÀtÎ@žÏ?»ýâ¶²úÒ&§ºzu[4ôíþ!.^ÒÎïÔgrô4Ó¹d'ØÞóª­ UFtT‚Ý;mÿåÕ¢+[Ïý¨®D“¯ª³ÉêÒïÿÛæàÁ’ÕÉÍædÆ’é$A¨¥º 'ì­dp ì±äƒûßm$ÕjœÁôŒ˜ðÊ­ÏÞ’$TŠÐ)ó7 IÏ~¯­x³ÿ×­4 …‚Á`²m«^dÞÖÏC&Ïõ0”›vàáÎ-‘)ës¿^ë3hxpâ 5xÅõ²R$¼œ4¾ËŒ7MäËòÛßžßr·âv“|o¶wÒà·Æô|‰š9èÀx²íŠÓé£Ñ£7ÃAªŒèØ ‹éûçÍß¾ò5XMA…êLˆ£]Xª”vŸÒåöv3¶ôÝÔ+f°WÌ`휘ÿýøT ‹LYo:ÇÚDCCÃáÇgÍšåèhÌ¥>MP $¥%ž}€g¿Å¿ïV êEÅû¬Ù 4Ǫ '¥Õ@¨”­×ÙJë¹Û/n»N3۟™é<=vÖäè©ô'J¬­ÊK‡-÷w 0º?;½Ù!:¹ßÔ}ó%>÷ªvgE©V¿ûW“®Ý8~­n÷_k†F£åååmÞ¼¹ªªÊüÖŸÚí† ²W-!”Š€Q/ÝPƒ´þë³_ÎÚ5í|þYmI¦á´ñ½'î›÷ûìsµ%4ÉÁ]†Œ4¾Kû©2B7Ç€R•ÊœF)sQQQí¸ÖÍÑíýQ4ÕÙœÐq¤ iv ŽãPSS³yóæÛ·›ê ÇÕ)¨sÝÍL¨Í¾êÖ³ƒãÆí^zì$I*‘PÙÀ—”–x JÈå@ýk88ß›µgÊÎ×þ¸qHE¡ÑšjÉíÛ·7oÞ\SSc G —ÈóɳõðÔþÎÛÃÞùuîþÂG>S’À‘á¸bT‹c×T;Õåg¯ƒVƒ‚’(Î^'ªË1¼!,ê+#tÃápvîÜ™°[(<+•¦¸¹ rp0Åhv©JuY&K­¯¤Ra¶sçN‡Ó¾ªjżM§6þWpAŸÂ Pd“×aÏ·ÏVGG­V«Õj‚ ¨)š«Õj…BÑüòªªªÍ›7Ïš5«GŽ™™Éa^'3KÈ¢&S¬4ÆÄ¾“g÷ŸëâІÀj8†ã´gtl4í¨ºà@C奠^K8>ý™&ÍVH*Õ™¥w¿•‹K lGËÒ4b¡MzzzRR—Ë5ƒ­ààà;v$$$´ïòwo=ÿµP&|vQ-úcq_½û50jD”BAÑþŸÂæ›¶‹£ Í­' C©Ô½ Çñ±cÇ>\ó™™êŸYó9¶LMì„ÓŸÖQjnÖžû¿ ~~…í@íaqP_Ñ ùùù©©©—/_.,,ÌÏÏ7º‰îÝ»wéÒeРA)))íûTI¹í·×e¹°8`B™°IO¨n’Ù †Rhü•¯p~Ê–‡à8©T@ð«Ó‚^šØ¼˜f7eµLRq꘩U¹­D‹ã®Aüõ×_¥¥¥S§Ne¶q móãàéà"eÅüç{yd¹’A€øœú挈+öûÅ´£:D;BX H•Ï€Åb}üñÇ–ö¢50À´w˜'”*¤"¹P$‹äB±B$’‰„r¡X!Ê›¿ÝLw¤÷êÓSI*• P€2ôåN~+0‘o}Ö~ãàí y9·Ö&û‘æØtSK+ßM¹U¦¸qãFYYÙ‡~hÚølýÈ’!lã…´NYãê#¢ü±€#ܦ+ÚM„õ·#„•€Tak`€91œ˜N>º>.Ž_ oõ]`u2ÚÃúœ3ÀTª¬Ú$µLJstjÌY³›r—Y  îffÁžïäu¼Àѯ†N{ÃÔŽ=’$qoE›ƒƒƒ“’Œ°w¡IqH–yŒb‹àUå8ú/Oå+¾$êR"¬¤Ê»ÃŸéFϬ¤=lÀêdP¡lº‘!I¥°¡ø÷=NÁL7hÌY³›²¬¦ª.žêûÙ·’Òâ[k“­A• UŽŒŒœ5k–õ_+Y ¾JâAoŒ‹ŽWKG ”‰M—E!©2Â^àç—üõqð«þL7È|<òº¨ØtF3–Ìšƒ£kDd¯÷×Q![æ±pF§3Ý<‰æXF£ÑpÇq¼ù&Iåp¹\•®(oñññ‰‰‰Ú šÛÇù)#¼}I’$är:›Ýuö"Ï~©üß%3¨¤JEst zib@Â+m2¡b1¶Vœ\â?²›ƒ/•ƒWK™G œi,±Ú|»• Ï©2ÂÆ¡Ä¸àDÿa9ø3Ý´Ï’&ì+øv/õ]ù‰E‚È^µ$èÅ £^.ù}OóK0jù™‰·hÚ´© Q±V®lº*ÇññãÇ2ÄXþ øö7’¬8{âÁ_Åm?¨»@ÝÍÌ»›>n«*€œPn­8¹yȼLDå`<éò€1_—ÿkë„QAªŒ°MšˆqK¨»¹B–ÙœÐsVKÄ@Èåtg6 ëí±5é ³X¬Ù³g÷ìÙÓø–0ŒÓ½‡J¤{yI ~mÝ­,ÞýÛW½‚P)^e+ÂK…9éþNÀhi­ÀÑ­îEXH•6…žb¬AÝÍíÙ…Œ ÓÍ£I0çßüBí¦üÜŸ›Ù=ÑVeWW×ùóçß IÊxUÅwyÇéQ®Yfí×ëÝ5í·BÇãB™Ç‹pîaN›¹1ñ—Ž^H˜–©2ÂF¸ùÃßw~=#*¯ÕÿÒÃôpxv¹ö¢{±†5æ¬ÙMYs‰ƒ·Ÿõ¬•ÒÝ ˜?¾››ñ_ežˆn¿ao¾Û¼@üÓ„R!~TT°g[þÏ[ ZÕMÇcC™ã;åüü²´^þu…“·¹ßÒˆ& 8Ø¡ÏüG~½ jn‚³ŸŽM÷t¢îæjR—lª¯Ü£G¥K—šB’ þÀéø§{.ÿ¤>/GV­{[œÁtéÞíõ·«Î§jŽ+ƆŸ,žãT¤ÍHW›xB>ñ,*#l óë×mЪi³.~ùêÁô‘gó_wPh4ÚàÁƒ“’’L4Ê{àÐÀѯÞùßj•D¬»IŠŠ28Æx¢aŠ—BoKJ5õ…•iÓ7ˆ+ù­\„@˜¤Ê›CKžc—½ÚÒNÀ¦¾¶%†þÚk¯¾JB¦¼îèãïÿ6ÀÓ!ú3–L¿ºhê¥y¯”üùkØ[ÉÆ1FÃ~¨<“#~žº¡¸êèô ¢Š:ãÔ@´ô]a³<<žyýÛ´–ö_AÃ×úcêzµ¿ c8þÜÊ MòM÷‰]E?V=¶àë¢ôl*Gð¨:mú†—Mq ô4‘Q¢P_a›<<–q&ùBÝ‘ªy _#(T$1jË¢.cb49nMÚŒ ÂRž½BØ-H•6HIÆixÌÒ§‚N ák„686ò›…]_ŠÕäKyG§opk,èÂ>AªŒ°5šKò _¾½$Q{ò—Ù†¯ üÛŸ`[CÀiøˆÍ º É•צMßÐPRmA¯vRe„M¡S’»ÖuÌ“žáÃ×Õ—Îd%Ï»ºxÚ•“3ß™]uá¤Îb„B^wKßàa¤Z-­(YM¥fý.Âlà4|Ä—ovåÉGtQE]Úô EºWj!¦©2ÂvhQ’ ËãñÉ E½áÃ×÷þoCÄ¢”ÿ·/nûÁ>Ÿ~ãÒ-ÂÀ áñFËÀòô‰ûþá"Ú FÃ_ؘ>a°&G\ÅO›‘Z_XaA¯všƒ°Z—dðëÛÕÙÏ]\ÉÏ1Û ©nÜF‰éêÎtm/ûçHåÙÀòò‰XüÔØu“St'giEÙƒ¾”ÕTbtzèÔ¤êÿNÁã–s>{Ÿšx,*~øàû¯¥‚á _”@f,™ñ܇_XÕ̶FÇmxÃñ{¿_¤rÄÕõi3R_þ5Ž«¿e}Cب¯Œxr¹|íÚµcÆŒ ÃL@XXؘ1cÖ®]+—·{†gJ2h±²ucÄ¢”;WÝ\³¼ôØïòÚÆ9A‚¹Ü´ý}>ý::õ{º“sÙßhÊë<•ûõZ>ýlÝÛón¯ØA]ç,€è?8ú4^F’y[?~uj̦}<ܹ…ʦö`ŽZ¹¡ô8êR Çâ?½Ç䡚IMCÚŒ üü²v×Ù!ÚÂ@}eDk¤§§'%%q¹Ügm/ùùùùùùÿþûïŽ;vìØ‘ÐÖô’dèòRì¿?¬P!ª¢Ï^ý‡ðs®ó²þ+ùcOÈ”×ÇŒ¯¿sü¸$¥%j©Ä7¾ñç4?¥Ô‹ŠöY³™Út£éhŒJAƒ¤´Ä³ïðì7°ø÷ÝT¾yö`¶g0‹_?£á¹ûÎQ9Rž mFêË¿¬ðÒy‰J*ç^¼šÝüT‡hG+©2¢EN:5fÌ’$;Ñé)nnƒ‚èÆ¿aJUªË2Yj}ý#.w̘1ééé#GŽÔÿrý%üúv=Õp×NS¶˜,ϘAž1ƒ|ãGßÙ°2pÌxŒNwðñ™4‡*@c9ªFÕl~Š:h)ÈIë˜gf{Æ®áøÝ½g¨ i0mfêË¿¬ðŒn^¼ä\΃?/5WeM;b9õZÂñéÏt2þH¸BR!¨Î,½û-·]ía= l„nÁ¼yóH’œãâ’4™Í6…$@>™ÍÎ šãâB’ä¼yóž×¶I’0ìŠ ßpŸ æÊ9M¬fEéî žÑq¢â‡*±ÈÑ/ÐÑ/æè¤)ßüƒãÆí^zì$I*‘§3àé–W§ Îu73 6ûª[Ï>Fq¡/öü𙑳ŸÈ›Œ/úkæF^î£æe ÿ¹Æý﮼á©ÞšväÓuJŸ—þõ yÅ’ L'¯Wú¼ô¯O×)mmG«©2B7›7oær¹ýX¬TOO3Ü%8@ª§g?‹ËånÞ¼YŸKÚ,ÉОž©.ª/Ÿ½¾âÍ«‹¦f,™^~ò/jsF§ÀNK>¸ÿÝÆ¬ås¯¯x“û×AMy§z.[Å¿}yþ„Ì¥³êr®1Ý<¨–Iµºñ2 ëñöÊ’?÷^{/©öú•îo,5’û½Á°!«§GÍ}2 ,«ý5kcÍbíR*™âÑÙ[„RU|ê†v>ÕŽØQ!ýVfú–„á!ýV³=¢ôoGk`#tsåÊXêêJ3—EÀRW×¹ÕÕ”éÖiŸ$‘^ÉŸêÌ÷Šì3X;Gùù)Gÿ ¾ë¶hç4ßh™Ò-zÃvZÕ̶ † Z5 £ã·vüCeÈÄÇfÿoì®dŸ¨.TNéw•9<<–>qˆæRêföHÂ03µ$ £ùG$å_^ªO;BX!¨¯ŒÐMEEôf2Íi”2G™n‹K2‰û`JŸ7_Ò$åɱ9›ªnPÉ‚±bÊ.çÊø"M1êff{DšÑÓFsÏlGë©2B7999`¢oÉ-A™£L·’dk¦[·n çY]”JÊ¥€€€g–l…+&õ[8N“T¥Çç~Y™ýPª½Eej¢ðŸkš2ÔÍl¢oÉ-A™k½!¬¤ÊˆŽ’d+‡N§@åùtK;ÒÊ%7wC7gìŸ<1zq¢&©I¿þåí]§ä‰&óáñ ­ ì¤Êˆƒ‰$Ùj»w¦À(]ÆV1b†a%üRqꘕüIå¼êŠSÇ*þ>Ò?qùÀY[ 0ôûnìòñ1Ë^Õ$•bYÆ—¿k¨Èz ©i0Ð Ân¡ƒ®­gÇŽ{ìØ1ÓYÕ¶ˆa˜««ëóÏ?¿}ûvS<,ø|þçŸ~øðáââb:Þ¹s瘘˜;w²X,£ÛB˜Óõ’5Ý»Îg^›•Cu9މêïÖ­[bbbZZ/ÅJèÒwÌk)‡™Ž.$@ ä‹—XaÌÛ¯à4ZæW±Û•Zû,©& ÿ¹9 í/bVfΜ¹wïÞæùëÖ­[µj•>5X‰05~5<~üx—.]48;;݉&PI’‹Å÷ïß_·nÝ‚ ÒÒÒŒk¥®®...ÎÝÝ=55µ{÷î ׯ_?qâ„J¥²U~tþv§øç,í…A˜tàzĈ÷ïß/=ºŸéêæÑ§?ËËÇ(ÕZr^uÝÍÌ’?~Á0lÄ ưaÃzôèqâĉÒÒÒÚÚZÓÒ//¯ðÞƒ˜Ž.T²† ö€J–²ß¢q²zaÎNÝcõg Uní~^mܸ‘Rß±cÇæååQù^^^úWb „‘$‰aX^^^D„6½Ñ“æOŸ>˜˜(‹[¹ª¼ýöÛYYYçÏŸ· nÎÍO<:—³ô•€mø/¦^kBBLåV xÃÓ¯Œ+ÉÔïÒ^Ê©VÏ+íûdÏ„­ Ç fiGÌ ´{êX4.(pǪ‚ñûÔñòåˡ֊* þÎzx<£îA‹a±1›yáKg?wê~09¯ýÞ·‹Œƒ= ½‘ã,KûžWÚÜ»w¯GíøíV"LÏø®Œaؾ}ûwíÚb±xîܹÎÎÎ~ø!Ašb'OžŒŒŒtrrÚ´iSEEEtt4ƒÁ˜ptíî4 ÙJORŸ_vŠ_vÊ·Û4š¨²ÑŸW­‹—6Ö LmˆÜ„ãO}„¦¦‰éyZz ^1¶mÛæãód*¬··wKù­˜ð÷÷www?þüĉÛí§Í ýú©ÁXÚü«PI..Í%¹}˜H’3ïó_}[“|è5ûÑÑñÇ …jw0P€lÏŠœN Ü+hp¯ç×̪¸ž_x"«(=[\Åo^òá±¶…)¹ñyÕÃ},ç nÿÇö|j0¹˜[_qÁ:ÊÆ}^é/^Ö Lmx†999åææöíÛrrr¨Ñã 555M¾F·”ß 8ŽOž<ù“O>IHHpqy2¹ƒúÎßäÿÉæiþú©Ápm¾,“ÀKNNÏ,©'F—d¡TõË©G×Ô7—dÀ1ÔW¶ X ñÄ*4b\Mtrpv—‰uª>`4< x@ÿðÁ«gTÝ,(üçZѿׄeOƒéÜð±%Äü¼ª‡¿ÑèÎ=†íb96õÜ9Ø·ÛŒöùÙ1îóÊpñ2§0µA• Æœ9s’““·oß.Ö­[·xñbý/דððð©S§.[¶ Çñ!C†H$’ÌÌÌ &´”ßúÒêuëÖ 0 66699922R&“eeeíÚµëòåËÚ³Ûôd{·× øeÖŽ!Ú\¢R@7†‘_ä%É×óë9õH i±CŒF°í_¼„¯ö¡¦¨Þwô[WþÜ``Žùõëæ×¯Û §Tß.¦ä¹¡¤m¡ÍjŠ€o÷™Í%¹ÝØð#«MÏ+ÃÅËœÂÔ¶ñÆM›6-\¸°oß¾L&sÁ‚K—šd·×]»v­Y³fÅŠeeeîîîÑÑÑãÇo%¿¼½½322Ö­[·~ýz.—Ë`0"##ßxã jdÑͽަ«¤$ ÎF~0Š$‹¤ª½g¸÷žÑ¢!U¶h ôÅ•A“ÂNÈ»¤£CÖN0Ì'*Ô'*tàŠIµ÷¸…'®Á»»ô¼TP“(öHÐ_› /³ Ö—™[ ~ñlBÀ€ˆW~ûôŽ"\R"#ÉÂN\ f*ŠÈ÷aó —ä {N>j+ŸYÒãuÆs ±…è@€ÝWÇ(À‘J–Þ»œþãÙÒ?ŠHÖ} µ,f|a„>Eä»®s ¯Êú1ÑjOKaÖ}úÖÏ“ûû·ô¿ªþ@©ÌS*û)`Ë+ûWúöíÚîË%2õÞ³Ü+¹úΰE#Øv¤?^TBô¤’Aƒî "CL\Oµ ht£MΰlL)*·¶´ qóÇ:gOPrppx T‹¥Ê†H²BEì;WÊ*C|dJB¦PË„LÑšî¢9Øö†+Æcc "Ò•J8_Ö³³ nÀ¢ÃÁi„Z¦VIŒÒW¦èÐ,Ó=¯¬¤Êö‚J*¿µã§ ¿¿§³Ù¿…{„Â)ÎÎ},ß”IÇßÓ¹y~æ}þöcE:/A}e;Ä+È'ûQÇe<é…۵â,Ø€å(H¸xõ³ V‚IŸWVŽ}­²gîüz¦Éâ?‘¸7%qoŠ·x ‹5•ÍVäkUU¿‹Å*­É $@¶\¾ŒÇ«U[RùÔyär…&‰=É‹†VFÙŽ˜È«Ò$\*—¶: bj(1®ãž° ÖƒIŸWVê+ÛÍ_<þ¾ù¥§'pP$ZXSóÖ›ÉtÁq!AÜQ(jÔj `µECŸž¹YSY'£ŽI‚¤”‘Ý5gq4‚m—øáE5Ré‰êØÕÊIC¶*©­x‡N¬.w~=ãÞ-`Ô–…vx@eìì­'[÷ÌHÿõ£Æ˜ˆ¹%Â/Ï'þùû¯Ú¼á.Â6¸’[÷ã‰bêøÚ}þþÞÝ-eÇ™]¤út™T]ô‡ˆ—-¨Î$ %îìÀ õï:žÁ²Ùý¿5Øùó *ÛaA}æ¿hi/,Æóej¢qö™·+kT¿'Aä{vvÖÛûì­¦ÅF×g`“ÙÕÅU ö+[5#Ü‚k¤\¼c\¼c,gßÂØùó Ðl{ Süs–vÁbä–o6h’“†ÒiO=o'Çz¹2˜¨!Ø/S‡i’E•⌼6ìðˆ0.öü¼¢@#„ÍBäþó¥šdX ;&¬é–$,þƘ'ê+Û5Mîß/–+TD+åÓTa³\¼][Z#¥Ž›ô‡´ b»:Û˶µˆ–ÐG©*þ½Ö¶ŸcTa›Hê×Ê5ɸ!¾(Â0¢E¼]Y#µæüY©Ï¾&„ÑAªŒÐMTT”ªÌ^ƒ2G™6cW+5*³øÄç-ÑQxy€Ÿ‹cãX¹’øã¿òÖËëÃðáÃ@!©xfI#B™3J;B˜¤ÊÝøûûÀ-…œF)s”iCà5(NݨÑ$_Œõug£1jÄ3pdÑ^ôäÞ»t·öQµÔÀ:™L&ˆêîXO› ÌÞŽ©2B7qqq°¥¡Ál¡Õ[4¦ áÐÅ2åãÙ:î.Œ1±¾†:‡°⣼<Ãà$К-Ø>¨›¹âÞ’4SK"IuŽ`Œv„°H•ºY¾|yppp¶\žR[k†Ù¨@Jmm¶\¼|¹AŒ–‰®Ýçk’¯ dÒÑ}ŽÐ ǦÄ?™˜÷Hx£ ¡•òÏ„jG¢ºœâìu@š¾%‘Dqö:Q]Žáía)ÐÓ ¡‡³sçN Ãv …±¥¥E"}c.U©ŠD±¥¥»…B ÃvîÜÉá´ÿy`ß¹RÍ–U¡~N{Ø~Ü`„y.”òäÙ“G<ãiôCµƒ׎„¶fÍKû€°^ºvíºhÑ"ƒÁb±p¯«3~Ì£îÝ»ÇÆÆÎž=ûÀááá†T¥P[Èã„1aîcbÐeD›á8ÑëÅJ*'UJâ£< ùÒ±Ú² ¾2ÂvH»Rqärãð †}þz/Kíʇèè$ªwޕʧhêç3­…(4„qAß•6_¤<‘U¥IŽêçƒ$Ñn8Nôqü4É37kªør úƒ°*#l„?ÿ+—+Ç®9NôqýZ/@´Žö‹š _%…@èRe„-PR%¹œ[«IŽàˆ6gD†Mú$$ÜÍ‚†¼GB úƒ°*#l}gK5$‚¼ŸÎö7‡G˜è0÷nZsøœ/%ÐD„‰AªŒèð\{Pÿ L¤IN„cÜ´a;`Ó†jn¦GÕÒKwÑÖËÓ‚TѱQ©ÉCÊ4ÉÞ]\{uv± ?#ÔÏY;öô UFtlNeW×44NŽ¥áØäx´7ÂÈL|>@³X¹A¬<žQiY¶ ReDF Qý¥õˆÞÛËßÃÁ‚þ læè˜'±½Ò¯W× Íº—®@ªŒèÀ¹\®‰óàì@OŒC[×!LÂKýý\7U¨ˆ?.aëeB'H••2žôBΓÕP‰q~ìÇ[Ö#Æ…ÅÀ' Ð$3îÕVˆ-è†AªŒè¨ì?W¦Y¦âëÎz¡·eýAØ6ƒ{yvòq¢ŽI€ýZ[“!F©2¢C’S$¸["Ð$§ÄÑðÿoïÎã¢*÷?€Ï0 0ìûŽ ¢ˆ"^S£P3à sÉ$½je¿ÔÜ®–¤7Ókja–f›šÕõšš•Z)𹿂†; %Ûˆ û2Ã03ç÷ÇÑqB–˜å€Ÿ÷Ë?fÎcXüœƒ¦>|xÆŒ‰ÄuùûûoݺuذaMÈT­Ýý§æéÌQAýBMÐ0€‡]¾U±ñÇ[š§ ÆurÐ.{·vÕŽ››æ÷æ®ÙS«ÕüñÒ¥Kkkk‰Hdã¥e>mÿ/¾øâ™gž1ÆÊÁ04é×_eY6@(Lprhmí'4|‡¹­Tž‘ËËËó$’ØØØÃ‡:ôáb,Kßj] ÕÕÇöˆd0ŸÞ]ÃìÓ󪸧»Žßï&¸ѼRÅn=˜«R³r…Š;½|ùòU«V‘w苎^Ñöî}‘Û£¨-¬¼›rûÆ'‰døðáM}€ÿ°WYYùÒK/±,;ÍÞþ‚ŸßD;;cD2ù …íì.øùM³·gYö¥—^ª¬¬|¸Øé%ywï½cˆâûaÒ0¯IZwò.,•¿*Õ¼´ïL!w°Y®PÑüñÞ{ï1!ÑŸôZìè9а‘LD"±·[à˜Þ#’=º<Ï}*** [˜R·~ýz‰DÒÇÊ*ÑÕÕ½D@”èêÚÇÊJ"‘¬_¿¾Á«r…êûÓÎt},Ì%ÈËÖøhŽ¿»Íã=ÜzùÇ3…µu*"Ê*¬9x¡ˆ[(W¨ˆhñâÅJ¥Ò+dš³Ï㶉öYfç!‘H6lØ`ܺÀ8Êи³gÏÑ ß `ã¢}¬E÷¾"Õ2ås… ¥zÛ¡\Í íòzµJ¥JII!"ß I cáö 5ö=‚v© +,,$¢^"ïgkWWµFI¥âÈw5OŸéëáboÒV4ÅÑÖrD?OÍÓ£—Šw•h&ž#"¹BŸŸ/“ɬÄ>B‘“iZeë܃úA{T†Æ]½z•ˆŒt,¹)\u\Õ{Nå+îÏ6ìdg9¢Ÿ—)›мaQ®÷&*Uì©ë%گʪœœ•J%´v5Y“Dbozè{íRxíVAÍ…Œwæíce‰N æWW¯®¨©/*«+,• wiªw\™ˆV¦j´o¸2 ø«Á]l;yˆv7Ý@•µÊÏögIŠe²ûYÛ"¹BÉç@/"zxš˜Q£FµVíº³³s\\\Aá§“ÕÔbaaÑ©S§W_}Õ4b€AœÏ(½UX£y:i°ƒË¡À|ÄÂEº>áª{?¬«Ç­MdÊ”)ÎzÆ]&® žÓ½måŸþ¹sçΚ¥¶¶F¿ì„«‘eÙššš›7o¾óÎ;3gÎÜ¿¿1* ¬®®NKKÛ°aCTTÔùó烂‚ ^oå—È}]­ÍÝ ½)”ê½'|¢‚BýìÌØ"² žñ‹êê´-9·¨¬å¹-e z­^Z=^­]»ö­·Þ"¢¬¬¬‘#G¦§§sËÝÜÜt_ ‚‰aY–a˜ôôônݺ¼â¦<\ãÑ£GãââjjjšyWÛ+ª­­ŽŽ ùöÛo [ŸºPt5»rÌïP=Ɔaˆ¨80ÐXÍj‚{N±,{àÜîßGhÁ¬šÞÝà Gæ€/Jõž“ù¿].n~Îâ§"Ýý…Ù111öî}»þÆT­£ó»Ãˆ¨=N¨ÜºñJ[FFFXXX+þvžS 'Î0 ³sçN__ߤ¤$"ª©©™>}º­­­‹‹Ë’%KÔjµ¦Ø‘#GÂÃÃÅbñºuë £¢¢,--'Nœ¨TêtóQ•êÞ¡š»wïÆÇÇ;88ˆÅâñãÇK¥Òæ—7hd3ÄbñòåË÷ï߯c«:†Á½Ý Jd‰»3×îþó¦¤ÚHµ¸çähÿóËÍí—Ÿ?³¸øW™¬CEMý/)f éH^ “‡ø/~.Äͱ¹ëô¸¹½@wF¯š ¯æ™%˜îíÁ...vrzp-—׃‹OV¬X±zõꘘ"Z´hQvvvjjjuuõ /¼àéé¹`Á®XBBÂÒ¥Kïܹ³xñâ#GŽ,\¸°¨¨hÑ¢E3fÌhæ~Gމˆˆ "–eãâ✜œÒÒÒT*ÕsÏ=7kÖ¬={ö4µüáF6/::Z&“´X¸c°²ÄöõÜ}2?CR•!©êæoߖߡ͛foÏÕ³l™Z®Pì­©Ù[S3ÈÆf«»»£@s§÷ž.г·Žê«¡€BýíÞ™Ö}׉Û'®Hýõ)W¨H¬ß:¹Í\ …•ÈÆÓÖ%­Óh'ï'ˆ:ø¹F¯š ¯f˜%˜î¥ò“O>©]B{Û?!!aúôéD¤P(¾þúëS§N…††ѲeËÖ®]«ùÃ-Zô /(•ÊE‹M:uòäÉÜ㦕s¿ÔjµT*Ý·oßêÕ«wïÞMDçÏŸ?þü… üüüˆhÖ¬Y¯¾úªB¡HMMmt¹H$Ònd‹‰H.—·X²#ÜÛýÐÅ¢ÊZ%5›×¹>8Gš%:/—Ï–JËd/ݽ»ÇËK÷Xþýƃ‹>Ÿ}Ü[le²Æôce)˜:4 *ØùËäÜÒ*EƒW[½­ìÑåybY–U*ëÊk+þ,Éû©$ï'GÏÁ7XXÚ·¹Õ¼fðñªùðÒÆ‡`º—ÊÍW8p ÷@"‘Èd²ððpîixxxFF†¦XTT …›¢ùàèèØ·oß}ûöq·KKK#¢I“&qo¯ªªª¯¯—J¥M-÷ññÑnd‹JKK‰ÈÝÝ]Çòƒæç§f‰ ¶›¢þÖÖ?zyÅœ”ËÕÖŽëºÕ ùYèëjÓS“5Ì¢G'ûw¦…í<~ûôßg©«×õª‚¢Vh=c«ŠSo¥$TÉ<3/ìÉmÄtä«ö >^5^ÚøLz\¯,øûHî41ÝßÞ@S¿¸ŸŸ}ö™‡ÇƒÚ»»»7µ\ßzÿý÷Î;;;?r7Ôþù©a‚l _±·__Qñ]Mñü ?ÍÝñøÌÆÊâ¥g:õ vJ:’W^}oÚvWfìÝ£Â%]K~¶²è\YÁ1gß§ ±Zþ2ìx¥{xñ!˜ôHe???±Xœ––IDW¯^åöÖ?þñ"*..np4º©åz‘Éd«V­Òq—BóðÏO cgóp±x}EÅ庖/#i gCx CËåx#¢³ãªiÝwü&9›^JZs{µ•­ŸWð?óÓ7IstøT6ìxÕöð2e0é‘Ê–––Ó¦M[´hѦM›*++ßyç×^{­ÕíhJhhè¤I“æÏŸ/¢££kkkSRRÆ×Ôò/­ÎÊÊ""™LvíÚµ?üP$½þúë­kÛK¤¶îí‚ñ²9ØÒ’ˆŠTú Oó|ŒŸ›`bk‹WFö qúêHžÜ ³ˆ8ûÉOßTSzMÇòxÈÒk¼j{x™2˜ô›qsݺu³fÍŠŒŒ‰D3gΜ7ož^o×QRRÒŠ+/^œŸŸïìì5vìØf–7oäÈ‘D$:wîŸ`cccŒfw š¾nÀuÚD¤ÔóòÁAn>ípòNdW§`_»Çn•jÖ‰H!/6Ô Û;ݳ¹íáe²`bÚãeææÒx6ÐÍß>áùÒgnöFËW¨Õ]óò\,,núû븞Õÿ˘÷l;ÌÓíÞÉ“'õšE„»2걉é¿Ä²ª”=áÄ{î†.+yqÝú··ý1ê™1¦‡QþFÓ¿ž7Ø:ÿ¬¯§ûû±u´4Þð§,´wje- EŽæn_t°<æ •õ°}Qs7¡M](jôì Žñú÷áÚZ"dÝÑm"«Ì""ûÎ-–ä´ë!Ë\ã•Ù!•uõêC‹}ɨý;_©ÜVU%b˜ì:à÷À”Ê Ž‘£—®WÁ¶_æ¯ø©ü¨8v¹¸ÁÅdüþ}¡®nvqq¥ZýŽ‹‹O³³Ê@óµwîüµC ¹3w[ŒÎ,ãO` |$<üÃÓHýûõ’"b‰ªÕêë Ef}½Ñ¿_uÀeÇ­W%½”•ò¦ª¾ªSï7E6|Zx“Wü„T~$hÿð4jÿþªªŠ{`Å0Bá ‡ííCô9Ï ˆ(ûDD,«RÖÔ–gÈ*o1Œ…Ïy…L5sËŒÏdã?!•;>ÍO£öoÓ߉ »{k÷@`aeeëçÙu²g×x‡.æm• ˜f¼â3¤rÇwìr±«Í¬Qbÿhw½RùÑñ ©ÜñùºÙÄþÃÓÜ­hYÏÎŽøxÕ‘oœžA8Ó ÚßG~ž]¤2_`6€y{{Û¹öVÕW›¬F¥¢B(r;æ“Õ„T0"ÿºÊJ¥Z­’ ,L±{¶¦ì†RQYPP`‚ºÀà°7xð`"º­l8½ŽQqÕEDD˜²R£²¶¶îÑ£˪¤¹LS£4çG"ŠŠŠ2Mu`XHehœH$"¢+ …)+åªóöö6e¥Æ–@Dy—ß­«¹mìºÊ OIsˆÅâ9sæ».0¤24nÀ€D´±¢BeªUD+*4Ut“&M7nœJ)»–YXX$&&.Z´ÈP+C*C“~ýõ×aƱ, &89 ´¶ö3Â}Ÿn+•gäòÄòò<¥’a˜Ã‡:ÔàµðÁ·ß~»yóæ'Nغôª.¹lÀ5ÛÙ;Èjkž~úé7b+¹]C*Cs>þ¸X*5^\ºtèðásçö‰Œ4^]ÀFíW×Ò ²;iééûxqêÔ¸Q£†1FEÆ€T†&]ºrå­+X–  œœZ[û ßan+•gäòÄòò<©ô­+V¯\Ù«—ÁkþÐô++[?¿s<ú‰ÄÞ\¿Z­¨*¾XqçtáÍ/7}ñEEEÅÔ)S ¸~£Âqeh\mmíú>bYvš½ý?¿‰vvƈd"ò 'ÚÙ]ðó›foϲìú>ª­­5FEÀš~åÑåùÞ#’ÝÇ6’‰H 9z èµ8$úS"f÷Þ½ݺeØ*Œ© ûaÿþb©´•U¢«« z‰€(ÑÕµ•U±TúÃþýỮëWv.}–cÜžåì3Ä+dšJ¥Úúå—F­À€Êиôôt"šçèhaª-ˆæ9:jªn…’ÒÒ%Ë–QII ÷ u†ÇÅ ‹Ó~`(_a»Ã}¸ÞÝf0Œ)z–o÷W‰(33S­V·XØPýG_èo  Ç•¡q¥eeDÔK$2e¥\u\Õ­°eÛ¶ðîݹ={ôÐ,禃FØofÈs°·ßµc‡ñªn§¸×Î%Ü4Õ ENV¶¾u²Â’’ww÷æ 7Õ8YÙÙ~ùåêÕ«wïÞ%"^£GŽ 4NÛþö(@*Cã²srˆÈHÇ’›ÂUÇUÝ —._މŽ&¢KW® 4¨ÕÍxgùò5‰‰DôŸ·ß~wíÚˈ}x¡µµ5 -ìŽR(eååž­jiûÃ}¸?–Ü ¡•K]M~ÑÝ»-¦rSý‡eÙÿþï;wïfY¶k—.111D”““s09ùÐáÃ/Lš4yÒ$½Nón𡣿6¤2tUUUÿݹsà€UUUßìØÑ¿_¿Ö­§èîÝ.]ºQqqq×.]Z,?wöì¦^úùÇ›ï˜ 7Æ$°°Ò±dSýgמ=ÿÛµËÛËkÉâÅÁ]»jÊßÌÌ|ïý÷wìÜ)²´œ8a‚îMj𡣿6W†E³•Ýê•üôË//NÊ=˜†‹j%÷ŸÂ;wþ»s§Í»«ViG2…†„¼»j•µõ7;vÜ)*ju¥èo  ÛÊÐq$®^ÝàAS4‡ßŽ8±cçÎÂ;w‚»vMxýuo//"zoÕ*GGG"zwÕ*'GǶ4©™ã|7oþë7´‹}³}»›››L.ß³w'ïYYYu ›ß-4´Á:¿ßµkí¤\¼Øâæè¨ÑþóË¡C*•*näÈF÷úzyzŽ1bÏ÷ßLNæ’µÑO\³°Ñý ´a[:Žˆž=#zöÔ~мCÉÉïø¡“““‹‹ËÍÌÌM[¶pËïŒm"›çæê:9>ž{<9>~r|¼X,–Éd¯¿ùæÎ]»:½<}ú¨áÃ322ÞX²$=#£ÁÛ·lß~ùêU]vx‚Ží?©—/Ñ€þý›z÷ҥ˗u©¢Ñý ´a[]_~óÍÚ5kÂ{ôÈÍË›9gεë×[·žWfÍj°ÄÖÖvúuÍ¿ËÍÍmJ|üŽ;‰hÊýár{RRVVÖ„qã^ž>[Ò'2rɲe_~ýõÚ5k´ßžzéÒç7zyyµ®Í #nŽn?¿¦ Q¾nSy7ú¡ë ý­cC*C[ݬ¯RP `Ù-îîcmm¼šY_?´  @(<âãcóéˆÿïå—Ã{ô "___"’Éå­[ÏíüüKZuS–e=JD£FŒÐ,ì!‹¯ß¸!—˹ól9ófÏÆiuuuDdccÓTkk"’Éd&kú[džT†¶ µ´\æì¼¬´tqIÉkk/‹³CÔ±ì+ÅÅj¢/ÜÝùÉD4äþÕ/B‹6Íha¨3ZËËËË+*ˆh{Riýw©T*–eKJJ¸_œ¨>} R)?É*o]?tSþ-èoü‡TCr·°˜ãà°²¬Œˆ›ð¬ÔökÖÿý_UUÕÅÔTy]ݘѣ†™7{vTïÞ?>Özžçìž“C˜=ßø¸Ï·u_ÿ¶÷«Ç&êw íÂŒmyW×QøÐݶ.-ÏÚ¦-íØ?«Š/¾ÿî»áÝœ ®-ý 88æÃÍ‘J‹Tªmîî¾Baf}ýªÖÞ)@£¾®´0ó+îñ­”%jU+'{hÊ`0[*+•Éæ::ÆÙÚ~âæÆm®¬<ÕÚ ³ˆˆˆÍJYR//°^$ö’UÞ’\[oî&R ãªBñŸ²²H+«7œˆ(ÚÚz–ƒÍ•J+Õjs·Ú«;™ß”žôîö²‹l—~ï1w2¿®¼{ÎÜí0¤2@ZýJq±ˆa¶¸»‹îH^êì&å+•KJKÍÛ9x<æ:ˆn¥,QÕW™¹qÆTH(-ͪ¯ßÅ%Pøà¬~+†ùÜÍÍ’avWWÿT[kÆæA{¤RÖþuv¡@ êÚ#¸7û£_ø|Ç`EíœÔUæm€‘ •¡­¾«©ÙU]ý¼Ýs]JÑC$ZâäDD‹¤Ò»˜”ô‘“ºR^µÜÚ.@³P`aÕõ±µŒ@(ÍÝ_zû°›`$Heh« ¶¶ÅŸ41áÀ\GÇâÀÀ›m»/˲K/æÿÐÜ¥KZzº4çGÓ¤²4÷˪‚D"‘^oD¿j_ýª#A*Cã,…B"º¢P˜2•¯(Dä¢ÏÎÆÚÚZ"²¶¶6R“æÎž­ý”eÙï~øa{RÒw?ü`ÊÑ“ˆž‹;{þüµë×7lܸrùræþ̦[¿ü2;'gάY nôËOq£F:rDš{À5`´“wÃ3꫹wù]"š8a‚¾ïE¿j_ýª#Áqeh\XXm¬¨0ÙŒ\*¢šªõÂèyçVcfÔˆD”——gšµ«^´`ÍÅÔÔƒÉÉܳçÏøùçÇ à¶½øÏÇÇçÅ©S‰èæé™¹—•uƹ×'«–渖`ÀÃûfu„~Õ^úUG‚mehÜØ¸¸äÇS¥Ò„’’µ®®Æþù¦&J()I­«swsûз¦hÑ ‹³‹¿ûö["’Éå;vî¾[h¨îtl’§‡ÇÌW^Y¿qãÛ·Göîm)®ß¸ÑÃÝ}Áܹ&˶3z´J¥Ú–”t'3éNf’•­¯¥µ›f¦ë¶DEg‰X"ŠèÙsÁܹú®ýª=ö«© ‹Åÿš?ÿßo¿ýUUÕ1™,ÁÉi µµ1öfßV*ÏÈå‰ååyJ%Ã0ÿš?_,ëøÞÉññ;vîäˆ,-‰H©Tþûí·Ó32z†‡މɏyó»ï¿OKKK|÷]áß§üܲ}ûå«W»véb¡çT çRRˆÈßߟ{*“É^_²$+++zàÀ‘Ç———ÿrèÐK–¬]³&¬[7] èÕ¤§Ÿzê̹sçSRÖ­_/jjjV¼õ–ÝC3óܸgŸí߯ßg[¶\º|Ù‚-¯.É7àÊí\{3 õ ï9"6¶u[ÉèWí´_u HehRd¯^«V¬ØðñÇyRékR£O8ìîæ¶`îÜÈ^½tË”û£ç”øxnÉÁääôŒŒ'|ÉâŠð,»fíÚÓ¿ÿž|øðÈáõߛzéÒç7zyyé^B¡8uúôg[¶ÑÓC†p wîÚ•••5aܸ—§Oç–ô‰Œ\²lÙ—_½vÍ] èÕ$†aæÏ™3sΜ´ôt"š:yrwýwøóϪ+X–Í“Hªª y[F;;»NmÙÈC¿j¿ýª@*CsúDFnÛ¼yÏÞ½iéé…EE¯ÂÇÇÇÛÓ³{XØsãÇ[Z¶u7æñ“'‰èÙ¸8nPfæÙÑ£Oÿþûñ“'ŒžófÏÖeè|eÖ,îA}}}II‰R¥"¢ýû9’ˆX–=rô(q9½""Äbñõ7är¹••Uó´wêØ$g'§ ãÆmOJ"¢¨>}Z,Ïg Ãt h¹œ¹¡_É •¡–––/LšdîVè*;'‡ˆ´žq³³³”Ôqܹoç*Ã0NŽŽ]»v:xðÑÑÜè\^^^^QADÛ“’HkãL¥R±,[RR"‹›/àëë«o“***~Ü·{¼nÆOÖ¯×÷²Ðú˜ R:™LFD666š%ÜFC­Lֺܿ¿™WëêêˆH ”•—k/ &"¡¥e‹ôm˲|ôQiYÙÒ„„/¶m“H$_~ýõ«3fè»Ð ú˜ R:™L&—Ë5(wá©Xk<5 "bYvåÛo7zm+W{3ôµïÀ />7nÜ?îàà°ä­·~Ü¿¿¿~½""Ú¾rh ú˜ ®W†…›,Wë¢Ï¬œ" 2Fub±8(0eÙ‹©©­+ —¿nÝÚöå—!ÁÁS§L!¢^={Ž3†ˆ>ذ¡¦¶¶í뇦 _É •¡CCDûú‰eY"bY–;TÖêy$Z4vÌ"Ú¼ukþßO…SªT*•J—:’Éåï½ÿ¾¥¥å›o¼!¼‰ÚÔ)S;u*–J?ß¼¹4ý L{°¡C‰6ì·ãÇ8QQQܵëôôë7n„uë;l˜‘j:dHZFÆ¡ääYsçöëÛ×ÇÇG­RÝ.(¸~ãÆ¦?vssk±€Ž}ºiS~AÁ zkO+‰ÞX¸pþÂ…GëÿØcÑM1¹ô#ýÊ8%4© ŠP(\ýŸÿ|½cÇÉS§.]¹âêê:~ìØÉññB£ÍæÍ0̼ٳ£z÷þéàÁKW®ü~ö¬¯ÏSƒÛÚÙéR@ÇŽ?úÛoO 2ä¡I’;Mýç?·'%}üé§=œõ¼e!èý ýÊdn‡ tHÜUÍŸí &n.ÆÖ}ýѯ )méWÀÁqe¾@*ðR€/Ê|Tà ¤2_ •ø© ÀHe¾@*ðfÜìȸ™šÒ–7š‚Xi l+ðÅÿé #„)€IEND®B`‚quagga-1.2.4/doc/fig-normal-processing.txt000066400000000000000000000010251325323223500204740ustar00rootroot00000000000000 _______________________________ / _________ _________ \ From Peer A --->|(A)-|Best | | |-[A]|--->To Peer A From Peer B --->|(B)-|Path |-->|Local-RIB|-[B]|--->To Peer B From Peer C --->|(C)-|Selection| | |-[C]|--->To Peer C From Peer D --->|(D)-|_________| |_________|-[D]|--->To Peer D \_______________________________/ Key: (X) - 'In' Filter applied to Peer X's announcements [X] - 'Out' Filter applied to announcements to Peer X quagga-1.2.4/doc/fig-rs-processing.dia000066400000000000000000004672771325323223500175770ustar00rootroot00000000000000 #A4# #Best Path Selection# #Main Loc-RIB# #From Peer A# #From RS-Client B# #D# #C# #B# #A# #From RS-Client D# #From RS-Client C# #Best Path Selection# #Loc-RIB For C# #Best Path Selection# #Loc-RIB For D# #Best Path Selection# #Loc-RIB For B# #D# #C# #B# #B# #B# #C# #C# #C# #D# #B# #D# #D# #D# #B# #C# #To RS-Client B# #B# #C# #To RS-Client C# #A# #To Peer A# #D# #To RS-Client D# ## #“In†Filter for Peer X# #X# #X# #“Out†Filter for Peer X# ## #Export Policy of RS-Client X# #X# ## #Import Policy of RS-Client X# #X# quagga-1.2.4/doc/fig-rs-processing.png000066400000000000000000001643701325323223500176120ustar00rootroot00000000000000‰PNG  IHDRd}sS-ÌsBITÛáOà IDATxœìÝy\ÔÕÞðï̳à0ì ‹Ž]·$4A„q­®’öd÷f‘H†(ÖóÜ\’L1p¹ˆ^êѰLP«›¸Yv±EMÍ¥@qd–fæùãgÓÌ8³óy¿|Ý×ð›3çœßtOçüÎ9,…BA…Åb¢Zü]茅_`) ”;Ã_ %„E° ªI±ÊßßM¸••)_ãïa,“ ”;PFFüÕ "¶©;ðÆLŠª mÖÀœé9,fee±:9tè~[Ñ©B¡0((hÛ¶m2™Ìhxùå—Y,Ö’%KŒÖ"è‘Ñ‚)€ù³1D¥›6mòòòRþdˆViëÖ­>>>uuu»wïNHH(++[»v­ÚmnnÎËË#¢]»v¥§§ÛØäKî%0¼`ZÉ1ÑÑу ÒP@*•r¹\C4­*""‚éÆœ9sžxâ‰-[¶¼óÎ;G_õ«»‹ýû÷×××ÇÆÆmÛ¶mÀ€B¡0::º¼¼\ËÖÙlöèÑ£%Iuu5;wnúô鎎Ž|>?,,¬¸¸Xµ°†w»¼‹Îrssœœ>üðC>Ÿ¿sçN¿*3b°ØÐÐPû‰DÂ\¬­­MLL\±bÅÕ«W“““=koo¿wïÞmÛ¶]¾|9,,ìúõëÊJçÌ™·wï^±XüÜsÏ-[¶ìã?^³fMvvöùóççÍ›§}—JKKmllΞ=;f̘ÊÊÊœœœ}ûö¹»»GEEýðÃL1Íïv¾‹Î ݾ}ûرcqqqnnn3gÎüâ‹/îß¿ß/À d:88Xù:$$äôéÓD$•J³³³###™ëÏ?ÿ¼ŸŸ_AAóH_XX˜X,^·n]vv6S@"‘lÞ¼9::šˆBCC===wíÚuõêU>ŸOD ‰‰‰•••êºÑÔÔ$‘Hêëë?þøãcÇŽÍœ9“Ç㥦¦ºººÙÛÛѤI“‚‚‚ÒÒÒöïßODšßí|}ôÑGr¹œ ²/¾øâîÝ»÷îÝ»`Á‚|&c°˜››ëëë˼vppxÐ’MDD󺥥¥¤¤$55U¹øÃ××wìØ±'OžTVÂår£¢¢˜×nnnîîî‘‘‘LR$¢¡C‡Qyy¹†°8räHæ‹ÅŠ‹‹ËÊÊjmm=~üø¢E‹˜,HDl6{êÔ©999D¤ùÝÎwÑ¥;w8044”ˆ¢¢¢¼¼¼vî܉°h*r¢7oÞjowápÎûøØb¹ €Ž 5²Øy‹‹‹ ›ý`Ö»¶¶V.—{zzªðôô¼pá‚òGGGGey"âr¹ÎÎΪ?QKK‹†nìÚµË××W(0™µ²²²­­móæÍ[¶lQ“ÉdÌ®:÷ïß×ðnç»è¬¤¤äâŋ˖-«­­e®<óÌ3YYYW®\yì±Ç4t äDsó­öv"ª–É77OLÝ# cš]]˜ XQQ¡z±¢¢ÂÅÅE­Œ1¢Cf‰D'!!aáÂ…Ëk~W¹¹¹D´nݺuëÖ©^ß¹sgZZZ÷ê´2·ó†‘׬ ,©»$"êËáÜ‘É>ih@XЕiNpáñxÁÁÁyyyíííÌ•7n7ÎÐíFDDœ8q" `ÐÃùî#µ¶¶îÙ³'$$äøÃžxâ‰>úgÇ1˜˜x;o(“ ê¾\~¨©‰Eô¾›‡¨¨¹¹Âˆ³X“íýöÛoÇÄÄÄÄÄ$&&666®ZµJ ¤¦¦ºÝŒŒŒððððððÄÄÄ~ýúUWWŸ9s†ˆÒÓÓù®fÿþ÷¿«««322:<Ôøê«¯&$$œ8qbüøñ¹%‹eèQÆÏ$’V…"œÇ áñ"øüÂææ½I’Hd æ¬’ÉΆž8qbAAASSÓܹs.\8hРS§NùùùºÝÀÀÀ’’’¤¦¦ÆÆÆ.Y²äÊ•+Ê•4šßÕ,77W(Κ5«Ãõ9sæðù|f†:3Ü(ã' =×§ÍíÓ‡ˆvÿ±‘h‰…éQ0>ué°ó(#sÜ_7Np9ßÚyûv6ûb¿~|«U¡x¼¼¼F.ÿ·§g÷È»••þv˜ld 3=Ž2îjh ¢ŸÅ"";ë™>}è%/ %Œ,š†–wX:f”±{#‹­ ŰòòûrùW}ûÿq~73ÖhÏf_ðñ±W¿ÿ#‹ Œ,‚™êÉ(ãWMM÷åòþ¶¶Ê¤HDÛÙ ³³k”Ë?oj2B¬ƒÉVC³´¥^.ŸrçŽêõ*™Œˆv540ë]´dä½!Ì Â"X›[íí_77Ñ=™ì^W+þG*ý­­m€­­NÕ"2@ï„°hÚdÕ PëË(œÞýã–u>Íy·D"'Ëãå?|ž$c~UÕŸH$o99éZ3!2@ïƒgÁ4'E¯YºÆD{$"š­f¢y¶½=í•H´9ËE]7ð,#ôY3Òó»oZZ®·· X,uÇ@GòùÎN¥LVØÔ­ÅQÑÊó ;¿…QFè 0²ÆÖeðêÉh¢*挖©ööê6DZe±ž±·§?ÁhIC÷0ÊÖ û,š/k}f±C´Ò|kÝ>Á¥‡4쳨!ZÓ?&¦¡Ád,4Zabz„E0*«‰SˆŒÐK ,‚QYY„Bd«‡.=…å/`Åô‘¬Â"€>!2€•AXÐ?DF°‹†‚ÈVa̳-6³E¶…Bd‹†°` ˆŒ`¡:2Ü@&"#X„E0wFž‰V6d¸cÓÀ‚° ÷zH54à ‹eÌæŒö÷BC4Ä?t0YË`Ìÿª1f[e3‡‘Eó…‘ÅÞ£Œ`†0²`.0ÊfaÀ¼ 2€YAX0GˆŒ`&Ì"#˜Â"€¹ÓÜèm,ƒºÈˆ!F0(„EK‚ÈF†°`yÀh,"#Â"€eCdƒBX°ˆŒ` ‹Ö›2€Þ!,Xìã ú…°`…@_¬"#ôÂ"€•Cd€ž@Xè {lLݱX,CT«P( Q­Yaòb—ѹ¨.P@¯õ`d1++‹ÕÉ¡C‡ŒÜÕnØÙÙ‰Åâ·ÞzK*•ª–)((?~¼‡‡‡@ èß¿ÿ¬Y³Ž;¦¹Úï¿ÿ>..ÎËËËÎÎÎÕÕuòäÉùùùÌ[iii}úôéüº‡ŠŠŠÖ®]«¡€êr8Ÿ9sæ\»vM/­[+å7f¡õ›Œ2€öYÜ´i“———òÇ   £÷‡ˆhëÖ­>>>õõõùùùiii‰dÆ Ì[Û·oŸ?þ¸qãÒÒÒD"Qiié¡C‡<¥®¶¬¬¬¤¤¤Áƒ/^¼Øßß¿®®®°°0..îÀS§NU-éîî>dȽÜBQQQVVÖo¼¡¹s§2™ìÊ•+ëׯÿî»ïΟ?/ õÒ+£šáªüý Ñ„[Y™²-Œ2F€ˆ:„ÅèèèAƒi(-•J¹\®»DL7æÌ™3räÈ>ø@333‡ VXXÈáp˜+Ë–-kmmUWÕwß}—””ôôÓOïÙ³ÇÆæÁ;òÊ+çÎkkkëP8>>>>>^ÿ÷£žòN‰¨oß¾/¼ðÂéÓ§'NœhÌ>X&)(#*1õ3‘±—äEBd€GyÄ—””OOÏÂÂÂ>Ÿ¿téR":räȘ1cø|¾H$š6mÚÅ‹;”ÿé§ŸÂÃÃù|¾X,f&|·mÛ6`À¡P]^^®eçX,Ö¨Q£$IMM s¥¶¶ÖÏÏO™vvvêjHOOçr¹999ʤÈ>|øÈ‘#;î< }îܹéÓ§;::òùü°°°âââwZ\\Z Ó ÎCa±¡¡¡ö‰„¹X[[›˜˜¸bÅŠ«W¯&''=z466ÖÞÞ~ïÞ½Û¶m»|ùrXXØõëו•466Ι3'..nïÞ½b±ø¹çž[¶lÙǼfÍšìììóçÏÏ›7Oûþ]¿~ÝÙÙÙÉɉù144ôðáÃ7oÞÔæãEEEcÇŽer˜®Îž=;f̘ÊÊÊœœœ}ûö¹»»GEEýðÃʵµµ¯¿þúÚµkKKK-Z”””TPP@DË—/íµ×„BaiiiiiééÓ§Õ5ÑÔÔ$‘HêêêJJJV¬Xáíí=nܸntôËhÁÔÜ92v~N@¿ÿ½xh¼-88Xù:$$„I9R©4;;;22’¹þüóÏûùù0cuaaab±xݺuÙÙÙL‰D²yóæèèh" õôôܵk×Õ«Wù|>544$&&VVVzxx¨ë¡òòòŽ9’­ü7ÈÆ+++SRRRRR|||&L˜ðâ‹/Ž?¾Ëzêêêêëëº÷Õ¤¦¦ºººÙÛÛѤI“‚‚‚ÒÒÒöïßÏJ¥999£F"¢¤¤¤;vìÞ½{òäÉÎÎÎ"‘ˆÍfû?*s¨Žn0m~y&¦@ÕCa177×××—yíààð „MDD󺥥¥¤¤$55U9«ëëë;vìØ“'O*+ár¹Êå&nnnîîî‘‘‘LR$¢¡C‡Qyy¹†°¨¡’’’,X üÑÛÛû믿>{öìáÇ¿ýöÛüüüÜÜÜ5kÖ¼ùæ›2™¬¡¡AYÒÑÑQ—ï¡£ÖÖÖãÇ/Z´H™ÞØlöÔ©Ssrr”e“ ¸qã†N­ìÚµË××W¡PܺukÓ¦M“&Múúë¯ÅbqOzn•zíPŸ -2*ŸH†^.99ÙÔ]€®uYì¼ÀÅÅÅ…Í~0[][[+—Ë===U xzz^¸ðç¯ GGGey"âr¹ª³ÀÌú˜–– }b"TUUUffæ¦M›‚ƒƒçΫZ 00000ˆª««cbb–/_õêÕÐÐPe…B!‰JKK5}jÜ¿¿­­móæÍ[¶lQ^”Éd2™Lùc‡e˶¶¶šï«³#F(¿ð˜˜//¯Õ«Wçææv£Ã† ßÈx;o(F%,Žn›r3A°¢¢BõbEE…‹‹‹û¤ŒP“&M6lXJJÊÌ™3Aç’...óæÍ;sæÌåË—üqÕ(ŒÈÈÈÇ×ÔÔèúØ¢H$âp8 .ìöèÄÑÑÑÇÇçܹsÆi@{zŒŒÈ‹G·ãþx<^ppp^^^{{;såÆÅÅÅZ–!ÒÓÓïܹ£œüí¼mõÏ?ÿLDB¡0\ónjjªT*Wv˜qîÜ9Õ¥*ñx¼ˆˆˆ'N z˜6=çr¹ºŽ2VUUݸqÃÍÍM§O¾–¿`m5€eÑù¸¿·ß~;&&&&&&11±±±qÕªU 55Õ#¢gŸ}6((hýúõ \.722ràÀ±±±‰äðáß|òÉŒ3 ÐåÇCCC7nܸxñâ   yóæùûû×ÖÖååå}þùçš›ÎÈÈ`rgbbb¿~ýª««Ïœ9CDéééìöСC¥Ré¦M›BCCy<Þðáû,vâĉk×®)ŠÛ·oggg·¶¶¾öÚk¬4 ½uëÚÃ;Ù³Ùýmlb‚}Ø8½G°ü ·Ñ9,Nœ8±  `åÊ•sçεµµ7nܺuëüüü Ñ9"b±XiiiS¦LÙ¾}{BBÂ{ï½·oß¾ìììÛ·o³X,±X¼zõê”” 5,Z´hÔ¨Q™™™™™™÷î݉DÁÁÁŸ}öÙ”)S47XRR²råÊÔÔÔºº:77·'Ÿ|RËYé3fÄÇǯ^½º¦¦ÆËËKÝF? Ì ww÷áÇ=zt„ ÚÔ4ØÎÎÍ&"Q…Lv¾µõ|kk~cãÁ¾}{¬‡‘“Ѥ·Sa‰T[ÍoÖ§2GQñµ{OvÀÒ}Gnfdq»›Û4•}ˆÎµ¶Îª¬¬‘ÉÞÖâVæüíІ†iåÿ¿íPÒ{öEÂjhø³é̆XÀ¨˜˜øTæh&5Íp;»…DT¬ã³¤ðHÝ~–ñÖ§ú9Š aLÆÈ‘ÑÛÆ†ˆÚ1naÝ‹ŒÈ‹æaLÌh‘ñg©”ˆª?IzNsd4rg@/Áغ|`Ñp‘QNt»½}[}ýÿ54رX‰M†£!2v6Ûû}ƒvzHçÕІ£ëò ^ªª¢ª*Õ+¡<Þ*'§ .·ç•ƒ64¬˜î`¶÷ûŸÞzÅð=€îÀjhÓÐfmo¿?ºŽ+j(i•˜ÈØíÕÐÃììÜ8æJLö{{»D.àó³]]]ÿ¸®VCë—6‘y±—Ãjh³…‘E0S=œ•^"©nÓ¤P¼]Só ÏTV÷òztZìÔ½ŒwX„Eè,Ö;..û/µ¶45Míê¨qÍ»Gûu-˜Œ0O‹Ð[pˆ|mmk¤Ò+­­¤{XT¥ ŽHšéººC^dæ%­¶" ‚°hÚ„ Õ_´J´{ä,óƒg—²ôÕ±v…âz[ ôw܆5èÞ^9³½ßgNv±nL6fd4“ä” `‰Á4'EC¤®F¹|åýû÷årQŸ¯å§”=ÑæJǹ{³z©CzPÍ4ãö¢cæàdÜ"JNN6tx2“Œ¨dü” =‡°fDk}]݇ –“×Èå¥íír9‹h¹³³ØÖ¶'Cp4+މ æOÆM0h^4Ãäm´” z„°ÆÖeØÒ{¢ºÔÚzé×v,–'‡3™ÏÉÁaT÷YDp4s³fÆIÉ _‹`bzÏOßy{ë·B  Á¬ÂåBò}AX“±²´„àfÉzaŒJú™3G°‹`T½0 !8€ECX0öâ!G0‹& ëp#áØ€ÞŠÙ‘T …~+«‡°`b˜§€Îôž;׌ÔZBX0#Žzw~Í5gKˆˆÅfs]Ü<ÆMòÿë<Òñ×ðo&xMšé1É0}èH5)†Ì¾¤¡d7|ÿé`e+È‹  „E3…à¨/Þ“ŸðÂ…\VõÒ/éÿà¹yxFĘºSj1IQïQ‰©™‰ŒÈ‹  „E0k …‚Åb¹••Uùû›º/¦„àØ#,bq8,ÇqH ƒx¤ì7沬¥¹tÏöê3§Ú››D ¿ô:Ï̓ˆnì»ùU~{cËÖÖ㩉 ¹¬±¼ô÷Ornìû¸O€xHò “Þ X9C'E¥Ù—AK‹Á±Ûš+nIÊ®yŒ{0›üë–µŠöö w¶ØÚ Ëò>¼±|ä»Ûš+ný¾ëý‘éÿxùʤ-MåeBñ ú_1í44ÇCPæEÍ:r++3u´…à¨;…_U:®ËÚ$ îa‘áˆHZ]uï?ߌÎÞc'r""ÿ¸—n:ÐX^Êá ˆ’߯Ú9ºØì…âA¦îþÈ‹½áµôÂ"˜;#ÏD+“¢ÅÍË 8ªãå?ûo¤P´Tß½¶#ëêöÍç'µTU‹u.í¿•ÅØ\®ô~µs`ÿÁIoÝ>tàJN¦½oßgžw¡ÕÞFF`nyñ§ÿ}ÍsBlßÈXSwÄÚa@'‹`”yј-­-CÀîߪØ\®£3Ù9¹xFÄü¾+gàü$ž«=±j£­ƒc‡ò®£Â\G…ÉÛÚ*O¾±"ìƒýº®ž6œääd"ÒoddŒÿeAŠçøÉ̕ƛeg–Îçpyá;¿ÒðAŸi³í}üôØ0OlSw@+ÆLo–žU/9­ü£åGžÊÍüÑWôXU7)H!“)díÍ·îž*²÷ö#"®«»ë“c.ÿ+CZ]EDí UßPÈdÍwnÞ?÷ƒ¼­•mkkë b±X,6ÇÎÉ¥ùN¹‰ïBõHàí{§ð òÇ;…_ ´Hn£ÇjS À̱Ô6l˜–•dee)?% ƒ‚‚¶mÛ&“É ÚsU/¿ü2‹ÅZ²d‰!*ÇÈ"X kÊp&aÂyê§2G›pÀòVÁ¾[ûˆÅ²Šïÿ«ÌõA‰o\ÏÿèçUÉmuµ¶BÑà@×±ò¶Ö²½;šnß ›çî1dÉJ6—ÛozÜ•eÜ>ú¥°ÿcÃÿ±ÞT7¢J¿SÒ.#C+Oi,/µï ok»[|Ì÷éçËöî`Þ½U°ïöÑ/¥ÕU6ö}ÜÇŒ˜3ŸÅ±!•ièRãƒB~ûµµ¶†ˆ5ðå$Ñ ÇõÕ7CËËËS¾~å•W˜ššÊü(‰tªjëÖ­>>>uuu»wïNHH(++[»v­>ûªFss3s»víJOO·±ÑsºCXèŒM•ÿµÿ¦æðýÿëÕþÿõªêE{ßþAïdu()ú˰Q™; Ò¿Ðc^dÙØxDLºSxPü·Ä{ßmß/€ß×Gù®£ó°eïðÝû6Ý)ÿeÝ?¸ÎnÞ±Ït¨á^É7O¬Ü`ëàXyòÈ¥®½e·^:f¹nç õšuÁÔ½­üõ¯U¾~íµ×¼¼¼T¯è$""bРAD4gΜ'žxbË–-ï¼ó‡ÃÑOG‰¤R)—Ëí|}ÿþýõõõ±±±5•yúÓåÉPé½»­u÷õÕ1Ëu;oèí¼¡¦îôÈ‘#GÆŒÃçóE"Ñ´iÓ.^¼¨åÙlöèÑ£%Iuu5;wnúô鎎Ž|>?,,¬¸¸Xµ°†wSRR<== CBBø|þÒ¥K»l.77×ÉÉéÃ?äóù;wîìîíª…‘Eø“¡G™òÖ·†Æ„ôµä…ïáÕÇO|cÿ'åe®ÁOÝ?ÿƒò­êOßüòÓæ»wˆH.má{útþ¸­ðÁlÛŽKD²æ&9õ°KÍkÖ&)2ÿkÀQF…ü§¯&´6UØrƒ¦d±{ï¯u½ÕG?~üÞ½{W¬XöóÏ?ûùiõ¨nii©ƒƒÃÙ³gÆš““# srr¢¢¢¾ýöÛ‘#G‘æw‰¨¶¶611133søðáR©´‹¿}ûرcñññnnn3gÎÜ·oßýû÷œôù°÷þ¿ 4ÓWp,^rºÃÇMû£UÒË”tߨ)7¥ùLù+ÛÖVy±­¾öÂ{ˇ¦¼íB,Ö̓ùU§Ž÷°¡^B™É‘±¶òTkSµIkîß>îì3QïMX æ ×ãWýÖ[oùùù0†……‰ÅâuëÖegg«ûHSS“D"©¯¯ÿøã;6sæL—ššêêêZTTdooOD“&M JKKÛ¿?i~—ˆ¤Rivvvdd¤ºF?úè#¹\>oÞ<"zñÅwïÞ½wïÞ ôüPBX€GÓûˆ#¦¤õ®çyÑ58|øÿ¦÷ñ zQÖÒBrE1±Xm õE9\~ÏzÚ{"2V•î#";¾GkseUi~o‹ªzþU·´´”””¤¦¦*‹øúúŽ;öäÉ“>¥d±XqqqYYY­­­Ç_´h“‰ˆÍfO:5''‡ˆ4¿Ë°±±‰ˆˆÐÐèÎ;JDQQQ^^^;wîDXSÒ&8>Ÿ=x×ÂKšË„g„è½o½\ó"‹cãôøˆyîžs_>ûö[¡£@à4üÉúËX·¡-ÕÁE%=FÆöÖºÚ[ED,qhÆ¥ã/ÖU|ÓÚ|׎ïÞóš­CO¾êÚÚZ¹\îéé©zÑÓÓóÂMµíÚµË××W(888Qeee[[ÛæÍ›·lÙ¢,&“ɘ]uîß¿¯á]†‹‹ ›­v…IIIÉÅ‹—-[V[[Ë\yæ™g²²²®\¹òØcévÏê!,@÷© Ž»^z>{°êêjÈ—ïy–ýœº×C?¤ÆûL›íñT”©;¢ƒnäÅ.Œ»Œ­Ü‘»ßô¸~Óã:—Q.™þç(ÛÖnÜÞB:Ð;é%2Þ»þ…\Þêà"t)ò «½óõ½ëŸ{ zEO}´÷ûÇÿRÈÚ‰èZî–ÆòÒß?ÉùÏë/\ܰŠùhkͽs錄[²ô¥º_Ϥ{D¤{b«*ýŒˆœûMfsxDÄbÛºúM¥?–¼hïÖ§Ct*o´ÜsâĉMMMsçÎ]¸pá AƒN:¥å¾9ªKJJ šš»dÉ’+W®DEEió®f¹¹¹B¡pÖ¬Y®Ï™3‡Ïç33Ôz‘E0½?G3 ØÊÝo ¤øø‹:I"~1±þ×_:LCß>úÅÅËíýúß8°“€Ayͺ@¤í¤¡\ÞZ}ã+"r xZyÑÕÿ™Š«×”ò ú_ŽÀ ½´"]Ž2vxH1:::::Z›Ú^{íµ×^{MÝ»ƒ Ú³gO7Þ}ï½÷Þ{ï=uüüóÏ»¼.‰šššÔwVgYCy*s´†¥-]úfé÷zïÆÂ¯¾‹ÿë7›öûÇÿø÷Eö¾ýµ9’„Ñ7jšP<ˆmkç3“è‘÷lmOÂè ¼f]ÐuúþÍcí­u¼>~B×?°Û; 8–µ7Õ”è»V¨_{¯…‘E0f™‹êCŠšµ¼h •áQþ³ÿÆáò8üc-ÚIÂຸ1/8<>á`½úôÖCë0˜ú …ÂDÝ1ÍÓ=XÚ’OD²6ÉÅ¢çU¯·µÜ#¢ªÒ}nÏjY•÷ì‹Öôµk3¿ŒŒ¨+„EЧmâ‹Zž'mc"µ¼h˜î±¹\;Gg嚎$ÑÓÊAh³ÓMÏcôù5oð½û‰_Lìa=ÊÚ¬1·ãò=½}Ÿžë>f|熔ÅXl6×ÅÍcÜ$ÿ¿Î3É—l†z’WZ›*êîž&¢6iu›´ºs†{?¶4”ñ„þÝnÂB=2)"&vÂ"ô”2 vA“bgŽ$±sri¾SnÌΓ> ½³Æ\Þ*½}ìß¿þsMq—kÌ™b ¹¬þê¥_ÒÿÁsóðŒˆ1hÇÌJ—Ù¥çy¥ªl)䡃ÇmïüîÕï’kÊU•æ÷¾´‡ YÄÄž@Xõ0ª2rR$G’ô›wå_·~)ìÿØð¬7rÇôB§¹Ûêj¯ån©ýå'b±œŸÏ[hÓGHD²æ¦Ò½;ªÏ|ÛÖPÇsóxlAŠƒ¸Ó81‹X‡/è7uVé'ïKÊ®u½!‹X‹Ãqè $)û­û÷fùô”WU¥ˆÈÍoF—o»úM¯)?TUö¹Ïã‹Y,Ž>Z´ Šæ@‹ ¥îDf÷œ.?›ðÛ‡D´ztœñ#uy<‰º#ID6*óÏí~,î`]Ïn¹¸ñmû>£6|¨ËýçšKYï>þÆ"º”õ®¬¥9pE&ÏÕ½éÎM6GÓoŠ»§Šrù#·®l®¸%)»æ1Ψž›–jvÑcd©¿û½´±œmÃwRs ´£çS6\§¶–ªº;ÅŽ^új×â &êÂ"X}mIß5=â­Ý>Ô¼½¢²LëÃîÕ]Ò5)¶TÞ©½xvô–Ý6ö}ˆ¨ÿ¼g–Îo½_­ÉªÏ|¼ù#ž›©Kw ¿ª:u\Ö*•·µ>öJr±†b ¹¬MÒàé>AÇÛ²Tʤ¨÷ÈœÚâì=QÝæ8,¶K¿ØÊk»î–æ÷ž°h h „E°ʈëïÍ©±'ÇÚשMšèš‰¨¥ú.‹ÃẺ3?ò=¼ˆHZ]%oke±Ù|÷¾ª…+‹ýšõ.ó:lûçôÇó¶úºßvfß?ÿCߨ©]¶Â#…¢¥úîµYW·o8?I×®Z(E–!넬Ó\ÆÄ?üGüí›'ÃEs` ,‚ePMŠUþþ†h­¬LÙVïÉ‹>Ô×§@ƒnÄDÏÅ]!“I««˜íZ*ï×ÅM!“)äò–»þüqãÆ¥¥¥‰D¢ÒÒÒC‡>>>>^ÿ÷Ó㎑)ó¢E3ÄÓ‡Ýf¤øÓÿ¾æ9!¶sˆ1U=ú¢kRìrU8 NêâÉ6ýÀù¯œÿº–µqø‚1ìïü–ºFÀ²<âlè””OOÏÂÂÂ>Ÿ¿téR":räȘ1cø|¾H$š6mÚÅ‹;”ÿé§ŸÂÃÃù|¾X,fæU·mÛ6`À¡P]^®íž·,kÔ¨Q‰¤¦¦†¹R[[ëçç§LŠ ;;;u5¤§§s¹Üœœe c >|äÈ‘ wž†>wîÜôéÓù|~XXXqqq‡;-..=z4s§›7ofÞZ¼xñ;ï¼SWWÇ̧ûøtq’˜Nëͬ{:X¿T'—»=¿lˆŽé·Ú¦Û7.¬_þíËÏÿ×äÿ¼þÂåmïé±rU?¾™Pqâ°òGŸi³E=ú1ãèösŠ`æ˜ÙŒï?Õáô##x(©444ÔÖÖ>xÃÆ†INµµµ‰‰‰™™™Ã‡—J¥G?~üÞ½{W¬XöóÏ?ûù=x¥±±qΜ9‰‰‰©©©ÙÙÙÏ=÷Ü’%KN:µfÍšÖÖÖÔÔÔyóæ?~œ´sýúuggg'§‡±†††8p ###..®ËÖAQQÑØ±cY²³³gφ…… :4''G(æääDEE}ûí·Ê0W[[ûúë¯oذaРA{÷îMJJ8pàäÉ“—/_.“ÉrssÏ;GDâ`Ï;Ö mÚâ˜Õð¡1(çßýÇ!ÃG¦çØ Z*ïÔœ;cœ–ÝFw±zÃøÀøÊ1ÁÁÁÊ×!!!§OŸ&"©TšÉ\þùçýüü ˜ &‹×­[—ÍH$›7oŽŽŽ&¢ÐÐPOOÏ]»v]½z•ÏçQCCCbbbee¥‡‡‡º>555I$’†††¼¼¼#GŽdgg+‡—6nÜXYY™’’’’’âãã3a„_|qüøñ]ÖSWWW__н¯&55ÕÕÕµ¨¨ÈÞÞžˆ&Mš”––¶ÿƒÙ©Tš““3jÔ("JJJÚ±cÇîÝ»'Ožììì,‰Øl¶¿šˆÓÃŽAofOšPk}mËÝ;ÞKWr]‰Hàã'ðy🩲–æÒ=Û«Ïœjon=6TüÒëÌ6ªº,Óåi%×r·4–—þþIÎ}÷ I^¡œ†VwêÉ©ñÎA! ¿ýÚZ[CÄør’hÐãú½}$EÐ/ a‚– ‹¹¹¹¾¾¾Ìk‡%ll"""˜×---%%%©©©ÊÑ2__ß±cÇž1‚ɬ“&M6lXJJÊÌ™3‚.Î5rqq™7oÞ™3g._¾üøã«.@aDFF>|¸¦¦F×§E"‡ÃIHHX¸pa·oDƒnw ´t¤©icc‰TZ%“ɈÜ8œ'ìì¦ÚÛOìÌoÑ †µgÓGè?ûoþ³ÿ&ok½[\x%'“çÑ—Ãã‹u.í¿•ÅØ\®ô~µjXl©ªè\¦þʅΧ•h îÔ&,Ú Ej¶ã‘¬¹‰ô¡·aò¢Z1t`t ‹</888//oõêÕÌLô7Š‹‹_~ùeCtN ¤§§Ïš5+''gñâÅDtíÚ5±ø¡Hþùg"òðð …ááájHMMýâ‹/âããUw¨!"f‡ ëŽy<^DDĉ'Ö¯_ßÝ‚¸\®æQÆnw é®LöRUÕ÷--DäÈf?fggGT!“ý»©éßMMïÚØìÛ×ýáõ&áÃbÛÚyFN¾¾—¤ôs¸È«62{]â¹zt.#½w÷ÆþO:œVò@W¿ªÕz¢‡ûx’˜û{ûí·cbbbbbW­Z%RSS Ñ9"zöÙgƒ‚‚Ö¯_ŸÀår### ‘H>üÉ'ŸÌ˜1cÀ€]~<44tãÆ‹/ š7ož¿¿mmmQQQ^^Þ矮¹éŒŒŒððððððÄÄÄ~ýúUWWŸ9s†ˆÒÓÓÙí¡C‡J¥ÒM›6…††òx¼áÇë±cIH†K<÷åòØ;w®··´µ]íì<žÏW>q£½=§¾~GCCµLf’°ˆáÞk«¯½ñù÷°HA_…Bq÷T‘´ªÒá/C¹®î®O޹ü¯Œ/½Îuqkol¸î×à§X*ÿ Õ•aN+ùKB*×Ùµ¹â‹Ía‚£“KóŽû|ñ<ú2§ž<öêR’Ë•§žõ[0.Ãâĉ V®\9wî\[[ÛqãÆ­[·N¹oŽÞ±X¬´´´)S¦lß¾=!!á½÷ÞÛ·o_vvöíÛ·Y,–X,^½zuJJІ-Z4jÔ¨ÌÌÌÌÌÌ{÷î‰D¢àààÏ>ûlÊ”)š› ,))Y¹rejjj]]››Û“O>©å¬ôŒ3âããW¯^]SSãååuóæM=vÌ¢-¸¶C¹  !2Pjuõõöö¿ØÚ~Õ·¯ˆýÐ6¢¾66iÎε·w4bRÄð¡~±í¸²–æ_ÿ¹¦åÞ]‡#ðê7èµ7‡Ñ Ä7®çôóªä¶ºZ[¡ƒhp k§£Š»,£î´’~Óã®ü+ãöÑ/…ýþõÊJÔz`­¬ç@3ës;ïÏ€-èà˧2G+_/9ݹ@‡ü¤9étÖßommcnÝ’}áéÊãióu˜\ºñ·ÇÚcþáª.ÝHNN&¢q{ MÖ'ã:7 ¶xÅœ¿Ì.oœé0~%˜!GôK£Œ‡››åDþ66=LŠºÂð!X1„E06f&ºÃE½DƳR)0üñå>€ÞaÌH#cµ\ND®†y$Ç`Y6lØœœ|2n‚yÎD€AX4 m’Çôwu+o.T–u¯Û=ŒŒzÜš aÌT7‚š ›MDU*§ìÒ¡¾`0̘Õ$ægÒX„E°\î¾ÆÆ¥R#´…€øH/eü¨úãö¥#LÕ“^‹ ߦîE, Â"Xh>%QY{ûw--z_t¨«íKG¨æÅÙ‘ˆþþÞDtîàᜯ•o™ç`˜!:6!–@ÏaŸEóeÌ}Uç|{˜Š¹Ïbç»ÄtC§}‰h~UÕ±µ=Ø·¯ÃÛr3~–J=llú>jL·÷Y„:gÄGÚ‘Ò[Ž»D’S…}ÌFÁ4'Åž¤Õ÷\\~–J/·µM¾sgµ³sDWÇýëÛ÷‘aô¥Ãøâ# ç|`VÁŒô|ª×‰Íþªoß—îÞ-‘Jã*+Ùìþ¶¶¶,ÖööííDÔßÖÖIѸ´Ï‹ª3Ñ`&ÁغVÔãžÎW}ûnjÚߨxF*½ÔÚ*#rçp¦ Óíí§¶,=î®ZÑ&/")˜'„E01C,aÅ1Þk†î鯓‹`&Ád°¾¸7À4€¥CX£ÒËÐ`´MDR0g‹`Tˆ‰VO×g$E3×ÅFtÝðRÆ’"Np°PY€žÒ<š¨!&îH‰]ÌÂ"t_O†{ÏI- aº£‡3ÎÛ—ŽØ‘¢×€a ,€nzþ`"ž_° ‹`Ö ‹År++«ò÷7u_@1,Â"99¹;}cAXèÈ­¬ÌÔ]0ú‰Ýû˜Â"˜;#ÏD+“¢B¡0BsfKï1±ó§zù7 `)Á(ó¢1[4Z[æÆ1,Â"X&/­-ã4dn°~:CX‹Ñk3œ &€:‹½b"h†°ÐK!&€6z¬_ ,ôˆ‰Ð ‹Ö1º aÀšáÁDè!„E넘z°`m@¬b"èÂ"€5@LAX°`Xæ ††°`‘À8, b"Â"€ÅÀƒ‰`|‹1LaÀ¬!&€i!,˜)ÄD0‹`yX,–!ªU(†¨¶À| ,‚Å0PFì\¿©R#–9€BXË š«üý Ñ„[Y™²-#çEÄD0[l"ÊÊÊburèÐ!#wEµvvvb±ø­·Þ’J¥ªe Æïáá!ú÷ï?kÖ¬cÇŽi®öûï¿‹‹óòò²³³suuóVZZZŸ>}:¿î¡¢¢¢µk×j( z§öööÏ<óÌgŸ}f>Ó æ†IŠUþþ̵¢Z¹¡G1•^ÊøQó¤3’"˜ÖŸ#‹›6mòòòRþdŠþÐÖ­[}||êëëóóóÓÒÒ$Ɇ ˜·¶oß>þüqãÆ¥¥¥‰D¢ÒÒÒC‡ŸV\\ÜáN‹‹‹GÍÜéæÍ›™·/^üÎ;ïÔÕÕ1³Ì>>>ZÞoBBBTTTNNNSS“–é Œ6l&1ã æéϰØÐÐPû‰DÂ\¬­­MLL\±bÅÕ«W“““=koo¿wïÞmÛ¶]¾|9,,ìúõëÊJçÌ™·wï^±XüÜsÏ-[¶ìã?^³fMvvöùóççÍ›§}ç®_¿îìììääÄüzøðጌŒ›7ojóñ¢¢¢±cÇ:;;kߢÒÙ³gÇŒSYY™““³oß>ww÷¨¨¨~øAY ¶¶öõ×__»vmiié¢E‹’’’ ˆhùò寽öšP(,-----=}ú´öN›6­¥¥åÌ™3Ýè°u3Ú´á &€…úsÈ-88Xù:$$„I9R©4;;;22’¹þüóÏûùù0cuaaab±xݺuÙÙÙL‰D²yóæèèh" õôôܵk×Õ«Wù|>544$&&VVVzxx¨ëPSS“D"ihhÈËË;räHvv¶rliãÆ•••))))))>>>&LxñÅÇße=uuuõõõÝû^RSS]]]‹ŠŠìíí‰hÒ¤IAAAiiiû÷ïg H¥ÒœœœQ£FQRRÒŽ;vïÞ=yòdggg‘HÄf³ýuÏ7~~~DtçÎîõÌ–9€¥û3,æææúúú2¯¼mcÁ¼nii)))IMMUÎêúúúŽ;öäÉ“ÊJ¸\®r¹‰›››»»{dd$“‰hèСDT^^®!,ªN'%%-X°@ù£··÷×_}öìÙÇûí·ùùù¹¹¹kÖ¬yóÍ7e2YCCƒ²¤£££ŽßÃCZ[[?¾hÑ"&)›Íž:ujNN޲Œ@ `’"cÀ€7nÜèI£D$—ËÉê&^{-ÄD°,v^àâââÂf?˜ª®­­•Ëåžžžª<==/\¸ üÑÑÑQYžˆ¸\®ê,0³>¦¥¥EC‡víÚåëë[UU•™™¹iÓ¦ààà¹sçª $¢êêꘘ˜åË—ÇÇÇ_½z544TYF¡PˆD"‡ÒÒÒG|]¹ÿ~[[ÛæÍ›·lÙ¢¼(“Éd2™òG¡P¨ú[[[Í÷¥ &nöíÛ·‡õ€i!&€5ÑaSn&VTT¨^¬¨¨pqqÑc‡FŒÁdÖI“& 6,%%eæÌ™ sI—yóæ9sæòåË?þ¸êFddäáÇkjjt}lQ$q8œ„„„… vûFºáË/¿äñx߀öBoݺöÇRw‘€Ív`±Ä¶¶A\îÓööÃÔ/‡Ò ÄD°>:„Eœ——·zõjf&úÆÅÅÅ/¿ü²!z&ÒÓÓgÍš•““³xñb"ºvíšX,V-óóÏ?‘‡‡‡P( ïPCjjê_|¯ºu1[çhÈd</""âĉëׯïÆnA\.·£Œ[·n-,,\¼xq—Ét2ØÎÎÍ&¢f…¢Z.?ÕÒRÜÒ²¹®n"Ÿ¿ÁÕÕãáõzÝpÀZévÜßÛo¿“˜˜ØØØ¸jÕ*@ššj Î=ûì³AAAëׯOHHàr¹‘‘‘Œ H$‡þä“Of̘1`À€.?ºqãÆÅ‹Í›7Ïßß¿¶¶¶¨¨(//ïóÏ?×ÜtFFFxxxxxxbbb¿~ýª««™EÊéééìöСC¥Ré¦M›BCCy<Þðáû,vâĉk×®I¥Òòòò 9 IDAT/¿ü²¨¨(::úÝwß}dý U†ÎOÿ-MûãyS"jËó×ÖÖmnžzçΡ¾}]ô—Àºé'NœXPP°råʹsçÚÚÚŽ7nݺuÌ^C`±XiiiS¦LÙ¾}{BBÂ{ï½·oß¾ìììÛ·o³X,±X¼zõê”” 5,Z´hÔ¨Q™™™™™™÷î݉DÁÁÁŸ}öÙ”)S47XRR²råÊÔÔÔºº:77·'Ÿ|RËYé3fÄÇǯ^½º¦¦ÆËËKÝF? DÄçóÝÝÝGŒ‘——÷ì³ÏZýê–íKG(7‘1Z–²Ù £ùüè;wÊÚÛÿQS³ÕÍ­çÕ"&@o`ØÍ 'nç U¾öšuACÉžÛ&þ»òõ‚k;zRÕS™£•¯‹—t±Íd‡Œ¥9WézÖóÌâv77Õ‘E¥Ï_®ªâýÔ¯__ƒ‹Ì .êþv &@ï¡ÛÈ"€Þs”qª½}Ÿêj‰\^ÜÜ<ûá{´õ+Ð !,‚±13Ñ.'2rˆ·³û®¥år§ÃÁ5CL€^ ä"£+›MD5r¹N]R1¬¢ihŽ Œ4_ÝÊ÷D°Êëž¶¥²D§{U422!j¹ŒHÃiÎúꀙCX3e ||O.'"'•s†t‚˜½ Â"ô"2¢_Z[‰h°îG¹ &@ï„°½È¿%r9‡(œÇÓþSˆ‰Ð›aŸEóÕí}U'pµ :ÆÜg‘ñÈYf¦çzÜg±B&‹¾}ûŽL6»OŸ-®®šëѼÏ"@ï‘E0#/1–Èåûß­­­’ÉümlV;9é·~+†°fD_1q}]݇ DÔ¢PÔÈå¿·µ1;åLäó7¸º:ëï`h«‡°ÆÖå°¢~G/µ¶^"""‹%b³Çðx#¸Ügìí‡ê¾® —CXÓoLüÎÛ[µÂ"˜ V˜?„E0*㜠ú‚°F…˜`Yºyèô‹ Â"¨…°j!,€Z‹`Ö ¹••™º#½Â"¨…°Ð2”ÁÜy&ZÙÓ.@/‡\À( ‹eÌ?$EFÁ23½!)(ad,2€ñadÔBXµ@-„EP aÔBXµ@-„EP aÔBXµ@-„EP aÔBXµ@-„EP aÔ²1uàX,–!ªU(†¨¬ Â"€™2PFì\?R#h€°`ŽT“âž›iâ9Ÿ?ÛB^uÌ“ ”•˜ú™Èˆ¼ê` €y1NRTR6dèYo°P‹½Ñ‚)X"„E3‚á=07‹fC}`>@-„EP aÔÂ>‹lÉ8ºýÛCWxöä@£&Qì+Äïc¢n€AX°x¾ƒÈÁ•ˆH.£û•Tö •ýB§ÐÛ¨“©;aÀ€nç %"¯Y ÚʳÉ2åÏKÏÓšçéöo´ÿŸôÂrƒ¶ ÖÏ,oç eR£qŽ7>ØR瑞ó!"¿  3Œ,˜…žü·ÁÓ¯?´uŽ´‰>YC‡?¤Õq´î±9ºõÁÐý¨bÂ1€*üG €¹Á3‹fäÖ§Cn}:¤‡•pôâ*:Qùe:sD‡¦™Ìó”ØF̈÷실Ë4´:l¹ùRÃ}ºy…‚'w³e^4ôXㆠ Z?XŠäädSwº€°htúmýRÆÊ×Û—ŽÐæ#ÛÄW¾^pm‡ömuöTæhåëâ%§{R•5yä@Ýÿˆõ3-+k§»×‰ˆx=Ô¦—ééÛyC9Á ú‚°`pš“¢Þ#TK#íJ#I-±9ôD¤¶Ÿòž}‘yVL]o{8Ðè5ëò"€%BX0}%§ü tô£¯%÷©¢ŒZ‰Å¢¹ÿC^ºÙ+ ·'È‹aÀ°ºL]ú L7~ýóµ­9zГÑý"=öd÷ëTöPïÈ‹–aÀ¨ô›“2Oê±²®t ÌÂ"€‘XtœÒï@#,Â"€Yߨ›¾R#ò"€¥À¦Üä5낵F¢GÞZç½;”Ǿß#‹Ð}=h¼õéfr0[‹ Z®ƒéìÖ§C>½e¨^@Ïaô†™›Öuæ}¶÷ûêôÂ"蟮‘yÀl!,€¡è4Ј¼`žÌs:ós>¦î‡¾Yñªp«‡.` Úl”3ÛûýOo½¢z%99Ù`=2± 6˜º ZAXèíŒ0©ý–ŠL^´âŒ¨ÄÜ£1#£™|«HÉaÀ¼( ‹õœí¹iŒæ”I‘™7]7ßžíý¾2ÔŒÛ[¨÷þ˜‰“qˆ(99ÙÐáÉL2¢’ñS2ôÂ"€ÙQæEc¶h šuJŠÌ4&¬8&2˜<7Á yQ5)šÉWj´” ú‚°`Ž˜¼h´¶ T³æãþˆˆ¹GÕÐ`nÃ`ÖÁLb"Ã8)ôaÀL.ÃM·W@›U¸±\HÞ Ø:Àš!y@!,€Z˜†06=”l¯€BX0C/\SÖÔz„°` ªI1dö%C4ñý§ƒ•m!/‚¾ ,“ ”•˜ú™Èˆ¼ú‚°Vîüš7jΖ‹Í溸yŒ›äÿ×y¤ãlào&xMšé1É0}+gœ¤¨2ûò"èÂ"X?ïÉÏ xaB.«¿zé—ôðÜ<<#bLÝ)RæE€žCX€^€E,‡Åá8 t’”ýÆ\–µ4—îÙ^}æT{s“象â—^ç¹yÑ­‚}7¿Êool`ÙÚz<5Q!—5–—þþIÎ}÷ I^aÒ› c´Ó˜ az‘æŠ[’²kãÌ&ÿºe­¢½=è-¶ö²¼/d,ùî¶æŠ[¿ïzdú¿^¾2iKSy™P<¨þ×_L; Ãñ,Ñæ ôa¬ß¯ªNWÈem’÷°Hð D$­®º÷ŸoFgï±9‘ÜK·h,/åðD ÉïWí]löBñ SwÿäE0 œàÖÏ#9æò¿2¾ô:×Å­½±áþ¹\ƒŸj¹{§¥ªR4øq¶­­ƒˆÅb±Ø;'—æ;妾?é4%}~Í|ïÿgï¾ã›*÷?€OÒ‘¦#Ý-]tB™edÊ' W«‚TQ*ÇO6‚ ”! Ve8rAP¯d²Šl …miéÞ#ÉïSBi“6mÎ99I>ï×}ÝWšœóŒ(öÃ÷œç9þ¡¯Mæ¤kÍVD߀çÆz>ñdÝŽ8Ù± Q^|ñEÍë)S¦øøøÔ|§QúõëND/¿ürçοþúkÍŸ¸øøø¶mÛîß¿_*•²ï¼÷Þ{ºšúûï¿cbbž{î¹­[·ZYUç® &œ?¾²²²îñÑÑÑÑÑÑMvhfJDÍš5{õÕW?>hРšÇà24˜¿{{vûÔáÿ 9;kš“s«é±ï‡O~_ÞÌïܼؿ^~ú½·²Ïœ †QUVÜÚ¶áïèŽ{ööÎï[¿3Wbkë?bôƒŽ7òüÂw; #^’ö}úù>›÷=‘ð_¯>ƒ®|¶¨$M{ŒfëõíÿZ¾ýÞÝÿý7ãÐ^ÇɹÞñÝ=h¢}ûö=ñÄvvv …â™gž¹té’ž'2 Óµk×¢¢¢œœö¼¼¼æÍ›k’"ËÆÆFW K—.µµµMHHÐ$EVûöí;wî\÷øZ—¡ÏŸ??bÄggg;;»ž={9rDóQ\\œ··÷‘#Gºwïnggºzõjö£éÓ§üñÇùùùìUf???}&ëêêJDu#,*‹`æÚ}¨ó®©<ø•·‚_y«æ›öÁ?^SëHE˶]ã7ð2>²ä¥2?/yÓÚ¼ g‰a\"º„F½måàHDÊÒ’”m²O«,Ì—yxµ˜çZg»>†©Tj'÷þRÊæ¯Šn%Ë}üµô¡cÇ"“ÆæÅ#ïð{'kÒž¡e…)5ß‘ZÉeŽÍ]|z·xMjeÏkï"ÁáW˜˜8tèÐ'Ÿ|rÛ¶mÅÅÅsæÌéÙ³ç¹sçš7o®Ïé·oßvuuuqqaìѣǮ]»–/_>zôh}BØúôéÃæ°ÆJJJêÙ³g›6mxìØ1MÊÌËË›6mÚŠ+ÂÃ÷mÛöôÓOÏž=[©TnÚ´éüùóDT+§ÖTRRRTTÄ^†ž3gޝ¯oß¾}kƒÊ"€ kr}ñÒÊùªŠò®+6vYöMe^îå5‹Ù÷/¯Y\|'%bN|¯¿´~g®cí:kÊ»øRUEß]‹ûmsòUÏš5«yóæ{öì1bÄË/¿üÇ/Y²¤žSØ•žž¾zõê}ûö}üñÇšý2W®\Ù£G¸¸8ÿ×_ýÏ?ÿÔÕN~~~AAAPPPÓF>sæLww÷Œ5Š]¾páBÍååå ýúõóööމ‰‰ˆˆØ²e ¹ºº* ‰DXO¨íܹ³£££³³s·nݲ³³÷ìÙco_ûo#¨,‚éái‡[Ñ>ËÒæ Õ„%/e÷Óó.%u_»ÅÊÞˆ‚£&žš1¾"7[­TfŸ:ÖmõwìæäºR »‘²¢\UYÑbB¬C`h=‡ÕÚ±ÈÔyç¸&»ð]eômó¶«ß£­=‹s/]9üfYaJÚ¥/:¼ÇS§âdÈW]VVöÏ?ÿÌœ9SS] èÓ§Ï¡C‡ê9«æ☘˜‰'j~ôõõ=|øpRRÒÞ½{;¶cÇŽM›6-Z´èƒ>P*•………š#ëû»Vƒ***þüóÏ©S§jÒ›D">|xBB‚æ¹\ÞµkWÍ!!!©©©êå‡~P«Õ÷îÝ[µjÕàÁƒ>úØj„E0|?AÓ¾HR”¥Í Ô¨KÒeÙ™ŒTjëîÉþhçåCDåÙYªÊ F"±ólVóàûGþ¸ò°îØsýn"òê50pÔë•ù7¾]—ûïéfk/çd±‡‘Z]–™¼aÍõõ«ÃÆÇ4mvb&Ì…i"²wiݬÅëwþ]‘Ÿy‚ï¾Ä©i_u^^žJ¥òöö®ù¦··÷Å‹ë9‹PYYYñññ«V­êÖ­ÛØ±ckADÙÙÙC† ™={vttôõë×{ôè¡9F­V+ ''§”””Úè!77·²²rõêÕk×®Õ¼©T*•J¥æÇZË–­­­ËÊÊÕK§N4 \† âãã³`Á‚M›6Õ<aLÃcÉé`"/}ô¤éËèù©æ|·Þ奋1/Jˆa¾À ýó¢ÌÍS­T–ggÙºyQÙýt"²uóP+•j•ª,3Cæõ(/zõèÕû±=AØ­ˆlœ][Mû¿“1QY'{Dö©Û‹Ö‹ ™ HÔ,.jhÞá55ÚÈ›‘Z­e ­Yªç«Öÿ{vvv–H$5ßÌÈÈpss«ç,M„Ë•í}ëÝêÿñ¤fãxv­ÙÐy £J¥ª¬ÐüOæé­hÕþÆ·ŸW•WÞøî ×Ýl\ÜlÝ=Ý:u¿öU|yv©Õ¥éwÙ©‹µ“³ßð—nm]¯V©´|¬&µR©VV•fÜÓìXdöx½±8÷Ù9†ðÔ¾ Ñÿ{–ÉdݺuÛ¾}{UUûNjjê‘#Gê.ãÐJ.—/]º4==]sñ·î¶ÕçÎ#"///GGÇ^5°ŸÎœ9³¼¼<::Z3ÖùóçOŸ>]ÿÈûõëwðàÁ   ðÇé3r[[ÛÆV³²²RSS=<p¾cb­umÔ*棺oZÉíÃÆO ?MWãµZ“ÚÉŸøú§ºÕ³c‘Œ• ìýú±éµÞqôèÒ/Õwn-㖟Ѽ^?£“>§Ôü½nà/õšÿq4üoÕ. VYdõDÆXù¡™¯`•E9Ÿo­¼Xû¯;ßše06åôݶŸÃaü»è};ÿW'*ËËÒöî¾µ}c—eßèZç[+,ò]Y<4š÷ÂÜ~™\94z@¯å‘Æ…@þšq‚ˆ"G]ÖÿvŸE¹s+kYõ}uUå¹eE·••Å ïž!‘ŸXÛÖw¿ëÄ­ˆÈr¾g–+,*‹` NŠÆ&pRäÏÄä ºò"ûþç!¯­I"¢²)<…!F*µ’ÛûskÛ†â[7r“þIKü¥<;ËÊÞÁó‰'ƒ^ÏH­’7­-¾“rssBêÎï‚B[ÇÎ!¢Šœç?ž™å‚ÌӻńXE8Š: ßÖoÕÜ:GUUšz~ÙýäÍ—¾ÑFZϹ1‘?‹À£zòb-²5Iô0>nåm<™íW“Zî@ µ}ïc;Ïf%éw.,ùÈÖÕÃwèó¡¯M.¸r¡Öeè´ÄŸ[OŸmß<8u×–ËŸ-ê¾v o£ãÅ¡ÑÄY\´l|afp³€Lbe×¼ã‡Ù©¿•æ_ϽwÀÕO¯»eÌ B5x5ß æ(r‹ .“nlìK¯rÛ¦fi©mØSí‚í‚Ùä>>OȽpÆwèóZÏm6ðÇÐp"òòìíÿ~[‘Ÿk£pávx¼mRükÆ ®ò#êO0<õË0R[¿ªœ¼Ò‚d"‹¸µÚ(ß3Ô‚°üÒ¿¸X6%‚ó¥,vwh©­LjW½MZö™ãwù±43ˆTåevÞ:×ø°;‘TfGDÊÒ2©°(f/HÆÔü‘ý§oêwÒó_ÔjeyÑ"’ZiÙðÏ¢ & aÌÔßÇéÀAºx‰rrI¥"gjÙ‚úô¦¾}ÈÚ|þµ§/¥Ýxì™=yQ×Á4tÙ9iXDTïê­x½gQ³;4«² ïâ²Ùmâæ»uŒ$†¹ûÛŽ¬£íjŒ-'õÙI›§ M£µÜÅw|QV•¤&}ZU‘Ï0Rçf:Wô›£|ÏP—ùüÖ¨–“Csпˆˆ©yY[Óƒl:üþ‹Öo¤5+©‘Ûè‹\@89¹©””{Ÿn] [èè.š¿‹/56#²ø]ÝR‡²¬ŒTj‡ÀPb˜Ê‚Œ¿ImíØl\ÜJÓï9>°é³Á|©ÙTˆåѵiûÝhÚa$[7¯¾ƒ_Œ2Jì6žâ˽‹ëîßØÆ¾®*Ï+/º­¬*!büÛÏ9ñÑ£È!& Â"ŠMý|È«Õ*eÁõË–~$óðòî7Dÿa˜.^ãKIþ5ʯ~-‘ØXÛy¸øð yÙѽ#Šb¢q!,‚ ØÛ×xŒP+WSZ:6§5+Éáñ«°Í¼iÊ$4€…»:Ëû|µ jGâië'tñ(¿éë¹mqÒ+¨ᦠ´VËüGŒö1ºîûŠ–m»Æ?ú'Õyi‚æµÄÚF´‹E4•‰ˆ$‰µMÍ7*óó’7­Í»p–Æ%¢KhÔÛVŽDtzf´KD—Âä+ù¹£^÷èþø£Òb¤RF*uná^tëñÛ#Ì ÇOgÑ&âéßøkÜTð=ƒžÁh¸PwîÒÁÃDD±1µ“¢FËœu×HBFFw_"¢ªJ^oTF¬ÿ€I76:¨¡ÑIQ›K+ç[Ù;t]±Q­R]ùlÑå5‹Û½¿ˆýèÁ‰#æ­´q©o;èÒŒ{E·’½ú ú!¾ß³x ,‚‘q¡Ž'•Š||(B¼Û& o&ù†qÖ`£®2ë9»‰É&1›8 ¨£iI1=ñ×Ì#°¯Ã§| oæŸw)©ûÚ-VöD5ñÔŒñ¹Ùl@ôî?TWRd7'R«”•E…ž=û{õâýÉ4 „EšÖ+’ÜD¨k׈ˆZµ4¨®ñ8ß:Ô*ʽOÇ¥½ÉÚ†ž™hhƒ\ë¶cÄGE›C Šž½¾øûÚÚIQpý2#•Úº{²ïØyùQyv›m]ÝuµÃnNDjuYvfò†5×ׯÓäQ€¨ ,‚ˆ¡òò‰ˆ\œ¹¿¸ŠŒ+ÞªýN«Hze6…4u݇š99êaà¥g©ÌN³‘$ÉÜ<ÕJeyvûfÙýtª±Ód= œ5›Ù¸¸y÷ró‡„E³°µ²¬•ˆèmC›28Bq³aÇç!¯úUèÇðÈ؆›æPz ]9I?~J“WVo©£ýçkÈP‘¹ÅÉMŠ5ɼš)Zµ¿ñíç-ÞšA*Õï¾píЭþ›«©I­T©Ë²îg=`ïۜۀ!,‚H5%¨9+ˆˆrs9Œ ¦ÏM{lëœòÚ¼ˆön¤£iÉ>’H9q‘óŒ•ÏþßïC›õ*’v¸ÂyRdµž>ëÆ¦u'§G1ĸDt ‰š¤ÏY÷öì¼·g'1Œµ£Â¹UûàWë”»Àd!,‚¨}ò:éõËŠˆZ´ ýÒå«ü‡oì|‰6Òˆ­œ^›GÇvÓ«tju{Úh´ IDAT !q•ð8LŠ%i©)?|õ‚²¬ÔÖÕ]Ñ:¢åÄ8®¯éÌ“|?ëݯza¯ß3£ìýÄR0ã$)jÝTÈÆÙµUÌGu߯¹‹>퀆Z­fæÄ­"G]6öXšaDíáÖ*ÿÑëè'"é‹JK£¤ż ºì|·ÜŽDJT˜Kw¯é'ÝØø0ªr_ä²AµúßÅ:·nßyi‚µ£SÙýôœó§8k¼^ÝEñ€5ž Šº ,Bmþ^ÿ¡Æ£<ëiªÁ«®ì¹ÛZÅߟúö¦ƒ‡iÅ*Z»Šìíµsõ¹¹’{÷òMº±Q­V7¢÷zñ2_Ý”U”y›ˆH&oÄY&qCaEA^YfºïŒ¹ìÊ\¹_sùÃjŸ²¬4eëúìSG«JK-Ú„Ž›&óðªuºÖc”¥%)Û6dŸ:VY˜/óðj11Î)´Uò¦µÅwRnnNHÝù½CPhëØ9šËÐõl[íÚ1²ðÆ•Š¼"&ìÍE8ÇiAR=ø±•±‡æaŒ þädPdy'†®\£[·éíi4y"ué¢åq Ÿë9Äã|µ)+¦RQI¤Ô¡?·mŸ“³½`ò†Ï|‡<çfçí«ùèÊÚOÔUU?^kmïxkûÆ‹Ëgw^üE­¼Z¹¼f±²¬4bN¼Ìݳ$ý®DjED¡¯M.¸r¡æehú¶­þç¯sWX;9ß?´ïòg‹º¯ÝÂáÜ‘M—ÀW¢5I‘ÿñ‚%CXá 699Ñš•4g>]¼D3?$GGòó%++zð€Ò3ˆˆü|IádøP9ÁULܱ‚¿«~]”K·¨¬˜†Æ~H>!œô & ÓaîÊ»¿í¸óóÅwnZ;9Œ|ÙgðÈòì¬'ÿê¾n«Â…ˆG»÷û®â;)öÁšSµ“}öDö©cÝVÇ–!å>þõ÷_v?½žm«› níäLDn]z\Y·¤"?—íËpHЦN“…ìQ°¾À¼!,‚д–Ù¸¬®¹»Ñš•tì8ø“.]¦”RªÈÕ…úö¦~}¨w/²ô_{ÞçK”zåÑkkrö¢.OÑS¯Q‹.v""VŽ£^õºª²"óÈþk ñ2¯fR™1Ìù…ïj“ØÚ–çf× ‹eYu)¸v‘‘Hì<›éÙ{Yvf=ÛV[;*ª[¶±%"ei qÁ °yQ°¾„é,Â"/÷É1 õìA={pß²Á¸oü!3=kïþOßþ釢”d¯Þ‰¨Ã¼•laO+™»WÝcÊd¦þ´¹,3CæU'/jû½ÞÀ¶ÕõB†S$1öÀrMLÞ`+*¸bióåIeAÞï¾(¼yMYZRURœ–øKyÖ}§–mlÝ=Ý»o,;mìIÄ•E;µZÍ0 õD…èïaR4Ö#\ÙùŽñ£­w…èN“øÈÚóÊÚÏYA„„E0ò¢€= Ö—ÖÞÙ¼(dÂuFDDã–Ÿ!"‹*"˜(„E0 ÕyQ¨¾„é¨þ1˜ß|ـؠöÒÃ|ô‡°&C NHf3_=3"ˆÂ"ð¥ 1eE±AX¾¬ŸÑ‰}â"€éÂÖ9À»õ3:i‚#˜„EHƒ‘× D—¡@ ¸ `ŠPY!4˜QV'„Eà]ݤˆ[LÂ"ð IÀ¤!,êIŠ5##®Aˆ¸_ô¯)ÆÆÆò?h T€ú$Å q5ÿâ„Ê"pOÏš¢Z­·üŒÙ<À,¡²Ês‚°\jlRDŽ9„Eà jŠæa¸¤`–€HŠæ «¡Áô0 ÃG³¢]“+þù")˜1„E0£Wg7½Y$E ܳcÓÆ¸ågêÙËiÄpúêsrs¥´4Zû¹`=e¾AíhX4ÑÅ£MoIX‹`4BGFšò6Ñþ?éÁáú}HÈùºûUU6ñt$EÐ@X#42öíMr9©Ttæœ@=Ö!Ì|o&ù†5å\$E¨ a„¦5y% !"ºu‹÷¾r¾jå¤Óo_ÑÞdmCÏLlt HŠP ¸€ˆ±„]%_Àczãj¾+ÞªýN«Hze6…D4e<5!)¢™Ó³|Õ­ñ§èÄÚ¿‘Q­&"b˜†Ž£7–æú¸áó lC ê×…9”žBWNÒŸÒä•Õ[ê4 ’"Â"ˆ_A-/ŸˆÈÉ‘—Æ `È|Ÿ›öØÖ9å%´yíÝH FÓ’}$‘6ºAÄDÐÀ=‹`IT*J¾ADdì¡ðÈVN¯Í#Gºs•NíkôéHŠPÂ"X’CG¨¤„$êØÁØCá—DJDDw¯5îD$E¨—¡Íœž¿û¿¨±Mµq¡w¼^M5xÕ•=wCœ!cy܃lZûÑÀþäîÖàáâ:«Ù¹ ð|•U”y›ˆH&oÄYHŠPÂ"AýɉûÈRRBÒ7)7—||hrãw”1ŒÀó-+¦RQI¤Ô¡?·m€ÅAXá,6múžvÿJDTQAùtï©TDDÝ#éÝwH!Ѓ¡ÄÕ|w¬ Äïª_åRÆ-*+&†¡±’O'=€åBX¡i-³q\]»™RýB&#ŠhO­ZÒ€þÌe/ú`¾©W½¶¶!g/êò=õµèÂa'`¡ÁÈ8މ߭ç²5p;ßøC6 Â"¥-§°´ù€y@XA ñ@?1±´ù€ùAXAYZl²´ù€ùÁ¦Ü Â"è„°:!,€N‹ Â"ˆšZ­&"ê7ÈØ;ß1~ÆÀC‹ Â"@SÈd¡ õ@X±úJôÃŽªûœÀW¢5k¾ rx‚ ˜µZÍ0Œ?ã&'v¾Bü@TÁ4™fÄœ,m¾ Z¨,‚ɰ´LcióqBetBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ at²2ö  ÃðѬZ­æ£Y03‹"ÅSF¬Û>R#Ôa@Œj&Å­wyébŒß£¾@„EÑa“"OQƒmŸŒÈ‹  ¸ˆ‹0IQCÓßW½ÀD!,X:Á‚)˜"„EAyÄa@tPêñ@X@'„EÐ û,˜ƒ3бÝtí4å? •’îÜž"‡Qä0²²6öàÀ”!,˜¶¼,Zù]9IDd¯ ß0²¶¡œ :¹‡Nî¡mKiþnrö0ö(Àd!,ð(m{"òyé"OíåÑì‘”™J>¡5‡"úóðÖ’ÌTú}=íÛD…9‹Ðt¸g€GlLLÛÞ†MœûæCÊL%¿´àgêð䣤HDž5—æï"{=€¥@e@ œWÓoÒñ_‰ˆÆ/&{'íÇGpÕX(TÅa•ñt"©UäÕœZErÒ€‹üÒZJä$2¦üKDÚÑÀfꃰ`4FÆ‚l""'7ÎÆP£V«=ÐŽ§% Nl’aÒûÙпLÿ¡¡oRÔ\C{ãGD„ÿ@]¨,ˆBªŒlM1ÿ—cà¬-0‹"rïÇÖ÷~l­çÁA툈’ÏrÖ5ñ¹Ë˜(„EñuÉwÔ%=î4†îߦË'8ò"h`ŸEÓШÍùÆ-?£y½~F'}Nù"ô Íë‰Éôï«®ÞñÝ5¯¼sܦÌIƒñëá?bFÿ6}B(rÿ•¾ù€æï&¹£–cn&‘³¹zëßjµ´ímø{ð ˜TxWRôyéb“cÙ›‹Éßî^£Y#(é ©U>ÊL¥oçÒìg©8_¯¦êV4Q_BeÀˆ /Ý9¸Ðü]´"š®¦Å¯½‚š‘• ådPf*‘w9º6b<µ"ß϶ñCXà—Öú‡ñËÅ‹æí¢3‰tìgº~†î\%•’9”º§nCIÚ˜?åuó"á’4€eCX©‹a¨óSÔù)nZcGX·Äˆ¼`™pÏ"€@ ¹7Qxu‡Š[,Â"4÷ü™PLÔ@^BXà•‰ÆD ­y‘À¢ ,@}´æ]äE˰ C^°X‹ äEË„°úÂ-ŒaAëzäE3†° "jµšˆÆø{õÂ’‹‚°M¼`!,]“ ™¸…À ,ˆ‹ÀW¢5±ý6na0{VÆÔ¦V«†òÎŦ%E›kÄ´ím|tMÚö6¾£.5¹_0W†üÛ|@e@Œ„ü}ÉI_¸…À\¡² R&W_ñyébcë‹÷~lí;êÒŠ+x˜†ØØXc´@e8ƒ%/æa¸ÔØ]ïýØšç€A€{¸…Àl ,/êÏ‹5_òýJ 1@ã!,_p #€@Xé¹k7Š‹¢…°üÒºäLÂ"¡Á¼ˆâ"€8!,€@P_0E‹ —¶ ¸ BxÜð+ LÂ"ð¥ q”ïW?Þ›ÀÇ` iptBeøRkE‹ž…FDaÒ„FÇÆÆò6#[±b…±‡ „E0ßQ—¨FlÒ¬†åûû‘cs°‘Q$É)Àä ,€X°WŸkfš¾Ûöo8ü:4zÅÆÆòžD’5„OÉ` „E0= ÃðѬZ­æ£YÃYÚ|YfYìÀk^aò,%W°Ló‰¶ßX–6_–ØÊ`æ¡ï¶ý"IŠTc0øg `*PYÓðX¦9˜ÈKýiú2zÕ­æ|·Þ奋1~ú2ú|kO²1iHcÀ „E0Õɉ§Œ¨Á¶ßo;?±óå)#j°í³‘Q„y¸‚ä Âeh;’¢ÆÃŽŒu}V˜¤¨¡éHl×£@$ê,˜Šƒ`ÁLÂ"ˆš¥•»,m¾ ~¸gLJ}`F,s?,0]‹BàûÒ¦}¤FàÂ"˜¹½Ÿ“ô1‰­›‡WßÁ/FQ#mŸù`’Ïàg½û ægŒ`þj&ÅÈQ—ùèâÄ­4}!/‡Àüù>ý|È«Õ*eÁõË–~$óðòî7ÄØƒ Â&Ež2¢Û>‘C‹`^^Gwî<öŽùùR¯žôÒó$—iX¼;óÛM×NSþR)IáNÁí)rE#+kcN b¤RF*uná^tëû¶²¬4eëúìSG«JK-Ú„Ž›&óð"¢{{vÞýߎªâBÆÚÚ«÷ µJY|'åææ„Ôß;…¶ŽcÔÉ€‰&)jDŽºŒ¼ÜBXsDÎÎDD*egÓõdºžL µ+ÉÉÉØƒãX^­|‹®œ$"²WoYÛPNÜC'÷ж¥479{{”¢Qšq¯èV²Wßê«ÉWÖ~¢®ªêøñZk{Ç[Û7^\>»óâ/J3îÝüá«ÎK¿”û(ËËJîÜr /¸rÁ¸—¡ñ0eП&/paÕ;¾;yç8¿Ý¼ö õíóèÇk×éÝèÎú~ ½ý¿]?ŽïùåÑì‘”™J>¡5‡"úóp;¬ÌTú}=íÛD…9‹”¾ÿYGÿT«”•E…ž=û{õ@DåÙYNþÕ}ÝV… Žwï÷]ÅwR¤29‘ºèæug7+¹½ch¸±‡_ yÑa?,0‹ ¨#ïïß] È¨Ñ"ŒF½@_­§3gêñ!¾çû͇”™J~-hÞ.²¼fê@Qs©×sd¯à¼[ÓãÕk`à¨×I­.ËÎLÞ°æúúÕaãcʲ2ˆaÎ/|Ws˜ÄÖ¶<7Û5"¸U̬´ßw]Kˆ·xþ?nºqð5!/š(Á®AðaŒFÐÈèéIDT¥¢/8ŸoúM:þ+ÑøÅµ“¢FpW½™6‰­­³+Ù¸¸y÷r󇄰ñ12w/"ê0o¥µ“s­ãÝ»ötïÚSUYyÿÐÞ‹Ëçôüú§Æ®žæOll,!2€`ð02Má_W¯5ལ†p8ßÓ‰¤V‘WsjÉI{fMMj¥R­¬*͸—yô€½os"²u÷tïòÄÕ/——ggQUqaÖßÕJeiúÝÜó§U•kkk'Ã0ŒDjãâVš~§¡n„ÃFF=ý»èýäMk¹êúßEï=àÐèG^zêÝ ™ÇþÔÚ‘æ°Ã/:1eì­í›‹-€OŒnmÛ¶Õ³‘5kÖhβ±± 5kVyyyÍcöìÙóä“OzyyÉåòààà—^zé?þ¨¿Ù'NŒ=ÚÇÇÇÆÆÆÝÝýé§ŸÞ±cûÑÂ… 4GÖú±É8ðÉ'Ÿ4xX=« •E{e¶Ö›|UUjÊ~@ÓO»ÉښƼÄqûzào¾)ÿ…v4¤ ÞõŽï.ÜýºÝÛ³óÞžÄ0ÖŽ çVíƒ_­¾u5|òû·w|wn^le~žµ£“¢U„{dUeÅ­mJÒR‰‘È<½Z¿3Wbkë?bôµ/—§%þâÜ¢ýGŸw:,#^’f·"RU”§ýñë•Ï9†Ê}üu†‹@Û·o×¼ž0aBXXØÌ™3ÙŠÆÝŽóùçŸûùùìØ±cáÂ…EEEš?këׯ?~|ß¾}.\¨P(RRR~ÿý÷ß~ûmàÀºZ[³fMLLL«V­¦OŸ˜ŸŸ¿ÿþÑ£GïÚµkøðáµöôôlݺu£F«ÕÖ¬Yóþûï×sŒþCXá,2ÎYPûˆv4é- oihËœ2p¾ÙDDNnŽˆFÏ‹í>Ôù×k©<ø•·‚_ylÙ“}@pÇ×Ô:RѲm×ø ¼ŒÏ†äÅÊü¼äMkó.œ%†q‰èõ¶•ƒ#)KKR¶mÈ>u¬²0_æáÕbbœShuµ 1R©ÔNî?ü¥”Í_ÝJÖuíXÀ‡_|QózÊ”)>>>5ßi”~ýú…‡‡ÑË/¿Ü¹s篿þZó->>¾mÛ¶û÷ï—J¥ì;ï½÷^EE…®¦þþû˜çž{nëÖ­VVÕ¡k„ çÏŸ¯¬¬¬{|ttttttÓ†Ý(Â"ð¨i×[9ˆŒ¡!äâRý:?ŸîÝ£óè›ôá{äRûî4]z-âú¸ÁóÍ­tÚgI“%ir^¼´r¾•½C×Õ*Õ•Ï]^³¸Ýû‹ˆèòšÅʲ҈9ñ2wÏ’ô»i}¿&2P«TÚ“b µv,ؾ}ûæÎ{öìY›>}ú,Y²DÏêÃ0]»v={ölNNŽ««+åååuèÐA“Y666ºZXºt©­­mBB‚&±Ú·o¯õø… ~òÉ'EEEìçÏŸÿè£>\^^Þ©S§O>ù¤wïÞìGqqqßÿýöíÛß}÷ݤ¤$__ßiÓ¦M›6ˆ¦OŸ¾jÕ*z¸ß××÷îÝ»† aDÊ  öêØÇ¶Î)+£/¿¢Ÿ~¦wÞ¥o¾$‰oÕmÂ|ÙšbþÇÀm¼CdäI–¼”ÝOÏ»”Ô}í+{" ŽšxjÆøŠÜlµR™}êX·Õß±›“ëJìVDÊŠrUeE‹ ±¡õVkÇ"S÷EèD41™ß2s^ÚÁì;¿>8WYþ€Ô*+[W×¶®~O¹ú f$Øg¿q‡úä“OnÛ¶­¸¸xΜ9={ö½¸/ØùÐçà vtt%s´Ðî£5˜öŒ~UÚ\5ªÄX–ÉH¥¶îžìv^>DTž¥ª¬`$;Ïf5¾ä+k³¯{®ßM·"ª,È¿ñíºÜO7Xû¾+–Ö‹š6;ñ˜˜¼á‹Ð7ø‹Œ•e®›^øà4YÙ8Ù9…H$6¥÷sî&æÜM´µ_ÝfÀfk™;çýŠ'ßó¬Y³š7o¾gÏ63õìÙ344tÉ’%ëÖ­ÓuJIIIQQQaaáöíÛ÷íÛ·nÝ:Í~™+W®¼ÿ~\\\\\œŸŸß€^{íµ'Ÿ|Rk;ùùùAAAMùÌ™3ÝÝÝ8`ooODƒîرãÂ… úé'ö€òòò„„„®]»QLL̆ ¶lÙòôÓO»ºº* ‰DÈÉÀAÔþšq‚ˆè Á I$ÔÌ› èöm"ñ†Ev¾SFëup§ôÃBº›.ŸtAtcdÝ%>(1òDÿ¼(sóT+•åÙY¶nDTv?ˆlÝ<ÔJ¥Z¥*ËÌy=Ê‹^½zõ~ìæ}v+"g×VÓþïdLT։Ñ}¨­;2A±á<2VUä_Ü?¶¼øŽSp@Ä{ÎÞ½4ûì—ß͸þÝýä-Uå¹– æeeeÿüóÏÌ™35Õµ€€€>}ú:t¨ž³4¥;"Љ‰™8q¢æG__ßÇ'%%íÝ»÷رc;vìØ´iÓ¢E‹>øà¥RYXX¨9ÒÙYß»ž´ª¨¨øóÏ?§NÊ&E"’H$ÇOHHÐ#—ËÙ¤È IMM5¤S]Gõ¤¯º²ç238º#O©¤ôt""™LÏ3þšq‚ÃǪò1_ŸŠFÇ¥o> ù»Iî¨å˜›IäìE®Þk“4¡Ù;¾{¯å‘ÕŽèÌ‹*•ªòÑ=ø2OoE«ö7¾ý¼Å[3H¥ºñÝ®ºÙ¸¸‘[§î×¾Šo9i¦­«{iÆ=F"­k±vröþÒ­­ëÝ»öbêÞà¡&µRI¤.˺¯Ù±ÈüpožW^|ÇÎ)¤Í€ÍRëÇvOµµ÷kÞá÷€g¤6æöÌR=5í{ÎËËS©TÞÞýGÐÛÛûâ³¢wž IDATÅ‹õœõÃ?deeÅÇǯZµª[·ncÇŽ­y@DDDDDegg2döìÙÑÑÑׯ_ïÑ£‡æµZ­P(œœœRRR5fVnnneeåêÕ«×®}´ï•R©T*mìèøØ÷­­­ËÊÊôi¼±CX#¨?9q_p*-¥Ï¨ $êÞãÆõÀß|ß\L7’èî5š5‚¢æPû>Z÷·øw½Â¢Öplà}N×zù[_š¿‹VDÓµÓ´ø²WP³ ²²¡œ ÊL%"ò"ǦÜW]ß9_$¾Cµ•ˆ^Œá¶Y½Ÿ“ôIlmåÍüžÿÖk¦¬3Lòü¬w?A×í6j‡í&4¨kó V1Õ}ÓJn6~ZØøiº¯ÕšÔNþÄ×?Õý¨ž‹Ì˜!‘17íOR«dŽ]¸— 30šËd²nݺmß¾}Á‚ì•èÔÔÔ#G޼ùæ›úô.—Ë—.]úÒK/%$$LŸ>ˆ’““CC[ÑuîÜ9"òòòrttìÕ«ömN3gÎüù矣££kîPCDì55¯w×y¿~ý<øé§ŸÚÚÚê3Úšlmmë¯26j`‹ 4>ÖLÔv³FiÝÚšÜܨ×4òjÛ†Ë^ôÃ÷|]¼hÞ.:“HÇ~¦ëgèÎUR)IáA‘C©ûpê6”êÝù¤)xJldä »;´²¼,mïîË«Ú/û¦ÁÝ^€oŸ‡¼Nk’j¿ó0˜´¦EÆâÜ‹DdïÚŽ—1™#=¿çùóç2dÈ!“'O...ž7ož\.×ì×Ý ^x¡cÇŽŸ~úé¤I“lmmû÷ï6tèР  ¢¢¢½{÷nÞ¼yäÈ‘!!!ZOïÑ£ÇÊ•+§OŸÞ±cǨ¨¨ÀÀÀ¼¼¼lß¾}÷îÝõw½|ùò^½zõêÕkòäÉþþþÙÙÙ§N"¢¥K—68ì6mÚ”——¯ZµªG2™¬î†8Â"Ç1ñ»õ\¶Æ>Vu0 u~Š:?ÅyÃÀU‚äë.F†©ÔJnï?rÌ­mŠoÝÈMú'-ñ—òì,+{Ï'ž zy<#µJÞ´¶øNÊÍÍ ©;¿w m;‡ˆ*rœÿxfþ• 2Oïbáø]zilê­*Ï!"k[.÷Ù7ƒäÝ #ã AƒöìÙ3wîܱcÇZ[[÷íÛwÉ’%zî›CD Ã,\¸pذaëׯŸ4iÒ²eËvîܹnݺ´´4†aBCC,XWO S§NíÚµk|||||üƒ E·nÝþûßÿ6¬þ®#""þù矹sçΜ93??ßÃãK—.z^•9rdttô‚ rrr|||êî³Ø¨1ÞÂÜJÛþ¨ æóR}·âÖ2nùÍëõ3:ésJÍÿ x›vÍ|P€Ð'6UïVp0Ñ!5E¿ADÄÉŸŽ&Ìw«–?ÔüãGÄÑ|µjTjükƉ¾ÛösØû¿‹Þ·óõ}m2Ý?œxeÝ’.KJî¥:·°ólV’~çÂ’|?ë;ôyªsúôÌ誒¢ÖÓgÛ7Nݵ%ãàïÝ×nápl‡F ±õ ·ß''ÀÖÍÞ¤‰(rÔå¼rh\þý¿½[D5ïðáýžø±=,ÖZ¾÷¿´X¨,‚ ,mÏK›¯Vz&EöžEÎïÞci6‘–ÚØ†½1Õ> Ø> ˜ýHîàóÔˆÜ gذXW³Ï8††‘ïgoÿ÷ÛŠü\…‹Ö#ÅI„I´²²u%¢Ê²lcÄ„ ³eºBXAYZl²´ù6Á_3N4ùéÆúcw‡–ÚʤvÕë³Ï¿ûË¥™éD¤*/³óÖù$v'B"’ÊìˆHYZB&EkÒµþѳU0‰ë]ú\Þe#Ë$f£žmÚ»´ÉNý_qο† ÌÂ!&òax¤«¬X½¯¤PO¶Öìͪ,È»¸lv›¸ùn#‰aîþ¶#ëèŸÕŸãaÛúÄežj®Ð &ŦEŸ~©IŸ–¥fâjA´y„'ý£9ða%†j«²¬ŒTj‡ÀPb˜Ê‚Œ¿ImíØl\ÜJÓïwx†cÓgƒùR³©Ë5¢k“÷»)L¾rû§ ®^P–•É<½Ý»öôþ’µ£¢i­™.C"‹Ì1ÈÕpÎßSNÏm3`‹ÔZË>ûÅ9¬íî¯Ý dIa±ˆ‰‚AX^ˆgqÖj™ÿˆÑþ#´<„[Ѳm×øG¿:/}ôV‰µø‹4úP‰DbmSóÊü¼äMkó.œ%†q‰èõ¶•ƒ#žíÑ¥0ùJE~nà¨×=º÷­>A­¾þõJ¯¾ƒÙõæD$÷ ;LáÖCÃq›W¬lœ[÷ß|ýXLQö¹«‡£­lœdŒÄº¢ô~yñ]"’94·²µ [fyæ ?„Eà…b¢¥ád©Ð¥•ó­ìº®Ø¨V©®|¶èòšÅíÞ_Ä~ôàÄ‘óV²Ö(¹—Z–•áÝoH톌q÷'ß8ÜeL;Ï66ç¦ý™ú[QvRIþ5R«¬dn®~O¹úqõÄH,÷7b¢±Xî¿s`Ôj5Ã0Ôo¶Z4v¾cüŒ°Õ"˜º¦%ÅôÄ_3üÁ¾Ÿò¼™Þ¥¤îk·XÙ;QpÔÄS3ÆWäf³Ñ»ÿÐZI‘ˆ* òˆÈÖÕÝ Ñ›MRä?²0.>ý]|úóÜ‹Ø ÍAO‹¦Í‚¢gï/¾Æ¾¶vR\¿ÌH¥¶îžì;v^>DTžÅfD­‰ÐÆÉ™ˆÊshö2cˆ,‚0šCÃêè7ÈØ#Ô; ‚ 0ðÒ³TfW3äÉÜ<ÕJeyvûfÙýtª±Ó¤Ö+Ërß™‡÷ýÃûœÂZ=öZmfW¢‘Z†/\<ô]û`,Õ;ô àvd¬Ù~ pšŽLb'd¨…óýÌe^Í­Úßøöóª’⪢Âß}áÚ¡[ÝKÏa˜°7§gü¹çÆw_”ÜKU•——¤¥ÞÜüUæÑÜŽ , ’¢¨ ²&àÑ‹ö(X_Z{gï\²Gá:ÜÙÿ›â=`h³þCEÒWxzòMëé³nlZwrzCŒKD—¨I žâÚ¡k‡¹+oïüþììiªòr™‡—[מ.Ül+ F‡°¦¡:/ Õ—0Õ?‹šo£”¤¥¦üðuþÕ Ê²R[WwE눖ãøèèÌ“|?ëÝo0û£ß3£ìýšóÑQp’µn*dãìÚ*棺ï×ÜE¨.ÇÐð¶3>$!„E0&—i dióÕ—Zýïâ[·ï¼4ÁÚÑ©ì~zÎùSÂôìѽ0ÕO€GiÔ„°¦¤¢ ¯,3ÝwÆ\ve®Ü¯¹üaµOYVš²u}ö©£U¥%ŠmBÇM“yÔ~Ð…Öc”¥%)Û6dŸ:VY˜/óðj11Î)´Uò¦µÅwRnnNHÝù½CPhëØ9šËÐõl[íÚ1²ðÆ•Š¼"&ìÍEx;n§¤hrØ«'~l9ê²±ÇÐD‹`Jlœœíý“7|æ;ä9‡ 0;o_ÍGWÖ~¢®ªêøñZk{Ç[Û7^\>»óâ/j-ÈÕzÌå5‹•e¥sâeîž%éw%R+" }mrÁ• 5/CkÔ·mõ?u˜»ÂÚÉùþ¡}—?[Ô}í玤FÕÐ`R¦ÃÜ•Îm:ÞùùÇSqã¿=&mïn"*ÏÎzpò¯°7§Û(\+«ÀÑãJÓïßI©yªÖc²ÏžÈ>u¬Eô;2/b¹¿Ì«Y=ý—ÝOÏ»”úú+{kG§à¨‰9gOTäf³Ÿ68ÜÚÉ™ˆÜºô(Y‘ŸËÕ¼‘A'~lÕðAzCeLŒ•ƒcà¨×G½®ª¬È<²ÿZB¼Ì«™TfG s~ỚÃ$¶¶å¹ÙöÁšwʲ2êSpí"#‘ØyÖk*ËάgÛjkGEuË6¶D¤,-!…=É´øJ´&)â¾gà Â"˜*‰µwÿ§oÿôCQJ²WïDÔaÞJ¶°§•ÌÝ«î1å2SÚ\–™¡¥ ¨mAzÛVh£É‹Bö(X_`öpLIeAÞï¾(¼yMYZRURœ–øKyÖ}§–mlÝ=Ý»ßô›tüW"¢ñ‹k'EàC{á|ëD”!L Â"™ ‘±oo’Ë©¤„Μ£§ ÑcÎ÷t"©UäÕœZEÞ˜ØaûáiÍõ< ŽK ……ݺÅ{_ñ7ß”‰ˆB;ØŒõ?¯IÀ¢ ²""D•‘]%_Àcz3p¾ÙDDNnŽÕD¨ aÑÌé[¾š4Uóò¤a¯0Z×èÞÇoddWT0Lƒ¾±ì´ÅNƒç«ÇTôRÏ|,Â"ˆ_A-/ŸˆÈÉ‘—Æ Ð„ù²5ÅüÜF1AÔÞXvšˆ6P7Í©T”|ƒˆ((ˆ›¹ÆÎ—H¯'&µ££»(ù,/#AL¸€¨mˆë¼!N¯ä¤—CG¨¤„$êØ³69Õ¨ùvH C÷oÓåÜt;À¨ •E3Ô„ßô_„¾¡y=1yƒ!½÷Žï®y}äãºkðª+; .Ÿü ›Ö~AD4°?¹7¼*dC\g·Œæc¾>!9ŒŽÿJß|@ów“\Û¥õ›IäìE®Þz5ˆŒu!,‚ÔŸœ¸,%%tà }³‘rsÉLJ&Oä¸ý†ð7ß7Ó$º{f ¨9Ô¾–Çý-þ]ß°PÂ"ˆg1qÓ÷´ûW"¢Š Ê/ {÷H¥""êIï¾C  Ý ÃçëàBówÑŠhºvš¿Bö jDV6”“A™©DDÞAäèÊÁPÀb!,‚д–Ù8®&ÞL©~!“‘ƒE´§V-i@ æ²ýð=_/š·‹Î$Ò±Ÿéúºs•TJRxPäPê>œº %)þ”€ðkŒŒã˜øÝz.[ã÷2 u~Š:?ÅyË`<–¶œÂÒæ æa%ÄýÄÄÒæ æaei±ÉÒæ æ›r€N‹ Â"è„°:!,€N‹ jjµšˆ¨ß cD ì|Çø{!,€N‹uXL!“…B&ÔaÄNè+Ñ;ªîWp_‰Ötd¬ù€Èá .`Ôj5Ã0BüŒ›œØù YðCR]PYÓ dšCr²´ù€h¡²&ÃÒ2¥ÍÄ •EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐ atBX@'„EÐÉÊØ€0 ÃG³jµšfÀÌ ,ˆO±nûHP„E1ª™·Þ奋1~úB^]D‡MŠ!AOŒ¤À6F˜„E“NNîDDeTMÿ¦ GéçuÔq½õ)9{{|`Êx”¶½ ù¼t‘×^^ˆ¥Èa~,-¤£»èÇetv?ÍyŽüLNn¼öæ ÷,ðˆ‰iÛÛ°©QvŽ4ðUúäwrö¤û·éÛ¹‚õ fa@ GF×fôÚ<"¢c?SN†`Ý€¹AX”‘1r(Ù9JI Ó!˜!„E~i½aQ˜È(‘V/ˆ¾s•ï®Àl!,‘‘]ÚR”Ëk'`ΰÚ4ð)F,欯mþœ5e!x]1­V1 m€E@e@xª2äÙ;ë;ÎÿÏÞ}4qöqÿ…0ÂÞK¦ˆ¨ "¸qokmmÕÚjíЪuánÝ»¢âÖª­ÖúºkÝ«*"*JU¬Š”!Û°G€Œ÷Ó4 È„ïç¯p¹Üó\òÓ|óÜÝsº#‹Z$åˆ/]§'JÙšP@‰‰ˆÜ›ÉÛ´z&†‚‘E-â2ì‰Ë0å$E"Š>G%…¤Ç&¿NнCŒ †‘Eí¥ÎÑŸ½¿?·§6›êÖAüøúôÛµÙT]Rmüzÿq+íìœ Ú·„ˆ¨ó²vTøå©Gý0¾„‘E5¨:)6øô±rcYI!]9@sûQv:9zÐèEr½ªâˆ&Æ€0² AÊʈÇÖÓ¥}DDå¥TMi¯I$$" èIß­!sú#q # ,¨V¥ãsÊ_IÏÞ=02!S òí@ZQç!äá«ð¦*æEÂ!i€ú a@­”›ºÂ®)qcï0=¬8Ĉ¼P?áœE5Qú¹‰*U±«8… ~BXP!ñ9:Å€TJGc¢X¥y‘ ^AX€ªTšw‘ê„E¨ò"@½…°rA^¨Ÿ@^8… BXTz½ò"@†° ED"pÕt?ª„K^ê„E¨ äE€za ¾«ñ@&Na¨´‹šD‹bÚUNa¨óô5Ý&‰X,–:Ï\¬YRd0yQ* ¦õ«öÖ5©Gý\†=©q»PWÕ¦@0² Ôù}©”¶p #@]…‘E-¥sã+ >}¬èøbÊ_—aOÖ¯_¯â®n Ñt Y¥Á%/uÂ"(“¢³0¦ñUq V@ùp #@°*Qu^”|<Ìe—šúŠCXUÁ)ŒuÂ"¨œ³vcp@k!,€jUzÉ è „EP‡jó"´Â"¨ ÆtÂ"¨Iµ—¶`p@ áv r¸@w!,€ªÔ #sÙu$e¬*:5ƒÃÐ F@U¤®h‘s ƒ‹ZaÔ¤7Œ QYw4lýúõšî€\@c\†=!‰Ø$¾z˜Ë.æ©:ŒÉÁꌌZ’¼‘’tÂ"h æè³d¦ézøŠæº£Z׆÷$¢U‡'-ɈbêOÉPK‹ {X,–*6+‰T±ÙÚ«oû˨Ã1‘Áìàµá=Ušµ0y«-%€²àjhЬ÷ttûŠªoûËжa°º¡ëá+Z’I¢3ø¬tFA7ü'ÓD\RIÝz‹ÛÒø¨›äþz£’&F¸þÛ–Æ÷WŠö$†4J°:à]rRQFc¶ß­7i:?1û«¢Œ(ÆlŸ‰ŒZ˜AY¼ –p´š’¢Øû†4u|V=IQLܶ-°PÚ‚©vP[0]„°Z­¾ wÕ·ý퇰ºC}‚ \ÔJéÇp¨Â"ÔqVÎÍ~p‡ˆXzzF¶öŽ]ûz~2šü¶ŽùaBƒ¾CœºõUM¡^P鴩̤FP„E¨û\úÜhÔx‘Pÿòilè|޽£S·~šîÔ/’I±ý°§ÊÝxô‘fâVAé¡nõ5%'ÿg‰±1¹ºPPgúôc21ÑP·TezWJ÷˜Å"#21§ÈËŸ:}Hž~íœVa‹Íf±ÙV¾þÞM Þ½k^ÉëC»¹woòKŠ-}ü¼¿žÂ±w$¢”ó¾9{Œ_TÀ20pìÒ[$%¿~u`gÒŸÿ3kèí²H£;º‡IŠJψbÌ–™Èˆ¼J‡°u‘WC²²"" ‰Ë¥—qô2Ž.‡ÓÖ da¡éÎ)Ÿ{S²°#"*ãQ>—ߢ؛tjô¤ïÖ•ƒ¦û§MJÒS ⻾;šülëO">?`ÅVS󄣿=^·°õªŸKÒS^íßÕ:t‡IwA)¯89ÁÜ»iþ³X͆ÆÍ”u—ª“¢XûaO‘AA­º„u ¢ëÓo«¶™/¿ ®Áÿþùâ%Íú’“éiâwªmú¿Ô³¿CC¨ýÀÿ,) ›'èÈZº…}DËN‘…­JÛ×iWÎfݼ* Ê :÷p êID¥Ü¬·ßè°í¡¥5yÿ:剢ä×lŽ ‘¨ðÕKC+[}Ss連îþ;È‹P-q^P"LjÅĦ.a˜¥&>iØP"¢˜ûêk”ˆ4´¿ÆæÔkýt¬(#‘~_¬¶–µ—cP¯Ö¡;Û¬ù%`ùæ’ô”—»7/+X¬‡ËgÝ s'dÌÝ_ë•æp9Nͦ.H¿záöøa÷çOæÆ¨ø·"p»gƒÉS¡ÀÈ"hŒšFDD|:Ú’A­ûKdãL_.¡(êœG6NêiVKéZÙ‘¡µ­S·~¯öïlüÍTŽ#µZ²ÁÀÂJj}»¶íÚv–—g\»øxݢοWôêiÕaò"†upœÑ IDAT‹ŽA¨FAÃÔ4êöü‘‡»ÊªŽ:GÛ c3 èñMõ4¨ÅD$D~IzJæÍpS"2²s°kÓéùŽu¥Ü,"âdÝŠ %iorÞ–—éXX²X,–ÛÐÚ¶$-¹ºfÔG¡!ÆG+çÆíݪ¬¦­œ{mxÏkÃ{^5à™QW+mH¼Zäg½£'L8º—p¨K¶æÍ›Ë¹‘-[¶ˆ_ehhèíí½`Á‚ÒÒRÉuΟ?ß½{wGGG//¯O?ýôòåËUo6::zøðá 4044´³³ëß¿ÿ±cǘ§–/_nff&^SêÏ ÿé§ŸªXArOMMM6løñÇÿñÇRç¼bdÔíúôÛÓ’ªFÝ„"â¾¥ˆH:~’ hħJÞ¾Ôº¿ÿ¥Ç&O?zMÉÏUÚNUº„uPÛ`jRÎÿ™rþOb± Ì-­šµôõîÔÕ¦ßÏM<¶ïŸ%!åy¹æ–ÍüíÚ ËËï)NM"–ÇÁÑwúb=##·ÁÃ_ìX—zé´¹—OËùk4»; žÂÈLE$,+M½|æÙæ•fžÞ& Üd­†‹@Ž=*~,//¯¸þ¸qãÆW³n×€xO‰($$dûöí'Nœ3gÎÆ™…‹ B5;Þª„å݈¬­ß=ÎË£”zK¿þF?Î!ké³Ód Z×^=Ç‹U™# <ÝŽXUóùšõJóâ“ KõMÍÚ®ÿM$>Û¼òé–U-æ®$¢§[V x%þ‹Â8vÅioôØU}MdÞ  …•'E R3騯×Å잨é^Ôªx·ÿúë¯Å‹ß¿ßÐÐ088xõêÕrŽÞ±X¬¶mÛÞ¿?;;󮮠ˆrss[µj%NŠ CCCY[ 522Ú¹s§8)2Z¶lYéúË—/ÿé§Ÿ ™?>|8þüÈÈÈÒÒÒÀÀÀŸ~ú©K—.ÌS3gÎüßÿþwôèÑY³f=xðÀÅÅeÊ”)S¦L!¢iÓ¦1i¹ÊÊÅÅåÍ›7òìï„ þüóÏ;w®ZµÊÄÄ„AkÕ*¨ùŸ©sx<Ú±‹ŽŸ¢é³èפ§§êª(˜æg™Ê—+öA¹ñ‘QEjpÉ /#-÷Ƀ[ꛚ‘×èñwg|S–à ܻQí6íc&'—•™©ˆe¥Âò2Ÿ±!fžÞU¬&5c‘Nûz] ©.2>8?€Wðúý_,¶¾1ÛÀœcÞÐ̦¹­û@+m™ÅI=”ûn_ºtiÀ€Ý»w?|øpQQÑ¢E‹:wîüÏ?ÿxxxÈóòÄÄDë÷Ã;v|xêÔ©7îß¿ÿÂ… ÁÞ½{>|HDR9µj|ðÁåË—ïÞ½L‹ å‚Öµ'¢µÜ ‡C“¿§+ô:nDQp2º¦ÌþE+ekB%>&"r—cÚµ÷MÿG¥¶–iOãG¥ë*…†yÜL›md÷nÆvcÇDTÊÍ–—±ôôŒœ%Wθ~ùÙ–UÌãλO‘cP/ÏacÊóóâß–óèžs/é3®Ìj$ñ¸™q{¶¼Ü½©ñ7Sk¶wÚ`÷Œ@&¾¨:2šXúèsl‰H$à•ó²ó³þÎϼúì+ç®^m—pìUÔ®VQú»½`ÁóçÏ3™©sçÎÞÞÞ«W¯Þ¶m›¬—=zô¯¿þÚ¶m›x"¤ 6dddÌœ9sæÌ™®®®={öüòË/»wï^évòòòòóó6lX³žÏž=ÛÎÎ.<<ÜÔÔ”ˆúöí°|ùòãÇ3+”––îܹ³mÛ¶D4uêÔ={öÂ"h@ÕÉIùN%%´}'åžuh§äËAÍû[RHQ§èÈÊË"G½H®WUŽky&¥"¢òR*Ȧ´×$ô¤ïÖy-XUÚC¥_‹sLxˆˆ†êPîfÅ­œ›ýàé™8»¹üy¥ÇL1?LhÐwˆS7µ^·«ô›øImPÖäAͦί¸PßÄ´ñ7S3EÖÆ¥¶Æ66éôËñŠOU1cQ]¥êÈhãÚ‡­o*àågFÛy VQ+ºB¡w›Ãá´k×îèѣ˖-cŽD'%%]¿~ýÛo¿•çå&&&¡¡¡Ÿ~úéÎ;§M›FDqqqÞÞÿ¹®ëŸþ!"GGGssó  é“fÏž}êÔ©qãÆINCDÌÔ9’Ç»+ö¼[·nkÖ¬122’§·’ŒŒŒj0ʸ}ûö+W®L›6MœŒAÝTqÍ„´W£ýdkKAè蹟2[‘ö7éÙ»F&djA¾¨Q+ê<„<”0¥k%T” ™È¨"ÌìЂR^êÅ“O7.7]ûkµ³½€ª}µöÞCôzt—ê"#‹Å6±nVu·$樂ݨóä·—.]Ú¯_¿~ýú}ÿý÷EEEK–,111Ï×]­¡C‡¬Y³f„ FFF=zôhܸñ€6lXXXxñâÅ|øá‡5ªôå;vܰaôiÓFíéé™››~ôèÑ“'OVÝôºuë‚‚‚‚‚‚¾ÿþ{777.—{÷î]" ­þl??¿ÒÒÒ7vìØ‘ÃáÈš©'"""..®´´499ùôéÓááá}úôYµj•x„EÐ0%ÇÄ}»•¹5Pîþ†Uur¶Z)+Aªê,F±Øl}S·G$ÞS”ŸóàNê¥Ó¥Ü,}S3‡NÝ~ö ‹­·wkQòëWv&ýù?³†Þ¾!‹ˆ¨,ûíóóžÅrœ|ƆX6m¡üîA£¢ÈÈ\ÚÂ/ËUîfu<ïvï޽ϟ?¿xñâ‘#GtíÚuõêÕrΛCD,kùòåܽ{÷„ Ö®]ûçŸnÛ¶-55•Åby{{/[¶læÌ™UlaòäÉmÛ¶ {ûö­¥¥e»víþøãVÝ´¿¿ÿ;w/^<{öì¼¼<{{û6mÚÈyTúÃ?7nܲe˲³³4h kžÅ &‘±±±ƒƒC``àÑ£G‡Ê’˜¡—¥ÄSøAwýìý•øñø8ÕÞ¦B ä‰MïŠ5â’J»T‰n½‰H)ÿ:j°¿‡äš6U™F¸)i+¥Pj¼1#ºëá+JlýÑʹÆ.nÞ_~OD‘—žm[Ý&tgqJ’™—±ƒsqZrìêù.}‡¸ ø˜*†¾7{¿¸ÐwÚBS¯¤Ó#.tØzP‰}»6\S*÷ýTŠkÃ{2ãˆuÞž™­‰¨ý°§ò¬Ì̳ظÓÉ«¡%½Œš’ý撃ק Û,•µ‘è#Íèý0m=„‰ÓU#‹ VõmΔú¶¿•’3)2ç,*ýì=†xi¶¡Qã¯&›º{™º{1O™4poÐgpNl +rîõ¹wS"ré7$ñßËòr -­+]S;iaR¬?vÏÜSÕ`“ÂÊK³‰HßP±{׈‰ªƒ°jUßbS}Û߸1#ºÆw7–3;4ÛˆÃ6~w¾67æö›ÓGJ2ÓˆHXÊ3v’yf&B"bsŒ‰HPRL:µÖž™­¥>zæ§‚NïªöŒ@U‘HPœóŒˆŒ-}ª]¹.%'¼Û aTHÖ°â»y%Õu×jñìÐŒòüÜÇkúÍ\jОX¬7çŽeݼúî9MÜH[ž¸¬¢1W¨ª³‹ê‚Kö›¿ü"‹má ÕN)—¦Þm„°j¥ £­„"3Oob±Ê òÓÃϱŒ™§ ­mKÒ’5Û½ÚcÒgÕùR<£ÃÆ¿mÍ&»ùwf"CCk[ _×CͽšÔ`SºN¥Á¥¬$3éŸÕDdë>ÐÐØAu é ÄDuBXU‘VÔ†Œ(Æqpj8òÛK§˜[雘X·l“ÿüÝܱc]ê¥Óæ^>-ç¯Ñl?kFþÃú.ý†x}ñn¢ìJî¿"ƒHÀg±ÿóÝÁÌL$âóK²ÒÒ¯œ»?o’oÈ"»vÚ{_ÍÚ¨t K¥ÁEÀ/â&{»±œÇ嘹{´š«º¶´úßm¨Â"¨„ö\ÜS這Ûàánƒ+¹ ·e“æmÃþ uè¿7`Õ30Ôþ‹E;TOOÏÀPrAy^nÜÞ­¹±÷‰Å²öoã=z¢¾™9Ý›=ÎÚ¿MAܳ²¼Ïacì;týÏvXÄb³Yl¶©«g£/'ò‹‹âöl®«aQŠ*‚KÊãmñ‡‰H$(-/Íá&2óì[9wõj»Lߨþž2‹˜¨)‹ Úë›Ú_*ôdÃR}S³¶ë …Ï6¯|ºeU‹¹+™§ÞF_oµdsÿèª9vé•q¡–=ÑN’]ª .Åy/(ˆHOßXßÀ¾­™M [÷&VMUÔ¢vRÏ» ò@X­&‰X,uë­©5Ùß®˜jt] ’bÚ¥3™×/3›NúÁÄÙ-÷Ƀ[ꛚ‘×èñwg|S–Ãe¢Sò$E"2²«›gÔ‰³‹ê‚‹ÿs*Ú²ÎQû òCXÐm5PtèÒÓó“/™Ç–ù/Ÿ²ØlqÔ3vl@D¥Ü,&#ÙØÉ¹ÙÒ·™5ëöCpQ'¼ÛÚa ‚n½5ݵ!s†Aе9ôÌæ‹g‘$"Ž­ƒH (åf1 yi$1ͤü“ eܸ"²Ô!È.ê„w[«È{ù€¦¼›¡Wmî}Cšš˜iWmNÜNÌ„ R”;Ÿ9ÇÑÙ²YËøß·ó‹‹ø…ñû~¶iÕN®CÏ" ²Òâ7‰¯þ·#ãÚÅFc¾WbÇ@³0²:àß3ÕØ¢ÚÚª´uæÌEu¶¨¾ÆÔîþ¼IN=8÷ %ÛQUÜùÆwÚ‚ø½Ûþž6šE,kÿ6FOçU)çÿL9ÿ§ž¡•­E¿€e›™$@Ý€°ºá]^TW[êi¨ê>Ô«ýUHqjÒëý¿ä=ðJŒlì,}ý›ŒWêýwß‹ùaBƒ¾Cœºõeþtý`˜©«‡*ªÚ'ÅJg2´²i6u~Åå’Sɳ¨KAgè\¦©¥ú¶¿ò‰­úÑÊ·eëÐæ¼Œ´ì‡wÕÓ²}‡`õ4T55ÜJ”ˆùá}¤YûaO5Ý€BX]R–ŸËËLs™±˜¹„ÂÄÕÃäýhŸ€WòúÐnîÝ›ü’bK?ﯧpì¥^^é:‚’âׇ÷pïF•äqì}ÆÏ´ðn·wkQòëWv&ýù?³†Þ¾!‹Ä‡¡«˜¹Ú& }Aü³²Ül"Vão§Z6m¡ÜÝGRõCX]bhaeêæ·g³K¿Ì66vr?õlëO">?`ÅVS󄣿=^·°õªŸ¥®á­t§[V x%þ‹Â8vÅioôØúDäýå÷ùÏb%C‹U5sõ­¯7°°Ê¸ö×ÓÍ+;l=¨Ä}GR„jEi¦é.@„«¡@§°X­o°ò H>uäîÌonO‘zñ$•r³Þþ}£ñ·Ó -­YúúžÃ¿.IK)J~-ùÒJ×áÞæÞò7cïH,–I7Ž£síó2ÒrŸ<ð3IßÔÌÀÜÂkôøìûÑe9\æYç^ƒ ,¬ˆÈ¶MÇÒ·™ey9ÊÚo$EÝÅœR¢†'n'±€radtŒ¾™¹ç°1žÃÆËË2¯_y±3ŒãèÌæ‹õpù,ñjzFF¥9\Sw/ñ^VzÅuò_QÅP"¦éÐQ‹ 5މâÃÜÚ aj¥6£‰õêÐ: ajN¡s@!,Buë6…GÐã'”CB!Y[Q îB]ƒÉ î”ýô®”ÿî1‹EF&dbN ‘—?uú<ýTØtícâø¸=X¿)­C uç[àìlZ´ŒÅ™›“‡;Ð[.EÞ È´û7Ú²ll4ÝKeroJvDDe<ÊçÒã[{“Nm£€žôݲrPrsJM”\9$$¤¶}•AXµbr† QæФi”šFînôýxjÛ–ôÞOF“–NÇŽÓÉS”—¯¶°¨òý%"¢¡!Ô~à¿–ÐÍtd-Ý¿B‹>¢e§ÈÂV9 á 3@=„°jÅÜ X…jÃ&JM#OÚ²ÌÌþó”³Mš@½{’¹™Œ+ŸÊ÷·2ÆæÔkö¢RF"ý¾˜&m®í6•;'Žø%¿7T a4Fù*ù ED…L•NŠbM|”Öœ‚ÔmœéË%´qE¢‘óÈÆ©†ÛQúÔ‰†Ð-‹ aÊŒPQ·I(¤ È¿…¶¦ꌌí±•Òã›Ôe¨Â/Ç Û@¸Ý¨_¥9C¡ûËôâQ³&µÝŽR©p«£Ç~wAtòsÅ^XõýúêŒ,‚©í¨[n‘µ•òz¤Zjed.m)Ì‘w}Œ&€„E¦†/y:P‹hª~9lo4F=o…J##s KŽ·¤ŠýEL¨ÏAKÕ$¨YYåÈ=Œ¦MTL󳉈Lk:ØŠ˜‹ Õ¶7CDä\ÛLJ®\¥§ ž §M˜ý%úM)[ (ñ1‘{3…_‹˜ \àZmBüoâ“wíNí‰Å¢ÔTzðH…}R%Åö·:Ñ稤ôØä×I®¦™¸„$adˆ41ŒTíQW¦KŠÝ;ØÍºv¡ˆHZ¿‘¶n$SÓJÖyþ‚lmÈήÚMˆÿM‰SF«d«”“Aû–uBÖŽr½*BX ¨:9Õ*²LŸJÏ^PB"MœBß§6m*¹ÝßÎíò„E%RáþV¦¤¢NÑ‘5”—EŽ4z‘r7õ Â"h%Ä& Ú²-¥ÇOhödnN®.¤¯OoßRZ:‘« YZÔ¾«J¡¬˜xl=]ÚGDT^JÙ”öšDB"¢€žôÝ2WÓ}° nBXu«t˜M™£kv¶´eEݦð«ôä)½~M!ÙXS×.Ô-˜º‘¾ZË^åûK”ôìÝ#2µ ßÔ¨uB¾Jlê)„EÐ0•œ'ÇbQçŽÔ¹£ò·\kÊÝß°kJÜ@%AcêÛåõm n@XµRà î´J}Û_¨{A­ê[lªoû u&å™@&„E adBX™A«‰D""¢n½5Ý5aöw„«¦ûðÂ"È„°PA½Èd` ª€°ÚNÝG¢ß7ô®]µSó‘hqCšÚ_Ðr,|C€N`±XêlNãÿ.êÛþ€ÖÂÈ"èu¦mHNõm@kaddÂÈ"È„°2!,€L‹ Â"È„°2!,€L‹ Â"È„°2!,€L‹ Â"È„°2!,€L‹ Â"Ȥ¯é±X,Mw´šH$ªt9*juÚ5 Ú†©IŒ,€LZ1²È8ꔦ»Z§ÿàÁÕ®ƒÊE¡®@Û &AÛHÖ$F@&„E adBX™@&„E adBX™@&„E adÒ¢{C×1¡aa±±±¿ïÞMDOž>1gβE‹Ú´n-^aì„ oRRæÍ™Ô¹³B[~øèÑœyóˆèÌñãl6›Ù΄ï¾ø@$­[¿¾¨¸X¹}C]®³°°˜b``P\\|7&¦öDéB-Õ™šÄ¿å+//gèééQYy9Éw8¯ÿàÁzzzgOœˆ¼qãøÉ“ ‰‰,«Y“&£>ÿ¼i“&Ì:B¡ðQllßÞ½œˆèŸ‡ÍÌ̆~ü±Rz^íÉgÏŸß²};óøÃO>/?°w¯µµ5•””œþ˜ˆ223Ç|û­«‹Ë®÷ £¬¬ìÃO>áp8Ça–TññYZZjs]‘|¥UoëJ!›¶n=ñbëÀÀe‹1§0ÖmØp9<¼}Û¶‹æÏg–3ïç™ãÇÏ_¼xöÂ…7oÞµhÞ|ÔÈ‘ž·œž‘qä?bîßçfgsŒŒ¼¼¼úõéÓ½kWÉu*ýŒ¾ûöÛ¿ü¬ «ädaaáÒ ABbbzzºB«T¥¥[RRræÜ¹›·n½yó¦œÏ·±¶öiܸO¯^­ÓÒÓ¿ùî;s3³}{öH¸äóù_|õU~~þÎmÛ\]\Ú©ºD\]¾|úìÙä7oŒ9œ¶mÚ|=fŒ•¥%ŸÏÿãÏ?¯\½š™•enfÖ­k×/¿øÂÀÀ@êå¨Iõ×$¢òÙÙÚþºc9ØÛÑô©Sy<^¥gUjßvuumî뛘”óÏ?? õnÔˆYaóúõ¶66Ìã¡}ôÉG™™šª`?*áÓ¸ñçŸ}vøèQ>Ÿ?bØ06›Í,çQFfæ¼… SRS-ÌÍ›øø¼|ùrÿÁƒ7£¢BW®¬8ü¾{ïޣǎ¹º¸øx{§¤¥©g4«ÚÚˆþûo‘HääèèߢE¥[044ìÞ­Û±ãÇ£ïÜùDÁ0WõǧµuE –V=¬+…Œ;öù‹÷bbŽ;6üý·àåððËááövv3¦M“LD´}çγçÏ·lÑ"¨S§W¯_Gݺu÷޽勷hÞ\rµØÇ-[V\\ìèàС}ûüüüÇOž<|ôè^LLÅmJ}F5ªºÂãñˆHÿ}ÂP¨cÕJKOŸ¿hQjZš1‡Ó¬iS“̬¬Ûÿ_PÐ:0ÐÙÉ©mëÖß½yãF¯=$_xýƼ¼¼ÿúœÅvïÝûÇŸzzxø5kö2>þÒ•+/^¾\¿víâeËž=ÞÐÓ³‰µõó/Ž?þöíÛ¹³fI½5)I=5©«a±ÿàÁªØ¬R!ØlvggñŸ6Šü  …§ÎœY±ti€¿?ñùü5aa‘7nì?xpÑüùD¤§§Wã×^coïÆÞÞÇŽçóùŸ &ù3E$-_µ*%5u`ÿþß~õ‡Ã!"·~óæÈë×ÞµkÖôé’› …gΞ]±dI`@órõì‚Ò+G¡š©¶6ââ㉨‰OiêãCD/ãâè%Uùñ‘vÖ)XZõ³®bhhøãìÙ“CBöíßßÂÏÏ·Y³äää-Û·³Ùì¹³fI%o¡PxùÊ•µ?ýÔ¬iSfÉÁÇß¿õºu»wìR<oehhqqñÐ!C¾3†8‹Ÿ·pá•«W}›5ЯŸä6¥>#‹ÕÂÏOV($!11#3“ˆ<ÝÝíXµÁ’åËSÓÒ:wì8mòdñϼÂÂÂ/_2ô÷Ý»gΓúb>sî}PÝÜJ¤µß’B¡ðâ¥KkV­òóõ%¢üüü™sç&&%MŸ5‹ˆvlÙâääDD¯¦ÍœyíúõÆIŽ¢&%©­&u,,ª¨ú+n_ƒ‡®F}þ9“‰H__ÿ«Ñ£#oÜxË”oí·¿bõj©%Û·_8o^-7{ëöí¸øø&>>ß/î'‡Ã™6yòƒ‡#"#Ç+õ=ôñG1ÿ2‰H)»VÕUŽrk&//ˆª>ÌÁ<[ZZZZZjddTûF•BEuEŠ—V=¯«Šœ:vLü§‹‹Ëäï¿]·nÕš5a¡¡+V¯.--ýúË/}›5«øÚ +шaîFF&''KTDDFæää4pvù‘w£F#GŒøy×®cÇK}ÿ©â3*,*züäÉŽ]»D"‘““S@«V5èXÕnDE%&%5pvž3s¦ä±Q333ñ¸<ñâe\œøœã× Ož=³·³kß®Rv¶ :ñ-9úóÏ™¤HD ¸mÇŽ„ÄÄMaaLR$¢†žž]‚‚®„‡?xøPê3jRLm5©KaQòß@–§§*š°OH·¥©¼Ø±}{É?œœ ‹‹‹y<žqÀ¥TœYC)‡EîÜ»GD;v”úgfÌá4õñ‰¾sçe||`«V’Ou®}»ò¬œöÞ*wãÑGš‰[QOͨm´L!*ª+R¼´4RWqIÉ[ïÖ[ÜŠBuUéÔ9’ß"Œî]»>Š=ñâ„I“ŠŠ‹ÛÊ:«Aê<*‹Õ=8ø÷ýû>z$þb~KD=»w×ûïÉÙ}z÷þy×®Ô´4.—kkkûï6•÷U Çöö‹æÍc®P´cU»{ïõêÑ£âû)Æb±¸}çÎ3çÎ…L™Â,<}ö, è×OOjF²&½QI#\ÿm«ÆÿãIMùéââBDÖVVRWû1ÿ‡p³³¥^ŽšS[MêLXdþ ¨(#Š1Ûg"£Fò"‹Å²«P%¦&&eeeåååJ ‹*šY#-=ˆvïÝ»{ïÞJW(((Zâàà ônTÄTŽÒ3¢³e&2Ö¾f˜ ·sss«X‡yÖÈÈH{†I•3¶(ZZê¬+ågD1fËÝz“‚u%ÿ1~ìØ{÷ïgffZYZΚ>]ÖhŠ“££ÔGGG"zûö­x —Ë%"ñ˜˜1‡cme•“›ûö¿ßJüŒÄsÚX[Y5÷ó  ÿÓP´cUËÌÊ""7WתWëݳçoûöEDF~ûÕWæææÅÅÅW¯]Ó××ïÛ§B»¦(¦&U”Ří3‘±fÿã±X,©÷ÜÄØ˜ˆìíí¥Öd.ò+/+“ZŽšS[MêFXTORËòôÔT^O‰¬s„B!uîìáî^é înn’êééUñKHYTÅÚ{ª”¼ØØÛûÚõëÏž?¯bg/^‘ø‚'Y´s²*-uÖ• “¢XÄ¥äE9Å>~œ••ED……)©©ŠÞHò*¦Ø*ýŸ«b*÷3’œÓNVërvLYŒ{÷ìyêÌ™¿®\:dÈåðp×-8X)QÉ¢ž¤(vèMÍ󢬯¹Ú÷¡&e©}MêFXT?q^9ÙÛÙ‘‡»ûŸ}¦é¾h†8/ÖF»¶mýí·ôŒŒ‡µ¬ì‚èòòòˆk×Hâ8sh£¤¤DjMæ”ê: ¾—Öû¼¨\Ù99kÂÂD"QŸ^½þº|ù§5k¶nÜXé¤ ™™R1=33“ˆlÞ_;ODvvvô~ XÇËÍË#¢ŠLÔC¹c&1¨âžŠbƒ<}öì¹óç?þðóçÏ“z/mQq^T?Ô¤˜ÚjR&åVõ麠(&„BÉ…Ì­#"#Ë*2Ð]¬7W×íÛÑö;Kx¼Š+ìÝ·›mffÖÿýIЖúúúÙ99RGcoEGWÚD¥Ÿ6Õ1m+-]¬+)"‘(tíÚܼ¼!|2eJÏ=2³²Â6n¬teæÇ‰äk#"#‰HòÇLËæÍ‰(<"BøßïÒ•+DÔÀÙYžÃjª¨L¥tL¬u` ]¾z•ÏçW½¦‹‹K`@@jZÚžßOJNöjذҋ‡”¥Ô¤BP“bj«I‹ µƒ†j1¿{’’’$yzx¤¤¤¬^·.''Gò)nv6s.­F¨á´rMž8ÑÆÚ:!1qÎ?¾zýZ¼¼°¨hÛŽÇNœ`±XÓ§NO‚¨¯¯ïçë+‰öüþ»ø(Fô;‡ßÏÅ-¥ÒOÈꘖ––ŽA«ÌþC‡qútÅ•Ož9óüÅ ñŸGŽKLJ²±¶ /ìlmm’šúÛ¾}â"LHLÜè ýè#yz¥ŠÊTJÇĺtîìîæ–’’²výzɱüâââJ­¿g÷îýûö•§çª¨L¥tLŒÍf/üñÇy‹]»~ýî½{~¾¾ÆÆÆYYYq¯^ù6kæß²¥äÊm[·nà윚–fjb"Ï9@N¨IIj«I„EPØgÆ øüQQ·¢£™¡ï/¿øÂÄÄÄÑÁaËúõç/^¼•˜ø2.ÎÂÜÜÖÖöã!C:uì¨é^ë''§­7^¹zõúÍ›qññcc9FF ==Û¶i3xà@KKK©õý|}W.[¶ÿÀ/_Æ>yÒÐÓsþ?´mݺҰ(ëãSÇŽU©ŠŽ¡´ä—’šZéræh~n^^èÚµ"‘hê¤IÎ×czzx|÷í·›·m[ºeÃS‰z˜0nœ›«ëù‹?}jhhر}û/FŽôjØPjûÍýü¶mÜx䨱{÷ïß¼uËÈаYÓ¦ýûôéÖµ«œ.¨¨2kß1I...[7m:yúôÍ[·ÆÆ …BkëŽíÛ÷é-}^)‹Å hÕ*5-­wÏž7º„šAMJROM²´á’IæÝ‘uE•š/…c.pÁe5‹ùôeU©<•£ÎÃÐÌ.¨íWûºRëaèn½«èêˆï™«ævë>Ÿ?úë¯sóòä¼tíkRý‡¡™ \ÔY™¨ÉÚ¨MMêÌ9‹rºZRbŸÐ())µ²“='¾}kŸðYF†ú;õ˻ԭ7 BYY•<»â'êÖ›æ*á7 NŸ=›“›Û®MÜ ´Dmj²®†înlü…¹ùÿ B¸ÜÃÿ·óBqñÑÂBK=½0;;Mu´S^úg‘cÙæ-û24–ž+5>zÎÛÄSVÎÁMºìÐH÷@'µmCûÓÙó´f=…®üÏS7oÑ¥+dfF3C4Ô9P•äääc'Np³³ïÅÄèëë=ZÓ=ú×hÕçdbNkÃÉÆYúÙ­SèúŸЃæü®‰Îj(¥&ëÚÈ"-µ¶vÑ×/)ùŸÄL"9Bá .—ˆVØØ8³Ùšëh#K§ ¯Oå¯ï,”z*'5ümâ)¶EÃ6K5Ò7ÐaÇ“ƒ=ý}‡Îžÿwa~­Û@D4y"á‡kó6;ûâ¥K>läåµhþ|©›kœWêñÐŽYÒOÝû‹®ÿI¦46T=•QJMÖµ‘E"2×ÓÛ`kûiFÆÂœœîÆÆ.úúD4‡ËÍúš˜ ¯lÖYwÿ9¹é7rÓ¯g¾úÃÁëf!¿,ïõÝEDä𣡱ô ¦ªajB³gÐ̹´ígjÛ†쉈6l¦ìlêÔú*ªmåÂÙ·5àï¯åïÛ¨…ôà=ˆ ðƒÔãý<÷…¹´kÑ—KÉFúàŠÑò÷V;)¥&ëàÈ"u36en^ †p¹Dt¦¸øxQ‘µžÞ: ÍØÚm`æÕv%=X]Vünný„˜¥å¼·Ö ºÛy~¨ÑÞÎjÓš  ¢bZ³Žˆ(ò…_% sšРÆæ4~-Ѿ¥Ä}éüîy”›E­{Sð'ìh¯º‰h©µµ«¾þÕ’’ yy³¸\"ZikëˆÐ ›¥c'¯Oå…¯îÎ'¢ì7—¸Içô -¶Y¢é®.›ø9:Ð{ô¿ƒ´~#ÑäïÉÖ¦º—¨J‹`ê9’JÞŒþû05]ic3ÆÜ¼X$šúö­æïlÚ_š“po)95EÄJ~VZ¤ö[hA³~åäR×`š<‘"BבÜg곂lÚý#Q¿¯‰Å¢ƒ«(3IÓ}-VçY$¢SEE§ŠŠlØì566D´ÈÚúrIÉ ï·‚‚¯ÌÍUÝzôßùã׉‰%%%D´}óf•ÎË:v„7))â? ¬­­[øù}ôᇼ¼T×®BîÅÄÌ_¼ØÔÄäç-[ì*LD¼&,,<"¢m›6KJω­f¯c––—rm\ûzü(ò3⾺3¿Y·=D ßܽP9éJåÈI‘diùîTÅñcéößtÿ:u†>Tëé°òW—Taèëë[YY5õñ4`€Ë–×OHL]úv̤ù‡‰¥ŽÿêÞAMªS-k²†E®@0;;›ˆÖØØØ²ÙDdª§fkûiFÆ’œœ^ÆÆnú*Üë× Ëú‰ˆÚÚØØ‘¹êã)yzxXYYQaaaò›7W®^ˆŒœ5}z×.]ÔÐzµZöëÓçÂ_mܲeÙâÅ’OÝþûïðˆ3Sө߯¡Þ½“|!;ù‚¾‘µgë…Däæ?37íZ~ftFü!ÇFŸUûòZBåTJ'*G¦Ü<Ú°‰ˆ(d YYÓ¬š9—~ÞEÚ‘£šfz¯Au‰ £¨¨(ùÍ›QQ7¢¢¾3æ“?–\í¯Ë—7mÝ*Œ97WW33³¼¼¼§ÏžÅ>~|ÿŸ6¬]+gsrrV¬^ýøÉ"233ssu500àr¹7oݺyëÖïû÷‡­^mmm]ƒ}W¢† ãñx'ÿøÃÐаê5µ¼noŸ¡ÛgÈÜæÝ©ŠŸÏ£ûáô8Š.ï£Þêº=!jR)ÔV“u0,Îâr¹Á`SÓÁsåt“¸gôªüúVt4ŸÏñé§_Ž¥ºV*ú|Ĉ Î™ÇùùùkÖ¯¿{ïÞ¦­[[µROæ¨Öد¿¾s7&æÂ_õëÓ‡YXPP°iëV"?v¬­F¯X//ÍNˆYFD Ù[ߤaÛeÏ®}“ü`­•sW#“*í*G-¯œª¬ßH¹yÔ-˜ºÿ»°Mëw÷Œ £ujš×®Õ%Y…EEë7mŠºuë·}û‚ƒ‚ÞͰ’ž‘±yÛ6@0ü“OF Æy?ˆRÂãݹ{7..Nζ ¦Ï™“žžîæê:î›oZ²Þp¥gdœ<}ú̹syùù²¾˜¿5ª¬¬Ì@•£5 µu›Ï¥Ý󈈾YI¶DDSú.”VŒ¤ý+( Ù¹ª£¨Iõ«MMÖµsO..¶e³Cm¤ç¼]jmÝ@_ÿZIÉ>‰{F+ÝÛ·o‰ÈQ]•²°°˜b``P\\|7&Fƒ=‘dbb2mÊ"Úµ{wÖÛ·Ì­?ÿœ““Ó¾]»ž=zh´w”poIyi¶[?·~â…–Ž¼>ð‹_ß™¯ê rdÑòÊ‘éj]»NV–4­Â\9Ç“½=Ý‹¡3çÔÓ—ZV—™©iÈ”)†††àÞýûâå·££ù|~coï1£Gs$·s8ÁAA_#çö·üüszzº»›[Øš5mZ·fI urtüîÛoÃBCÍeß©u@¿~CÖײ/f­­Û_ |.uDý»°E0õøŒxE•Ü3ZEP“êW›šÔ®=©¥·Áœìl" }Z’¹ž^˜­íˆŒŒE99=Þß3Z‰þwðàþƒ™Ç·lÙ¸e uïÖmöôéÌÂôŒŒ#üsÿ>7;›cdäååÕ¯OŸî]»Jm§ÿàÁzzzgOœˆ8}ölbRRII‰<ƒÌ’,,,\4HHLLOÿ÷ºË’’’“gÎÜŒŠJIMNŽŽ]‚‚†bll,ùZ9W«A?[µêß·ïù‹7lÞ¼bÉ’›·n]»~ÝÜÜ|Ц#r“Ïg¿ùËÀÈÆ3pÔSîþsrÓnäeÜÊ|uÔÁëSU´ŽÊÑÝÊ‘)'—6l!"šöþ´$Sš9æÌ£í;¨]Ûw÷Œ®‘jk£Úê’“™©igç„ÄÄœÜ\ñÂÜÜ\"²·¯Õ¬õ)))×oÜ ¢I'šÉ¸uBcoï*¶ ëü0y R\‘7n?y2!1‘Åb5kÒdÔçŸ7mÒD¼ÚÙóç·lßÎ<þð“ïˆw`ïÞ*DjaÝÞ:EÑçÈ–¾^!ýÔ¨…ôO=ºNWPÏ‘5o5Iu±&ëTX´c³Ÿ»¹U±BOcã,OOµÞ²ysúì³ÛÑÑñ¯^µo×λQ#"jø¾¹ØÇ-[V\\ìèàС}ûüüüÇOž<|ôè^LÌŒiÓXN*Þ½wïÑcÇ\]\|¼½SÒÒDŠ_;ÉãñˆHßÀ€ù3#3sÞÂ…)©©ææM|| ^¾|¹ÿàÁ›QQ¡+WŠ8ʹZûÉ ƒÇÜ¿èèÑ“§NÑ„±cm4zÚGy)—9í¸€9-‰m`Ö°Í’ç׿KzjåÔÅÐÄIé@åèhåTÅÚŠNþQÕ íÛQÄ¥Z6"OmT]] á•–‘µ••x 3,ôðáÃôôt'§þÓ¸}çŽH$rvrjáçW³-TJ¡‚ÜwàÀÁÇ]]]›ûú&&%ÅüóÏ£ÇÃBC™·‹ˆ|7þü³Ï=ÊçóG Æ~?Áù´ªnóßÒîùDD_¯xwZ’±9 ¥ŸFÑÿ–Q«nd[£ónP“UÐ隬SaQ³Z¶hѲE‹·o߯¿zÕ¡];ñ DÄãñV††2äë1côôôˆ(.>~ÞÂ…W®^õmÖl@¿~’› …gΞ]±dI`@‰D¢Š™ j ‰‰™™DäéîÎlaùªU)©©û÷ÿö«¯˜Áy·~óæÈë×ÞµkÖôéò¯V›~O›2åÇ öîÛGD;tèÞ­›B»¦tF¶­?Œªb+çàöÞª®¨­Í’³6ª¨.…$%'gdd°ÙìÖâ…]‚‚öíߟ“›;~òäN:´hÞÜ»Q£†žž }cN#kâãS³ŽUJ¡‚ …§ÎœY±ti€¿?ñùü5aa‘7nì?xpÑüwçŸ4öönìí}ìøq>ŸÿÙ°aòÖkUÝZØÑ®‡U­Ðª;ªÅ\a¨É*èzMÖµsµSDddNNNggñ¿"ònÔhäˆDtìøñŠ/ùø£ßÿPèû¾°¨(úÎ¥+VˆD"''§€V­ˆèÖíÛqññM||¾?^|‡Ã™6y²¥¥eDddAAü«Õÿ}“§\IDAT²ŸþþÌ>›Íž4a‚ü»V¡r$¡r$Õ 6j¦¨¸ø^L̲•+‰hܷߊ¯$ "3SÓŸV¬hâãSZZzõÚµM[·N™>}èˆ /¾s÷®œÛÏËË#"+Ë ëkAÑ‚õùçÌ·2éëë5z4=Œ­ÁÀ|Eõ§nQ“UÐõšÄÈ¢:<Œ%¢žÝ»‹ÿý0úôîýó®]©ii\.Wê*¤îÁÁ¤ˆ«¥/«t°·_4oósêν{DÔ¹cG©oec§©Oô;/ãã[µ’sµÚô“ˆnDE½Œ‹#"@pãæÍÁƒUû’z •# •#©µ¡©Â000X¼`A»6m¤VswsÛ°ví˸¸{11Ï_¼xñòevNÎݘ˜»11ƒ š0nœ¼í)u~?E ²cûö’«999óx<ãêêU«þÔ-j² º^“‹êÀår‰¨âùÆ޵•UNnîÛ ÿ„$*ÉC<•µ•Us?¿à  ###æÙ´ôt"Ú½wïî½{+}9ó›FÎÕjÓÏüüü­Û·ч|pêÌ™=¿ÿÞ®m['^¬ÍP9b¨)5¨ …0…!‰òòò“’ÊËË×mضzµ‹‹KÅ•™#bÌã„ÄÄ}DݺuêÌ™ÀV­Ú·kGD¡ë։׷µµŸPoiiIï¯KP… ’ÅbÙUx£LMLÊÊÊÊËËkùÅ\¯ê5Y]¯I„Eu`Æ+ý‘R鲞žžÁûË ä$9UEB¡ˆ‚:wöpw¯tw77ùW«M?·lßž›—Ô¹óø±cù|þÙóç7lÚ´jùrEO­«'P9b¨)ŠÖ†¢$ #%%eѲe)©©«×­Û¸n]Õï¹§‡Çü¹s§LŸ#*Šùb¾“/ñ]è,‘'¼½½#"#Ÿ¿xQû>‹)T,KuUT¯ê5Y]¯I„Eu`n­“&1 ƒÇãåæåQÅßÊeogGDîî_|VÕHä\­Æ®ß¼yýæM ‹IãÇÑ7_}uçÞ½»pa`ÿþªhQסr¨œŠÔY...óøaÒ´i/ãâ.‡‡÷îÙ³êõY,–o³fqññLOˆèðþý²Vnß¶í¯{ö¤¥§?züXYŸªº åTßê5Y]¯I\à¢-›7'¢ðˆæ·…Ø¥+Wˆ¨³³ª§òoÓº5EDF–••Õ~µšÉËËÛúóÏD4iÂfߘÙ:iýºgOff¦Ò[<êEQìN Z•Cš¨œª1uEÝz«¹])j® OýúÑþƒù|>³Pü ¢”ÔT"²­ps„Š\]\‚:u"¢-Û¶WºÎ˸8æ§œTT̉¼‚ÿ¾á²h[ݪj² º^“‹êÐ-8ØÚÚ:%5õ·}ûÄ£ñ ‰‰û"¢¡}¤êyzx¤¤¤¬^·.''Gò)nvöé³gZ­f¶lßž——×¥sç.=[µê×§O ·aóæÚl¼®Bå*GõׯÈ#Œ323/‡‡3KŽ8±bõê˜û÷xµïÀ¡C÷bbˆ(X¾;ŒOš8ÑÑÁ!)99dÖ¬»11’‡,Ó32vüòËôÙ³ å慠 ’KJJ’gåzX·¨É*èzMêÀaèó§Nõ<Ø>!Auói«‡Ãùqöì…K—=vìfTTcoï‚‚‚‡±±|>¿g÷îýûöUuØlöâ ,YuëÖ½˜¯† ìíËùü”””¤äd+KË”µˆ¼~ýFT”¥¥å÷ãÇK=5öë¯ïÆÄÜð@òn•ºHC˜¨œúP9Õ1„©þÚ°´´üäã÷íßðÈ‘^=zèëë ‚7oÞ¸yÓÈÈÈÃÝÝÌ̬  àÍ›7%¼ÿ·wÇ,m„qÇŸBb!˜hZˆnvHjAj§‹-º4Ä B¡ú*Ä¡ ‚ˆÐ¤à k±¸TlBÉÖDê,µu lèðØ´M“{r¿Ÿé†\žÀóKžž{îž_Bˆ§áð¹[àõ¸œÎ¥ÅÅ×óó©tz6mmmíñxl6[>Ÿÿq|,„èñxÚ\®«Tƒé×´L6û*½?0àp8„/¦§åÁ9Šs+GÉÉÞšž’X;2YÕ3ib±9Üëï·²²¾±±ŸL~‰Ço¶´ø¼ÞÑ@`dxXÍJçÛÝÝo–—?nmíÆb™löÛá¡Ëét»ÝáPȯiÕ¾¬*?ONÞ®® !"33mž\åp8^F"³ssï×Ö Ê…õ"Cë>CŸª-Ê*ųk”õCrD#’S™Ì•y\û.,—ø[)þ3Wê³ÿ°¹™Ëå>mo? áо¾ýdòk*õýè¨P(Øíö®ÎNŸ× îúªøûäîèXZXHìí}ÞÙId²Ùb±x«½ý¡ßÿhhȯiÕn³kD ŸMLü>=ÝÅ≄¼Üù|jêâÀlÚÜ*@&+°t&oÔå¥É UeGÇÆ„*g»2yP÷±U‘]¯—ÒK“Sþ& « W0›3)OW9³8Ù{v@>›Uy&­±fQf±TÀJ±É¨éGÒrÝ+˜‡ÌI©€3•âuc™ËÐ¥•‹*[TÖŒFoÂä æQZ¹¨²Eu¡¡¬1³(©Ì%߀µ0J –™Y”H'z%a+Í,@1ŠEè¢X€.ŠEè¢X€.ŠEè¢X€.í 詼_*ðÈ̆LÂl¬´74Â3‹0§?âÕRý.FÕIEND®B`‚quagga-1.2.4/doc/fig-rs-processing.txt000066400000000000000000000043001325323223500176270ustar00rootroot00000000000000From Peer A | From RS-Client B | | From RS-Client C | | | From RS-Client D | | | | | | | | Main / Normal RIB | | | | ________________________________ | | | | / _________ _________ \ | | | +--->|(D)-|Best | | Main | | | | +--|--->|(C)-|Path |-->|Local-RIB|->[A]|--->To Peer A | +--|--|--->|(B)-|Selection| | | | +--|--|--|--->|(A)-|_________| |_________| | | | | | \________________________________/ | | | | | | | | ________________________________ | | | | / _________ _________ \ | | | +--->*D*->|{B}-|Best | |RS-Client| | | | +--|--->*C*->|{B}-|Path |-->|Local-RIB|->[B]|--->To RS-Client B | | | | | |Selection| | for B | | +--|--|--|-------->|{B}-|_________| |_________| | | | | | \________________________________/ | | | | | | | | ________________________________ | | | | / _________ _________ \ | | | +--->*D*->|{C}-|Best | |RS-Client| | | | | | | |Path |-->|Local-RIB|->[C]|--->To RS-Client C | +--|--|--->*B*->|{C}-|Selection| | for C | | +--|--|--|-------->|{C}-|_________| |_________| | | | | \________________________________/ | | | | | | ________________________________ | | | / _________ _________ \ | | | | |Best | |RS-Client| | | | +------>*C*->|{D}-|Path |-->|Local-RIB|->[D]|--->To RS-Client D | +--------->*B*->|{D}-|Selection| | for D | | +----------------->|{D}-|_________| |_________| | \________________________________/ Key: (X) - 'In' Filter applied to Peer X's announcements before considering announcement for the normal main Local-RIB [X] - 'Out' Filter applied to announcements to Peer X *X* - 'Export' Filter of RS-Client X, to apply X's policies before its routes may be considered for other RS-Clients RIBs. {X} - 'Import' Filter of RS-Client X, to apply X's policies on routes before allowing them into X's RIB. quagga-1.2.4/doc/filter.texi000066400000000000000000000143121325323223500157110ustar00rootroot00000000000000@node Filtering @comment node-name, next, previous, up @chapter Filtering Quagga 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 @comment node-name, next, previous, up @section 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 @comment node-name, next, previous, up @section 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, 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 @subsection 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 @subsection 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 @subsection 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 @subsection 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 quagga-1.2.4/doc/install.texi000066400000000000000000000240661325323223500161010ustar00rootroot00000000000000@node Installation @chapter Installation @cindex How to install Quagga @cindex Installation @cindex Installing Quagga @cindex Building the system @cindex Making Quagga 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 Quagga running is to issue the following commands: @example % configure % make % make install @end example @node Configure the Software @section Configure the Software @menu * The Configure script and its options:: * Least-Privilege support:: * Linux notes:: @end menu @node The Configure script and its options @subsection The Configure script and its options @cindex Configuration options @cindex Options for configuring @cindex Build options @cindex Distribution configuration @cindex Options to @code{./configure} Quagga 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 --disable-ipv6 Turn off IPv6 related features and daemons. Quagga configure script automatically detects IPv6 stack. But sometimes you might want to disable IPv6 support of Quagga. @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. Quagga 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. @item --disable-opaque-lsa Disable support for Opaque LSAs (RFC2370) in ospfd. @item --disable-ospfapi Disable support for OSPF-API, an API to interface directly with ospfd. OSPF-API is enabled if --enable-opaque-lsa is set. @item --disable-ospfclient Disable building of the example OSPF-API client. @item --disable-ospf-te Disable support for OSPF Traffic Engineering Extension (RFC3630) this requires support for Opaque LSAs. @item --disable-ospf-ri Disable support for OSPF Router Information (RFC4970 & RFC5088) this requires support for Opaque LSAs and Traffic Engineering. @item --enable-isisd Build isisd. @item --enable-isis-topology Enable IS-IS topology generator. @item --enable-isis-te Enable Traffic Engineering Extension for ISIS (RFC5305) @item --enable-multipath=@var{ARG} Enable support for Equal Cost Multipath. @var{ARG} is the maximum number of ECMP paths to allow, set to 0 to allow unlimited number of paths. @item --disable-rtadv Disable support IPV6 router advertisement in zebra. @item --enable-gcc-rdynamic Pass the @command{-rdynamic} option to the linker driver. This is in most cases neccessary for getting usable backtraces. This option defaults to on if the compiler is detected as gcc, but giving an explicit enable/disable is suggested. @item --enable-backtrace Controls backtrace support for the crash handlers. This is autodetected by default. Using the switch will enforce the requested behaviour, failing with an error if support is requested but not available. On BSD systems, this needs libexecinfo, while on glibc support for this is part of libc itself. @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} Look for configuration files in @var{dir} [@var{prefix}/etc]. Note that sample configuration files will be installed here. @item --localstatedir=@var{dir} Configure zebra to use @var{dir} for local state files, such as pid files and unix sockets. @end table @example % ./configure --disable-ipv6 @end example This command will configure zebra and the routing daemons. @node Least-Privilege support @subsection Least-Privilege support @cindex Quagga Least-Privileges @cindex Quagga Privileges Additionally, you may configure zebra to drop its elevated privileges shortly after startup and switch to another user. The configure script will automatically try to configure this support. There are three configure options to control the behaviour of Quagga daemons. @table @option @item --enable-user=@var{user} Switch to user @var{ARG} shortly after startup, and run as user @var{ARG} in normal operation. @item --enable-group=@var{group} Switch real and effective group to @var{group} shortly after startup. @item --enable-vty-group=@var{group} Create Unix Vty sockets (for use with vtysh) with group owndership set to @var{group}. This allows one to create a seperate group which is restricted to accessing only the Vty sockets, hence allowing one to delegate this group to individual users, or to run vtysh setgid to this group. @end table The default user and group which will be configured is 'quagga' if no user or group is specified. Note that this user or group requires write access to the local state directory (see --localstatedir) and requires at least read access, and write access if you wish to allow daemons to write out their configuration, to the configuration directory (see --sysconfdir). On systems which have the 'libcap' capabilities manipulation library (currently only linux), the quagga system will retain only minimal capabilities required, further it will only raise these capabilities for brief periods. On systems without libcap, quagga will run as the user specified and only raise its uid back to uid 0 for brief periods. @node Linux notes @subsection Linux Notes @cindex Configuring Quagga @cindex Building on Linux boxes @cindex Linux configurations There are several options available only to @sc{gnu}/Linux systems: @footnote{@sc{gnu}/Linux has very flexible kernel configuration features}. If you use @sc{gnu}/Linux, make sure that the current kernel configuration is what you want. Quagga 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} (@pxref{RIP}) or @command{ospfd} (@pxref{OSPFv2}) 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 Quagga 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 @uref{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 @uref{http://www.tazenda.demon.co.uk/phil/net-tools/}. @end table @c A - end of footnote @node Build the Software @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 @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 Quagga suite, issue the following command at your shell prompt: @command{make install}. @example % % make install % @end example Quagga 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 ospfapi 2607/tcp # ospfapi isisd 2608/tcp # ISISd vty pimd 2611/tcp # PIMd vty nhrpd 2612/tcp # nhrpd 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}. quagga-1.2.4/doc/ipv6.texi000066400000000000000000000153541325323223500153170ustar00rootroot00000000000000@node IPv6 Support @chapter IPv6 Support Quagga fully supports IPv6 routing. As described so far, Quagga supports RIPng, OSPFv3, and BGP-4+. You can give IPv6 addresses to an interface and configure static IPv6 routing information. Quagga 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 @section Router Advertisement @deffn {Interface Command} {no ipv6 nd suppress-ra} {} Send router advertisment messages. @end deffn @deffn {Interface Command} {ipv6 nd suppress-ra} {} Don't send router advertisment messages. @end deffn @deffn {Interface Command} {ipv6 nd prefix @var{ipv6prefix} [@var{valid-lifetime}] [@var{preferred-lifetime}] [off-link] [no-autoconfig] [router-address]} {} Configuring the IPv6 prefix to include in router advertisements. Several prefix specific optional parameters and flags may follow: @itemize @bullet @item @var{valid-lifetime} - the length of time in seconds during what the prefix is valid for the purpose of on-link determination. Value @var{infinite} represents infinity (i.e. a value of all one bits (@code{0xffffffff})). Range: @code{<0-4294967295>} Default: @code{2592000} @item @var{preferred-lifetime} - the length of time in seconds during what addresses generated from the prefix remain preferred. Value @var{infinite} represents infinity. Range: @code{<0-4294967295>} Default: @code{604800} @item @var{off-link} - indicates that advertisement makes no statement about on-link or off-link properties of the prefix. Default: not set, i.e. this prefix can be used for on-link determination. @item @var{no-autoconfig} - indicates to hosts on the local link that the specified prefix cannot be used for IPv6 autoconfiguration. Default: not set, i.e. prefix can be used for autoconfiguration. @item @var{router-address} - indicates to hosts on the local link that the specified prefix contains a complete IP address by setting R flag. Default: not set, i.e. hosts do not assume a complete IP address is placed. @end itemize @end deffn @deffn {Interface Command} {ipv6 nd ra-interval <1-1800>} {} @deffnx {Interface Command} {no ipv6 nd ra-interval [<1-1800>]} {} The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in seconds. Default: @code{600} @end deffn @deffn {Interface Command} {ipv6 nd ra-interval msec <70-1800000>} {} @deffnx {Interface Command} {no ipv6 nd ra-interval [msec <70-1800000>]} {} The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in milliseconds. Default: @code{600000} @end deffn @deffn {Interface Command} {ipv6 nd ra-lifetime <0-9000>} {} @deffnx {Interface Command} {no ipv6 nd ra-lifetime [<0-9000>]} {} The value to be placed in the Router Lifetime field of router advertisements sent from the interface, in seconds. Indicates the usefulness of the router as a default router on this interface. Setting the value to zero indicates that the router should not be considered a default router on this interface. Must be either zero or between value specified with @var{ipv6 nd ra-interval} (or default) and 9000 seconds. Default: @code{1800} @end deffn @deffn {Interface Command} {ipv6 nd reachable-time <1-3600000>} {} @deffnx {Interface Command} {no ipv6 nd reachable-time [<1-3600000>]} {} The value to be placed in the Reachable Time field in the Router Advertisement messages sent by the router, in milliseconds. The configured time enables the router to detect unavailable neighbors. The value zero means unspecified (by this router). Default: @code{0} @end deffn @deffn {Interface Command} {ipv6 nd managed-config-flag} {} @deffnx {Interface Command} {no ipv6 nd managed-config-flag} {} Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use managed (stateful) protocol for addresses autoconfiguration in addition to any addresses autoconfigured using stateless address autoconfiguration. Default: not set @end deffn @deffn {Interface Command} {ipv6 nd other-config-flag} {} @deffnx {Interface Command} {no ipv6 nd other-config-flag} {} Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use administered (stateful) protocol to obtain autoconfiguration information other than addresses. Default: not set @end deffn @deffn {Interface Command} {ipv6 nd home-agent-config-flag} {} @deffnx {Interface Command} {no ipv6 nd home-agent-config-flag} {} Set/unset flag in IPv6 router advertisements which indicates to hosts that the router acts as a Home Agent and includes a Home Agent Option. Default: not set @end deffn @deffn {Interface Command} {ipv6 nd home-agent-preference <0-65535>} {} @deffnx {Interface Command} {no ipv6 nd home-agent-preference [<0-65535>]} {} The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent preference. The default value of 0 stands for the lowest preference possible. Default: 0 @end deffn @deffn {Interface Command} {ipv6 nd home-agent-lifetime <0-65520>} {} @deffnx {Interface Command} {no ipv6 nd home-agent-lifetime [<0-65520>]} {} The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent Lifetime. The default value of 0 means to place the current Router Lifetime value. Default: 0 @end deffn @deffn {Interface Command} {ipv6 nd adv-interval-option} {} @deffnx {Interface Command} {no ipv6 nd adv-interval-option} {} Include an Advertisement Interval option which indicates to hosts the maximum time, in milliseconds, between successive unsolicited Router Advertisements. Default: not set @end deffn @deffn {Interface Command} {ipv6 nd router-preference (high|medium|low)} {} @deffnx {Interface Command} {no ipv6 nd router-preference [(high|medium|low)]} {} Set default router preference in IPv6 router advertisements per RFC4191. Default: medium @end deffn @deffn {Interface Command} {ipv6 nd mtu <1-65535>} {} @deffnx {Interface Command} {no ipv6 nd mtu [<1-65535>]} {} Include an MTU (type 5) option in each RA packet to assist the attached hosts in proper interface configuration. The announced value is not verified to be consistent with router interface MTU. Default: don't advertise any MTU option @end deffn @example @group interface eth0 no ipv6 nd suppress-ra ipv6 nd prefix 2001:0DB8:5009::/64 @end group @end example For more information see @cite{RFC2462 (IPv6 Stateless Address Autoconfiguration)} , @cite{RFC4861 (Neighbor Discovery for IP Version 6 (IPv6))} , @cite{RFC6275 (Mobility Support in IPv6)} and @cite{RFC4191 (Default Router Preferences and More-Specific Routes)}. quagga-1.2.4/doc/isisd.8000066400000000000000000000052241325323223500147370ustar00rootroot00000000000000.TH IS-IS 8 "25 November 2004" "Quagga IS-IS daemon" "Version 0.97.3" .SH NAME isisd \- an IS-IS routing engine for use with Quagga routing software. .SH SYNOPSIS .B isisd [ .B \-dhv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B isisd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B isisd command: .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/isisd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When isisd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart isisd. The likely default is \fB\fI/var/run/isisd.pid\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the isisd VTY will listen on. This defaults to 2608, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the isisd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/isisd The default location of the .B isisd binary. .TP .BI /usr/local/etc/isisd.conf The default location of the .B isisd config file. .TP .BI $(PWD)/isisd.log If the .B isisd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBisisd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The isisd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBisisd\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR zebra (8), .BR vtysh (1) .SH BUGS \fBisisd\fR is ALPHA quality at the moment and hasn't any way ready for production use. .B isisd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://isisd.sourceforge.net or the Info file for an accurate list of authors. quagga-1.2.4/doc/isisd.texi000066400000000000000000000345721325323223500155510ustar00rootroot00000000000000@cindex ISIS @node ISIS @chapter ISIS @acronym{ISIS,Intermediate System to Intermediate System} is a routing protocol which is described in @cite{ISO10589, RFC1195, RFC5308}. ISIS is an @acronym{IGP,Interior Gateway Protocol}. Compared with @acronym{RIP}, @acronym{ISIS} can provide scalable network support and faster convergence times like @acronym{OSPF}. ISIS is widely used in large networks such as @acronym{ISP,Internet Service Provider} and carrier backbone networks. @menu * Configuring isisd:: * ISIS router:: * ISIS Timer:: * ISIS region:: * ISIS interface:: * Showing ISIS information:: * ISIS Traffic Engineering:: * Debugging ISIS:: * ISIS Configuration Examples:: @end menu @node Configuring isisd @section Configuring isisd There are no @command{isisd} specific options. Common options can be specified (@pxref{Common Invocation Options}) to @command{isisd}. @command{isisd} needs to acquire interface information from @command{zebra} in order to function. Therefore @command{zebra} must be running before invoking @command{isisd}. Also, if @command{zebra} is restarted then @command{isisd} must be too. Like other daemons, @command{isisd} configuration is done in @acronym{ISIS} specific configuration file @file{isisd.conf}. @node ISIS router @section ISIS router To start ISIS process you have to specify the ISIS router. As of this writing, @command{isisd} does not support multiple ISIS processes. @deffn Command {router isis WORD} {} @deffnx Command {no router isis WORD} {} @anchor{router isis WORD}Enable or disable the ISIS process by specifying the ISIS domain with 'WORD'. @command{isisd} does not yet support multiple ISIS processes but you must specify the name of ISIS process. The ISIS process name 'WORD' is then used for interface (see command @ref{ip router isis WORD}). @end deffn @deffn {ISIS Command} {net XX.XXXX. ... .XXX.XX} {} @deffnx {ISIS Command} {no net XX.XXXX. ... .XXX.XX} {} Set/Unset network entity title (NET) provided in ISO format. @end deffn @deffn {ISIS Command} {hostname dynamic} {} @deffnx {ISIS Command} {no hostname dynamic} {} Enable support for dynamic hostname. @end deffn @deffn {ISIS Command} {area-password [clear | md5] } {} @deffnx {ISIS Command} {domain-password [clear | md5] } {} @deffnx {ISIS Command} {no area-password} {} @deffnx {ISIS Command} {no domain-password} {} Configure the authentication password for an area, respectively a domain, as clear text or md5 one. @end deffn @deffn {ISIS Command} {log-adjacency-changes} {} @deffnx {ISIS Command} {no log-adjacency-changes} {} Log changes in adjacency state. @end deffn @deffn {ISIS Command} {metric-style [narrow | transition | wide]} {} @deffnx {ISIS Command} {no metric-style} {} @anchor{metric-style}Set old-style (ISO 10589) or new-style packet formats: - narrow Use old style of TLVs with narrow metric - transition Send and accept both styles of TLVs during transition - wide Use new style of TLVs to carry wider metric @end deffn @deffn {ISIS Command} {set-overload-bit} {} @deffnx {ISIS Command} {no set-overload-bit} {} Set overload bit to avoid any transit traffic. @end deffn @node ISIS Timer @section ISIS Timer @deffn {ISIS Command} {lsp-gen-interval <1-120>} {} @deffnx {ISIS Command} {lsp-gen-interval [level-1 | level-2] <1-120>} {} @deffnx {ISIS Command} {no lsp-gen-interval} {} @deffnx {ISIS Command} {no lsp-gen-interval [level-1 | level-2]} {} Set minimum interval in seconds between regenerating same LSP, globally, for an area (level-1) or a domain (level-2). @end deffn @deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {} @deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {} @deffnx {ISIS Command} {no lsp-refresh-interval} {} @deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {} Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). @end deffn @deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {} @deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {} @deffnx {ISIS Command} {no lsp-refresh-interval} {} @deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {} Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). @end deffn @deffn {ISIS Command} {max-lsp-lifetime <360-65535>} {} @deffnx {ISIS Command} {max-lsp-lifetime [level-1 | level-2] <360-65535>} {} @deffnx {ISIS Command} {no max-lsp-lifetime} {} @deffnx {ISIS Command} {no max-lsp-lifetime [level-1 | level-2]} {} Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or a domain (level-2). @end deffn @deffn {ISIS Command} {spf-interval <1-120>} {} @deffnx {ISIS Command} {spf-interval [level-1 | level-2] <1-120>} {} @deffnx {ISIS Command} {no spf-interval} {} @deffnx {ISIS Command} {no spf-interval [level-1 | level-2]} {} Set minimum interval between consecutive SPF calculations in seconds. @end deffn @node ISIS region @section ISIS region @deffn {ISIS Command} {is-type [level-1 | level-1-2 | level-2-only]} {} @deffnx {ISIS Command} {no is-type} {} Define the ISIS router behavior: - level-1 Act as a station router only - level-1-2 Act as both a station router and an area router - level-2-only Act as an area router only @end deffn @node ISIS interface @section ISIS interface @deffn {Interface Command} {ip router isis WORD} {} @deffnx {Interface Command} {no ip router isis WORD} {} @anchor{ip router isis WORD}Activate ISIS adjacency on this interface. Note that the name of ISIS instance must be the same as the one used to configure the ISIS process (see command @ref{router isis WORD}). @end deffn @deffn {Interface Command} {isis circuit-type [level-1 | level-1-2 | level-2]} {} @deffnx {Interface Command} {no isis circuit-type} {} Configure circuit type for interface: - level-1 Level-1 only adjacencies are formed - level-1-2 Level-1-2 adjacencies are formed - level-2-only Level-2 only adjacencies are formed @end deffn @deffn {Interface Command} {isis csnp-interval <1-600>} {} @deffnx {Interface Command} {isis csnp-interval <1-600> [level-1 | level-2]} {} @deffnx {Interface Command} {no isis csnp-interval} {} @deffnx {Interface Command} {no isis csnp-interval [level-1 | level-2]} {} Set CSNP interval in seconds globally, for an area (level-1) or a domain (level-2). @end deffn @deffn {Interface Command} {isis hello padding} {} Add padding to IS-IS hello packets. @end deffn @deffn {Interface Command} {isis hello-interval <1-600>} {} @deffnx {Interface Command} {isis hello-interval <1-600> [level-1 | level-2]} {} @deffnx {Interface Command} {no isis hello-interval} {} @deffnx {Interface Command} {no isis hello-interval [level-1 | level-2]} {} Set Hello interval in seconds globally, for an area (level-1) or a domain (level-2). @end deffn @deffn {Interface Command} {isis hello-multiplier <2-100>} {} @deffnx {Interface Command} {isis hello-multiplier <2-100> [level-1 | level-2]} {} @deffnx {Interface Command} {no isis hello-multiplier} {} @deffnx {Interface Command} {no isis hello-multiplier [level-1 | level-2]} {} Set multiplier for Hello holding time globally, for an area (level-1) or a domain (level-2). @end deffn @deffn {Interface Command} {isis metric [<0-255> | <0-16777215>]} {} @deffnx {Interface Command} {isis metric [<0-255> | <0-16777215>] [level-1 | level-2]} {} @deffnx {Interface Command} {no isis metric} {} @deffnx {Interface Command} {no isis metric [level-1 | level-2]} {} Set default metric value globally, for an area (level-1) or a domain (level-2). Max value depend if metric support narrow or wide value (see command @ref{metric-style}). @end deffn @deffn {Interface Command} {isis network point-to-point} {} @deffnx {Interface Command} {no isis network point-to-point} {} Set network type to 'Point-to-Point' (broadcast by default). @end deffn @deffn {Interface Command} {isis passive} {} @deffnx {Interface Command} {no isis passive} {} Configure the passive mode for this interface. @end deffn @deffn {Interface Command} {isis password [clear | md5] } {} @deffnx {Interface Command} {no isis password} {} Configure the authentication password (clear or encoded text) for the interface. @end deffn @deffn {Interface Command} {isis priority <0-127>} {} @deffnx {Interface Command} {isis priority <0-127> [level-1 | level-2]} {} @deffnx {Interface Command} {no isis priority} {} @deffnx {Interface Command} {no isis priority [level-1 | level-2]} {} Set priority for Designated Router election, globally, for the area (level-1) or the domain (level-2). @end deffn @deffn {Interface Command} {isis psnp-interval <1-120>} {} @deffnx {Interface Command} {isis psnp-interval <1-120> [level-1 | level-2]} {} @deffnx {Interface Command} {no isis psnp-interval} {} @deffnx {Interface Command} {no isis psnp-interval [level-1 | level-2]} {} Set PSNP interval in seconds globally, for an area (level-1) or a domain (level-2). @end deffn @node Showing ISIS information @section Showing ISIS information @deffn {Command} {show isis summary} {} Show summary information about ISIS. @end deffn @deffn {Command} {show isis hostname} {} Show information about ISIS node. @end deffn @deffn {Command} {show isis interface} {} @deffnx {Command} {show isis interface detail} {} @deffnx {Command} {show isis interface } {} Show state and configuration of ISIS specified interface, or all interfaces if no interface is given with or without details. @end deffn @deffn {Command} {show isis neighbor} {} @deffnx {Command} {show isis neighbor } {} @deffnx {Command} {show isis neighbor detail} {} Show state and information of ISIS specified neighbor, or all neighbors if no system id is given with or without details. @end deffn @deffn {Command} {show isis database} {} @deffnx {Command} {show isis database [detail]} {} @deffnx {Command} {show isis database [detail]} {} @deffnx {Command} {show isis database detail } {} Show the ISIS database globally, for a specific LSP id without or with details. @end deffn @deffn {Command} {show isis topology} {} @deffnx {Command} {show isis topology [level-1|level-2]} {} Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). @end deffn @deffn {Command} {show ip route isis} {} Show the ISIS routing table, as determined by the most recent SPF calculation. @end deffn @node ISIS Traffic Engineering @section Traffic Engineering @deffn {ISIS Command} {mpls-te on} {} @deffnx {ISIS Command} {no mpls-te} {} Enable Traffic Engineering LSP flooding. @end deffn @deffn {ISIS Command} {mpls-te router-address } {} @deffnx {ISIS Command} {no mpls-te router-address} {} Configure stable IP address for MPLS-TE. @end deffn @deffn {Command} {show isis mpls-te interface} {} @deffnx {Command} {show isis mpls-te interface @var{interface}} {} Show MPLS Traffic Engineering parameters for all or specified interface. @end deffn @deffn {Command} {show isis mpls-te router} {} Show Traffic Engineering router parameters. @end deffn @node Debugging ISIS @section Debugging ISIS @deffn {Command} {debug isis adj-packets} {} @deffnx {Command} {no debug isis adj-packets} {} IS-IS Adjacency related packets. @end deffn @deffn {Command} {debug isis checksum-errors} {} @deffnx {Command} {no debug isis checksum-errors} {} IS-IS LSP checksum errors. @end deffn @deffn {Command} {debug isis events} {} @deffnx {Command} {no debug isis events} {} IS-IS Events. @end deffn @deffn {Command} {debug isis local-updates} {} @deffnx {Command} {no debug isis local-updates} {} IS-IS local update packets. @end deffn @deffn {Command} {debug isis packet-dump} {} @deffnx {Command} {no debug isis packet-dump} {} IS-IS packet dump. @end deffn @deffn {Command} {debug isis protocol-errors} {} @deffnx {Command} {no debug isis protocol-errors} {} IS-IS LSP protocol errors. @end deffn @deffn {Command} {debug isis route-events} {} @deffnx {Command} {no debug isis route-events} {} IS-IS Route related events. @end deffn @deffn {Command} {debug isis snp-packets} {} @deffnx {Command} {no debug isis snp-packets} {} IS-IS CSNP/PSNP packets. @end deffn @deffn {Command} {debug isis spf-events} {} @deffnx {Command} {debug isis spf-statistics} {} @deffnx {Command} {debug isis spf-triggers} {} @deffnx {Command} {no debug isis spf-events} {} @deffnx {Command} {no debug isis spf-statistics} {} @deffnx {Command} {no debug isis spf-triggers} {} IS-IS Shortest Path First Events, Timing and Statistic Data and triggering events. @end deffn @deffn {Command} {debug isis update-packets} {} @deffnx {Command} {no debug isis update-packets} {} Update related packets. @end deffn @deffn {Command} {show debugging isis} {} Print which ISIS debug level is activate. @end deffn @node ISIS Configuration Examples @section ISIS Configuration Examples A simple example, with MD5 authentication enabled: @example @group ! interface eth0 ip router isis FOO isis network point-to-point isis circuit-type level-2-only ! router isis FOO net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 metric-style wide is-type level-2-only @end group @end example A Traffic Engineering configuration, with Inter-ASv2 support. - First, the 'zebra.conf' part: @example @group hostname HOSTNAME password PASSWORD log file /var/log/zebra.log ! interface eth0 ip address 10.2.2.2/24 mpls-te on mpls-te link metric 10 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab ! interface eth1 ip address 10.1.1.1/24 mpls-te on mpls-te link metric 10 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab mpls-te neighbor 10.1.1.2 as 65000 @end group @end example - Then the 'isisd.conf' itself: @example @group hostname HOSTNAME password PASSWORD log file /var/log/isisd.log ! ! interface eth0 ip router isis FOO ! interface eth1 ip router isis FOO ! ! router isis FOO isis net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 mpls-te on mpls-te router-address 10.1.1.1 ! line vty @end group @end example quagga-1.2.4/doc/kernel.texi000066400000000000000000000034321325323223500157050ustar00rootroot00000000000000@node Kernel Interface @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 Quagga 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 Quagga. You can use netlink as a dynamic routing update channel between Quagga and the kernel. @end table quagga-1.2.4/doc/main.texi000066400000000000000000000426211325323223500153540ustar00rootroot00000000000000@node Zebra @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 * Multicast RIB Commands:: Commands for controlling MRIB behavior * zebra Route Filtering:: Commands for zebra route filtering * zebra FIB push interface:: Interface to optional FPM component * zebra Terminal Mode Commands:: Commands for zebra's VTY @end menu @node Invoking zebra @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 -r @itemx --retain When program terminates, retain routes added by zebra. @end table @node Interface Commands @section Interface Commands @menu * Standard Commands:: * Link Parameters Commands:: @end menu @node Standard Commands @subsection Standard 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/prefix}} {} @deffnx {Interface Command} {ipv6 address @var{address/prefix}} {} @deffnx {Interface Command} {no ip address @var{address/prefix}} {} @deffnx {Interface Command} {no ipv6 address @var{address/prefix}} {} Set the IPv4 or IPv6 address/prefix for the interface. @end deffn @deffn {Interface Command} {ip address @var{address/prefix} secondary} {} @deffnx {Interface Command} {no ip address @var{address/prefix} secondary} {} Set the secondary flag for this address. This causes ospfd to not treat the address as a distinct subnet. @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 of the interface in kilobits/sec. This is for calculating OSPF cost. This command does not affect the actual device configuration. @end deffn @deffn {Interface Command} {link-detect} {} @deffnx {Interface Command} {no link-detect} {} Enable/disable link-detect on platforms which support this. Currently only Linux and Solaris, and only where network interface drivers support reporting link-state via the IFF_RUNNING flag. @end deffn @node Link Parameters Commands @subsection Link Parameters Commands @deffn {Interface Command} {link-params} {} @deffnx {Interface Command} {no link-param} {} Enter into the link parameters sub node. At least 'enable' must be set to activate the link parameters, and consequently Traffic Engineering on this interface. MPLS-TE must be enable at the OSPF (@ref{OSPF Traffic Engineering}) or ISIS (@ref{ISIS Traffic Engineering}) router level in complement to this. Disable link parameters for this interface. @end deffn Under link parameter statement, the following commands set the different TE values: @deffn link-params {enable} Enable link parameters for this interface. @end deffn @deffn link-params {metric <0-4294967295>} {} @deffnx link-params {max-bw @var{bandwidth}} {} @deffnx link-params {max-rsv-bw @var{bandwidth}} {} @deffnx link-params {unrsv-bw <0-7> @var{bandwidth}} {} @deffnx link-params {admin-grp @var{bandwidth}} {} These commands specifies the Traffic Engineering parameters of the interface in conformity to RFC3630 (OSPF) or RFC5305 (ISIS). There are respectively the TE Metric (different from the OSPF or ISIS metric), Maximum Bandwidth (interface speed by default), Maximum Reservable Bandwidth, Unreserved Bandwidth for each 0-7 priority and Admin Group (ISIS) or Resource Class/Color (OSPF). Note that @var{bandwidth} are specified in IEEE floating point format and express in Bytes/second. @end deffn @deffn link-param {delay <0-16777215> [min <0-16777215> | max <0-16777215>]} {} @deffnx link-param {delay-variation <0-16777215>} {} @deffnx link-param {packet-loss @var{percentage}} {} @deffnx link-param {res-bw @var{bandwidth}} {} @deffnx link-param {ava-bw @var{bandwidth}} {} @deffnx link-param {use-bw @var{bandwidth}} {} These command specifies additionnal Traffic Engineering parameters of the interface in conformity to draft-ietf-ospf-te-metrics-extension-05.txt and draft-ietf-isis-te-metrics-extension-03.txt. There are respectively the delay, jitter, loss, available bandwidth, reservable bandwidth and utilized bandwidth. Note that @var{bandwidth} are specified in IEEE floating point format and express in Bytes/second. Delays and delay variation are express in micro-second (µs). Loss is specified in @var{percentage} ranging from 0 to 50.331642% by step of 0.000003. @end deffn @deffn link-param {neighbor as <0-65535>} {} @deffnx link-param {no neighbor} {} Specifies the remote ASBR IP address and Autonomous System (AS) number for InterASv2 link in OSPF (RFC5392). Note that this option is not yet supported for ISIS (RFC5316). @end deffn @node Static Route Commands @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. If the interface name is @var{null0} then zebra installs a blackhole route. @example ip route 10.0.0.0/8 10.0.0.2 ip route 10.0.0.0/8 ppp0 ip route 10.0.0.0/8 null0 @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. The third install a blackhole route. @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.0.0.0 10.0.0.2 ip route 10.0.0.0 255.0.0.0 ppp0 ip route 10.0.0.0 255.0.0.0 null0 @end example These statements are equivalent to those in the previous example. @end deffn @deffn Command {ip route @var{network} @var{gateway} @var{distance}} {} Installs the route with the specified 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. If zebra has been compiled with multipath support, and both 10.0.0.2 and 10.0.0.3 are reachable, zebra will install a multipath route via both nexthops, if the platform supports this. @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 @example ip route 10.0.0.0/8 10.0.0.2 ip route 10.0.0.0/8 10.0.0.3 ip route 10.0.0.0/8 null0 255 @end example This will install a multihop route via the specified next-hops if they are reachable, as well as a high-metric blackhole route, which can be useful to prevent traffic destined for a prefix to match less-specific routes (eg default) should the specified gateways not be reachable. Eg: @example zebra> show ip route 10.0.0.0/8 Routing entry for 10.0.0.0/8 Known via "static", distance 1, metric 0 10.0.0.2 inactive 10.0.0.3 inactive Routing entry for 10.0.0.0/8 Known via "static", distance 255, metric 0 directly connected, Null0 @end example @deffn Command {ipv6 route @var{network} @var{gateway}} {} @deffnx Command {ipv6 route @var{network} @var{gateway} @var{distance}} {} These behave similarly to their ipv4 counterparts. @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 Multicast RIB Commands @section Multicast RIB Commands The Multicast RIB provides a separate table of unicast destinations which is used for Multicast Reverse Path Forwarding decisions. It is used with a multicast source's IP address, hence contains not multicast group addresses but unicast addresses. This table is fully separate from the default unicast table. However, RPF lookup can include the unicast table. WARNING: RPF lookup results are non-responsive in this version of Quagga, i.e. multicast routing does not actively react to changes in underlying unicast topology! @deffn Command {ip multicast rpf-lookup-mode @var{mode}} {} @deffnx Command {no ip multicast rpf-lookup-mode [@var{mode}]} {} @var{mode} sets the method used to perform RPF lookups. Supported modes: @table @samp @item urib-only Performs the lookup on the Unicast RIB. The Multicast RIB is never used. @item mrib-only Performs the lookup on the Multicast RIB. The Unicast RIB is never used. @item mrib-then-urib Tries to perform the lookup on the Multicast RIB. If any route is found, that route is used. Otherwise, the Unicast RIB is tried. @item lower-distance Performs a lookup on the Multicast RIB and Unicast RIB each. The result with the lower administrative distance is used; if they're equal, the Multicast RIB takes precedence. @item longer-prefix Performs a lookup on the Multicast RIB and Unicast RIB each. The result with the longer prefix length is used; if they're equal, the Multicast RIB takes precedence. @end table The @code{mrib-then-urib} setting is the default behavior if nothing is configured. If this is the desired behavior, it should be explicitly configured to make the configuration immune against possible changes in what the default behavior is. WARNING: Unreachable routes do not receive special treatment and do not cause fallback to a second lookup. @end deffn @deffn Command {show ip rpf @var{addr}} {} Performs a Multicast RPF lookup, as configured with @command{ip multicast rpf-lookup-mode @var{mode}}. @var{addr} specifies the multicast source address to look up. @example > show ip rpf 192.0.2.1 Routing entry for 192.0.2.0/24 using Unicast RIB Known via "kernel", distance 0, metric 0, best * 198.51.100.1, via eth0 @end example Indicates that a multicast source lookup for 192.0.2.1 would use an Unicast RIB entry for 192.0.2.0/24 with a gateway of 198.51.100.1. @end deffn @deffn Command {show ip rpf} {} Prints the entire Multicast RIB. Note that this is independent of the configured RPF lookup mode, the Multicast RIB may be printed yet not used at all. @end deffn @deffn Command {ip mroute @var{prefix} @var{nexthop} [@var{distance}]} {} @deffnx Command {no ip mroute @var{prefix} @var{nexthop} [@var{distance}]} {} Adds a static route entry to the Multicast RIB. This performs exactly as the @command{ip route} command, except that it inserts the route in the Multicast RIB instead of the Unicast RIB. @end deffn @node zebra Route Filtering @section zebra Route Filtering Zebra supports @command{prefix-list} and @command{route-map} to match routes received from other quagga components. The @command{permit}/@command{deny} facilities provided by these commands can be used to filter which routes zebra will install in the kernel. @deffn Command {ip protocol @var{protocol} route-map @var{routemap}} {} Apply a route-map filter to routes for the specified protocol. @var{protocol} can be @b{any} or one of @b{system}, @b{kernel}, @b{connected}, @b{static}, @b{rip}, @b{ripng}, @b{ospf}, @b{ospf6}, @b{isis}, @b{bgp}, @b{hsls}. @end deffn @deffn {Route Map} {set src @var{address}} Within a route-map, set the preferred source address for matching routes when installing in the kernel. @end deffn The following creates a prefix-list that matches all addresses, a route-map that sets the preferred source address, and applies the route-map to all @command{rip} routes. @example @group ip prefix-list ANY permit 0.0.0.0/0 le 32 route-map RM1 permit 10 match ip address prefix-list ANY set src 10.0.0.1 ip protocol rip route-map RM1 @end group @end example @node zebra FIB push interface @section zebra FIB push interface Zebra supports a 'FIB push' interface that allows an external component to learn the forwarding information computed by the Quagga routing suite. In Quagga, the Routing Information Base (RIB) resides inside zebra. Routing protocols communicate their best routes to zebra, and zebra computes the best route across protocols for each prefix. This latter information makes up the Forwarding Information Base (FIB). Zebra feeds the FIB to the kernel, which allows the IP stack in the kernel to forward packets according to the routes computed by Quagga. The kernel FIB is updated in an OS-specific way. For example, the @code{netlink} interface is used on Linux, and route sockets are used on FreeBSD. The FIB push interface aims to provide a cross-platform mechanism to support scenarios where the router has a forwarding path that is distinct from the kernel, commonly a hardware-based fast path. In these cases, the FIB needs to be maintained reliably in the fast path as well. We refer to the component that programs the forwarding plane (directly or indirectly) as the Forwarding Plane Manager or FPM. The FIB push interface comprises of a TCP connection between zebra and the FPM. The connection is initiated by zebra -- that is, the FPM acts as the TCP server. The relevant zebra code kicks in when zebra is configured with the @code{--enable-fpm} flag. Zebra periodically attempts to connect to the well-known FPM port. Once the connection is up, zebra starts sending messages containing routes over the socket to the FPM. Zebra sends a complete copy of the forwarding table to the FPM, including routes that it may have picked up from the kernel. The existing interaction of zebra with the kernel remains unchanged -- that is, the kernel continues to receive FIB updates as before. The encapsulation header for the messages exchanged with the FPM is defined by the file @file{fpm/fpm.h} in the quagga tree. The routes themselves are encoded in netlink or protobuf format, with netlink being the default. Protobuf is one of a number of new serialization formats wherein the message schema is expressed in a purpose-built language. Code for encoding/decoding to/from the wire format is generated from the schema. Protobuf messages can be extended easily while maintaining backward-compatibility with older code. Protobuf has the following advantages over netlink: @itemize @item Code for serialization/deserialization is generated automatically. This reduces the likelihood of bugs, allows third-party programs to be integrated quickly, and makes it easy to add fields. @item The message format is not tied to an OS (Linux), and can be evolved independently. @end itemize As mentioned before, zebra encodes routes sent to the FPM in netlink format by default. The format can be controlled via the @code{--fpm_format} command-line option to zebra, which currently takes the values @code{netlink} and @code{protobuf}. The zebra FPM interface uses replace semantics. That is, if a 'route add' message for a prefix is followed by another 'route add' message, the information in the second message is complete by itself, and replaces the information sent in the first message. If the connection to the FPM goes down for some reason, zebra sends the FPM a complete copy of the forwarding table(s) when it reconnects. @node zebra Terminal Mode Commands @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 ip prefix-list [@var{name}]} {} @end deffn @deffn Command {show route-map [@var{name}]} {} @end deffn @deffn Command {show ip protocol} {} @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 @deffn Command {show zebra fpm stats} {} Display statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component. @end deffn @deffn Command {clear zebra fpm stats} {} Reset statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component. @end deffn quagga-1.2.4/doc/mdate-sh000077500000000000000000000136371325323223500151720ustar00rootroot00000000000000#!/bin/sh # Get modification time of a file or directory and pretty-print it. scriptversion=2010-08-21.06; # UTC # Copyright (C) 1995-2014 Free Software Foundation, Inc. # written by Ulrich Drepper , June 1995 # # 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, see . # 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. # This file is maintained in Automake, please report # bugs to or send patches to # . if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST fi case $1 in '') echo "$0: No file. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: mdate-sh [--help] [--version] FILE Pretty-print the modification day of FILE, in the format: 1 January 1970 Report bugs to . EOF exit $? ;; -v | --v*) echo "mdate-sh $scriptversion" exit $? ;; esac error () { echo "$0: $1" >&2 exit 1 } # Prevent date giving response in another language. LANG=C export LANG LC_ALL=C export LC_ALL LC_TIME=C export LC_TIME # GNU ls changes its time format in response to the TIME_STYLE # variable. Since we cannot assume 'unset' works, revert this # variable to its documented default. if test "${TIME_STYLE+set}" = set; then TIME_STYLE=posix-long-iso export TIME_STYLE fi save_arg1=$1 # Find out how to get the extended ls output of a file or directory. if ls -L /dev/null 1>/dev/null 2>&1; then ls_command='ls -L -l -d' else ls_command='ls -l -d' fi # Avoid user/group names that might have spaces, when possible. if ls -n /dev/null 1>/dev/null 2>&1; then ls_command="$ls_command -n" fi # A 'ls -l' line looks as follows on OS/2. # drwxrwx--- 0 Aug 11 2001 foo # This differs from Unix, which adds ownership information. # drwxrwx--- 2 root root 4096 Aug 11 2001 foo # # To find the date, we split the line on spaces and iterate on words # until we find a month. This cannot work with files whose owner is a # user named "Jan", or "Feb", etc. However, it's unlikely that '/' # will be owned by a user whose name is a month. So we first look at # the extended ls output of the root directory to decide how many # words should be skipped to get the date. # On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. set x`$ls_command /` # Find which argument is the month. month= command= until test $month do test $# -gt 0 || error "failed parsing '$ls_command /' output" shift # Add another shift to the command. command="$command shift;" case $1 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac done test -n "$month" || error "failed parsing '$ls_command /' output" # Get the extended ls output of the file or directory. set dummy x`eval "$ls_command \"\\\$save_arg1\""` # Remove all preceding arguments eval $command # Because of the dummy argument above, month is in $2. # # On a POSIX system, we should have # # $# = 5 # $1 = file size # $2 = month # $3 = day # $4 = year or time # $5 = filename # # On Darwin 7.7.0 and 7.6.0, we have # # $# = 4 # $1 = day # $2 = month # $3 = year or time # $4 = filename # Get the month. case $2 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac case $3 in ???*) day=$1;; *) day=$3; shift;; esac # Here we have to deal with the problem that the ls output gives either # the time of day or the year. case $3 in *:*) set `date`; eval year=\$$# case $2 in Jan) nummonthtod=1;; Feb) nummonthtod=2;; Mar) nummonthtod=3;; Apr) nummonthtod=4;; May) nummonthtod=5;; Jun) nummonthtod=6;; Jul) nummonthtod=7;; Aug) nummonthtod=8;; Sep) nummonthtod=9;; Oct) nummonthtod=10;; Nov) nummonthtod=11;; Dec) nummonthtod=12;; esac # For the first six month of the year the time notation can also # be used for files modified in the last year. if (expr $nummonth \> $nummonthtod) > /dev/null; then year=`expr $year - 1` fi;; *) year=$3;; esac # The result. echo $day $month $year # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: quagga-1.2.4/doc/mpls/000077500000000000000000000000001325323223500145035ustar00rootroot00000000000000quagga-1.2.4/doc/mpls/ChangeLog.opaque.txt000066400000000000000000000206741325323223500203750ustar00rootroot00000000000000----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2013.07.01 1. Feature enhancements 1.1 Update ospf_te.[c,h] in conformance to RFC3630 and clean the code. Add new directive to enable MPLS-TE per interface instead of globally 1.2 Add support for RFC4970 "Router Information" and RFC5088 "PCE Capabilities announcement". 1.3 Incorporate the mpls documentation into the main stream doc. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- 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. quagga-1.2.4/doc/mpls/cli_summary.txt000066400000000000000000000052551325323223500175770ustar00rootroot00000000000000Summary of CLI commands, expanded for Opaque-LSA/MPLS-TE. --------------------------------------------------------- router> show ip ospf database (asbr-summary|external|max-age|network|router|self-originate|summary|opaque-link|opaque-area|opaque-external) show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) (self-originate|) show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) A.B.C.D show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) A.B.C.D (self-originate|) show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) A.B.C.D adv-router A.B.C.D show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) adv-router A.B.C.D --> Add database items: opaque-link, opaque-area, opaque-external show mpls-te interface [INTERFACE] --> Show current MPLS-TE link-TLV parameters. If [INTERFACE] is omitted, all interfaces will be displayed. show mpls-te router --> Show current MPLS-TE Router-TLV parameters. router> enable router# router# configure terminal router(config)# interface [INTERFACE] router(config-if)# mpls-te link max-bw BANDWIDTH --> Set MPLS-TE link-TLV parameter: Maximum Bandwidth (Bytes/sec). In integer or floating point format (1000, or 1.0e3) mpls-te link max-rsv-bw BANDWIDTH --> Set MPLS-TE link-TLV parameter: Maximum Reservable Bandwidth (Bytes/sec). In integer or floating point format (1000, or 1.0e3) mpls-te link metric <0-4294967295> --> Set MPLS-TE link-TLV parameter: MPLS-TE metric. mpls-te link rsc-clsclr BITPATTERN --> Set MPLS-TE link-TLV parameter: Resource Class/Color. In 32-bit hexadecimal format, with leading "0x" (0x0 - 0xffffffff) mpls-te link unrsv-bw <0-7> BANDWIDTH --> Set MPLS-TE link-TLV parameter: Unreserved Bandwidth (Bytes/sec). In integer or floating point format (1000, or 1.0e3) router(config-if)# exit router(config)# router ospf router(config-router)# mpls-te --> Enable MPLS-TE functionality. Note that master-switch "ospf opaque-lsa" must also be specified. mpls-te on --> Alias of "mpls-te" command. mpls-te router-address A.B.C.D --> Set MPLS-TE Router-TLV parameter: Router Address. no mpls-te --> Disable MPLS-TE functionality. no ospf opaque-lsa --> Disable Opaque-LSAs capability. This node behaves Opaque-incapable node. ospf opaque-lsa --> Enable Opaque-LSAs capability. This is the master-switch to make this node Opaque-capable. router# exit quagga-1.2.4/doc/mpls/opaque_lsa.txt000066400000000000000000000550501325323223500174020ustar00rootroot000000000000001. List of "opaque-type dependent" callback functions per LSA-type. (N = 9,10,11) | | struct | list struct struct +-> +-------+ listnode listnode | head |-----> +------+ +------ | tail | | next |--------------------> | next | count | /--| prev |<---------------------| prev +-------+ | data |----+ | |///////| +------+ | +-------+ | | struct | ospf_opaque_tabent | +----------------------+ <--+ | opaque_type | +----------------------+ | (Callback functions) | +----------------------+ 2. Self-originated Opaque-LSAs per LSA-type. 2.1 Type-11 (AS-external) Opaque-LSAs struct ospf +---> +-------------------+ | |///////////////////| | +-------------------+ | | opaque | | +-------------------+ | |///////////////////| | +-------------------+ | | opaque_lsa_self |---+ | +-------------------+ | | |///////////////////| | | +-------------------+ | | | ......|.............................|....................................... : | | Almost common for type-9,10,11 LSA : : | +-----------------------+ : : | | : : | | struct : : | | list struct struct : : | +-> +-------+ listnode listnode : : | | head |-----> +------+ +------ : : | | tail | | next |--------------------> | next : : | | count | /--| prev |<---------------------| prev : : | +-------+ | data |---+ | : : | |///////| +------+ | : : | +-------+ | : : | | : : | struct | : : | opaque_info_per_type | : : | +-------------------+ <--------+ : : | | opaque_type | <------------+ : : | +-------------------+ | : : | | status | | : : | +-------------------+ | : : | | t_opaque_lsa_self | | : : | +-------------------+ | : : +-----| owner | | struct : : +-------------------+ | ospf_opaque_tabent : : | functab |-------------------> +---------------- : : +-------------------+ | | opaque_type : : | id_list |---+ | |(Callback Funcs) : : +-------------------+ | | | : : | | : : +-----------------------+ | : : | | : : | struct | : : | list struct | struct : : +-> +-------+ listnode | listnode : : | head |-----> +------+ | +------ : : | tail | | next |--------------------> | next : : | count | /--| prev |<---------------------| prev : : +-------+ | data |---+ | | : : |///////| +------+ | | : : +-------+ | | : : | | : : struct | | : : opaque_info_per_id | | : : +-------------------+ <--------+ | : : | opaque_id | | : : +-------------------+ | : : | t_opaque_lsa_self | | : : +-------------------+ | : : | opqctl_type |--------------+ : : +-------------------+ : : | lsa |---+ : : +-------------------+ | : : | : : struct | : : ospf_lsa | : : +-------------+ <-------+ : : |/////////////| struct : : +-------------+ lsa_header : : | data |--------------> +-------- : : +-------------+ | : : |/////////////| : : +-------------+ : : +--------| area | : : | +-------------+ : : --- |/////////////| : : +-------------+ : : +-----| oi | : : | +-------------+ : : --- : :..........................................................................: 2.2 Type-10 (area-local) Opaque-LSAs struct ospf +---------+ <-----------+ |/////////| | +---------+ | | struct | ospf_area | +--+---> +-----------------+ | | | | top |-----+ | | +-----------------+ | | |/////////////////| struct | | +-----------------+ ospf_lsa | | | router_lsa_self |-----------> +--------- | | +-----------------+ | | | | opaque_lsa_self |-----+ | | | +-----------------+ | | | |/////////////////| | | | +-----------------+ | | | | ...|..|.............................|....................................... : | | | Almost common for type-9,10,11 LSA : : | | +-----------------------+ : : | | | : : | | | struct : : | | | list struct struct : : | | +-> +-------+ listnode listnode : : | | | head |-----> +------+ +------ : : | | | tail | | next |--------------------> | next : : | | | count | /--| prev |<---------------------| prev : : | | +-------+ | data |---+ | : : | | |///////| +------+ | : : | | +-------+ | : : | | | : : | | struct | : : | | opaque_info_per_type | : : | | +-------------------+ <--------+ : : | | | opaque_type | <------------+ : : | | +-------------------+ | : : | | | status | | : : | | +-------------------+ | : : | | | t_opaque_lsa_self | | : : | | +-------------------+ | : : | +-----| owner | | struct : : | +-------------------+ | ospf_opaque_tabent : : | | functab |-------------------> +---------------- : : | +-------------------+ | | opaque_type : : | | id_list |---+ | |(Callback Funcs) : : | +-------------------+ | | | : : | | | : : | +-----------------------+ | : : | | | : : | | struct | : : | | list struct | struct : : | +-> +-------+ listnode | listnode : : | | head |-----> +------+ | +------ : : | | tail | | next |--------------------> | next : : | | count | /--| prev |<---------------------| prev : : | +-------+ | data |---+ | | : : | |///////| +------+ | | : : | +-------+ | | : : | | | : : | struct | | : : | opaque_info_per_id | | : : | +-------------------+ <--------+ | : : | | opaque_id | | : : | +-------------------+ | : : | | t_opaque_lsa_self | | : : | +-------------------+ | : : | | opqctl_type |--------------+ : : | +-------------------+ : : | | lsa |---+ : : | +-------------------+ | : : | | : : | struct | : : | ospf_lsa | : : | +-------------+ <-------+ : : | |/////////////| struct : : | +-------------+ lsa_header : : | | data |--------------> +-------- : : | +-------------+ | : : | |/////////////| : : | +-------------+ : : +--------| area | : : +-------------+ : : |/////////////| : : +-------------+ : : +-----| oi | : : | +-------------+ : : --- : :..........................................................................: 2.3 Type-9 (link-local) Opaque-LSAs struct ospf_area +------> +---------+ <---------+ | |/////////| | | +---------+ | | | | struct | | ospf_interface | | +-+-> +-----------------+ | | | | |/////////////////| | | | | +-----------------+ | | | | | area |---+ | | | +-----------------+ | | | |/////////////////| struct | | | +-----------------+ ospf_lsa | | | |network_lsa_self |-----------> +--------- | | | +-----------------+ | | | | | opaque_lsa_self |-----+ | | | | +-----------------+ | | | | |/////////////////| | | | | +-----------------+ | | | | | ...|..|.|...........................|....................................... : | | | | Almost common for type-9,10,11 LSA : : | | | +-----------------------+ : : | | | | : : | | | | struct : : | | | | list struct struct : : | | | +-> +-------+ listnode listnode : : | | | | head |-----> +------+ +------ : : | | | | tail | | next |--------------------> | next : : | | | | count | /--| prev |<---------------------| prev : : | | | +-------+ | data |---+ | : : | | | |///////| +------+ | : : | | | +-------+ | : : | | | | : : | | | struct | : : | | | opaque_info_per_type | : : | | | +-------------------+ <--------+ : : | | | | opaque_type | <------------+ : : | | | +-------------------+ | : : | | | | status | | : : | | | +-------------------+ | : : | | | | t_opaque_lsa_self | | : : | | | +-------------------+ | : : | | +---| owner | | struct : : | | +-------------------+ | ospf_opaque_tabent : : | | | functab |-------------------> +---------------- : : | | +-------------------+ | | opaque_type : : | | | id_list |---+ | |(Callback Funcs) : : | | +-------------------+ | | | : : | | | | : : | | +-----------------------+ | : : | | | | : : | | | struct | : : | | | list struct | struct : : | | +-> +-------+ listnode | listnode : : | | | head |-----> +------+ | +------ : : | | | tail | | next |--------------------> | next : : | | | count | /--| prev |<---------------------| prev : : | | +-------+ | data |---+ | | : : | | |///////| +------+ | | : : | | +-------+ | | : : | | | | : : | | struct | | : : | | opaque_info_per_id | | : : | | +-------------------+ <--------+ | : : | | | opaque_id | | : : | | +-------------------+ | : : | | | t_opaque_lsa_self | | : : | | +-------------------+ | : : | | | opqctl_type |--------------+ : : | | +-------------------+ : : | | | lsa |---+ : : | | +-------------------+ | : : | | | : : | | struct | : : | | ospf_lsa | : : | | +-------------+ <-------+ : : | | |/////////////| struct : : | | +-------------+ lsa_header : : | | | data |--------------> +-------- : : | | +-------------+ | : : | | |/////////////| : : | | +-------------+ : : +--|-----| area | : : | +-------------+ : : | |/////////////| : : | +-------------+ : : +-----| oi | : : +-------------+ : :..........................................................................: 3. Internal structures for MPLS-TE parameter management. struct ospf_mpls_te +-------------+ | status | +-------------+ | iflist |---+ +-------------+ | |(Router-TLV) | | +-------------+ | | +---------------------+ | | struct | list struct struct +---> +-------+ listnode listnode | head |-----> +------+ +------ | tail | | next |--------------------> | next | count | /--| prev |<---------------------| prev +-------+ | data |---+ | |///////| +------+ | +-------+ | | +--------------------------------+ | | struct | ospf_mpls_te_linkparms +-> +----------------+ | instance | struct +----------------+ interface | ifp |--------------------> +----------+ +----------------+ +----> |//////////| | area |----+ | +----------+ +----------------+ | | | info |-----+ | flags | | | +----------+ | +----------------+ | | |//////////| | | (Link-TLV) | | | +----------+ | +----------------+ | | | | (Link-SubTLVs) | | | struct | +----------------+ | | ospf_if_info | | | +----------+ <---+ | | |//////////| struct | | +----------+ ospf_area | | | oifs |-----+ +-> +--------------+ <----+ | +----------+ | | |//////////////| | | | +--------------+ | struct | | | route_table | | struct | +-----------+ <--+ | ospf_interface | | route_top | - - - - -. | +--------------+ <----+ | +-----------+ . | |//////////////| | | . | +--------------+ | | struct . | | ifp |------|----------+ route_node . | +--------------+ | +-----------+ < - - - - | |//////////////| | |///////////| | +--------------+ | +-----------+ +---| area | +-----------------| info | +--------------+ +-----------+ |//////////////| |///////////| +--------------+ +-----------+ quagga-1.2.4/doc/mpls/ospfd.conf000066400000000000000000000030701325323223500164650ustar00rootroot00000000000000! ! Zebra configuration saved from vty ! 2001/03/16 22:07:53 ! hostname HOSTNAME password PASSWORD log file /var/log/ospfd.log ! debug ospf ism debug ospf nsm debug ospf lsa debug ospf zebra debug ospf event debug ospf packet all detail ! ! interface fxp0 ip ospf hello-interval 60 ip ospf dead-interval 240 mpls-te on mpls-te link metric 999 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab ! interface de1 ip ospf hello-interval 60 ip ospf dead-interval 240 mpls-te link metric 111 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xcd ! interface de0 mpls-te link metric 0 mpls-te link rsc-clsclr 0x0 ! interface lp0 ip ospf network point-to-point ! interface tun0 ip ospf network point-to-point ! interface sl0 ip ospf network point-to-point ! interface ppp0 ip ospf network point-to-point ! interface lo0 ! router ospf compatible rfc1583 network 192.168.0.0/16 area 1 ospf opaque-lsa mpls-te mpls-te router-address 1.2.3.4 ! line vty ! quagga-1.2.4/doc/nhrpd.8000066400000000000000000000050021325323223500147310ustar00rootroot00000000000000.TH NHRP 8 "24 January 2017" "Quagga NHRP daemon" "Version 1.1" .SH NAME nhrpd \- a Next Hop Routing Protocol routing engine for use with Quagga routing software. .SH SYNOPSIS .B nhrpd [ .B \-dhv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B nhrpd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B nhrpd command: .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/nhrpd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When nhrpd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart nhrpd. The likely default is \fB\fI/var/run/nhrpd.pid\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the nhrpd VTY will listen on. This defaults to 2608, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the nhrpd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/nhrpd The default location of the .B nhrpd binary. .TP .BI /usr/local/etc/nhrpd.conf The default location of the .B nhrpd config file. .TP .BI $(PWD)/nhrpd.log If the .B nhrpd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBnhrpd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The nhrpd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBnhrpd\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR zebra (8), .BR vtysh (1) .B nhrpd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS Timo Teräs quagga-1.2.4/doc/nhrpd.texi000066400000000000000000000105131325323223500155360ustar00rootroot00000000000000@cindex NHRP @node NHRP @chapter NHRP @command{nhrpd} is a daemon to support Next Hop Routing Protocol (NHRP). NHRP is described in RFC2332. NHRP is used to improve the efficiency of routing computer network traffic over Non-Broadcast, Multiple Access (NBMA) Networks. NHRP provides an ARP-like solution that allows a system to dynamically learn the NBMA address of the other systems that are part of that network, allowing these systems to directly communicate without requiring traffic to use an intermediate hop. Cisco Dynamic Multipoint VPN (DMVPN) is based on NHRP, and Quagga nrhpd implements this scenario. @menu * Routing Design:: * Configuring NHRP:: * Hub Functionality:: * Integration with IKE:: * NHRP Events:: * Configuration Example:: @end menu @node Routing Design @section Routing Design nhrpd never handles routing of prefixes itself. You need to run some real routing protocol (e.g. BGP) to advertise routes over the tunnels. What nhrpd does it establishes 'shortcut routes' that optimizes the routing protocol to avoid going through extra nodes in NBMA GRE mesh. nhrpd does route NHRP domain addresses individually using per-host prefixes. This is similar to Cisco FlexVPN; but in contrast to opennhrp which uses a generic subnet route. To create NBMA GRE tunnel you might use the following (linux terminal commands): @example @group ip tunnel add gre1 mode gre key 42 ttl 64 ip addr add 10.255.255.2/32 dev gre1 ip link set gre1 up @end group @end example Note that the IP-address is assigned as host prefix to gre1. nhrpd will automatically create additional host routes pointing to gre1 when a connection with these hosts is established. The gre1 subnet prefix should be announced by routing protocol from the hub nodes (e.g. BGP 'network' announce). This allows the routing protocol to decide which is the closest hub and determine the relay hub on prefix basis when direct tunnel is not established. nhrpd will redistribute directly connected neighbors to zebra. Within hub nodes, these routes should be internally redistributed using some routing protocol (e.g. iBGP) to allow hubs to be able to relay all traffic. This can be achieved in hubs with the following bgp configuration (network command defines the GRE subnet): @example @group router bgp 65555 network 172.16.0.0/16 redistribute nhrp @end group @end example @node Configuring NHRP @section Configuring NHRP FIXME @node Hub Functionality @section Hub Functionality In addition to routing nhrp redistributed host prefixes, the hub nodes are also responsible to send NHRP Traffic Indication messages that trigger creation of the shortcut tunnels. nhrpd sends Traffic Indication messages based on network traffic captured using NFLOG. Typically you want to send Traffic Indications for network traffic that is routed from gre1 back to gre1 in rate limited manner. This can be achieved with the following iptables rule. @example @group iptables -A FORWARD -i gre1 -o gre1 \ -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \ --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 \ --hashlimit-dstmask 24 --hashlimit-name loglimit-0 \ -j NFLOG --nflog-group 1 --nflog-range 128 @end group @end example You can fine tune the src/dstmask according to the prefix lengths you announce internal, add additional IP range matches, or rate limitation if needed. However, the above should be good in most cases. This kernel NFLOG target's nflog-group is configured in global nhrp config with: @example @group nhrp nflog-group 1 @end group @end example To start sending these traffic notices out from hubs, use the nhrp per-interface directive: @example @group interface gre1 ip nhrp redirect @end group @end example @node Integration with IKE @section Integration with IKE nhrpd needs tight integration with IKE daemon for various reasons. Currently only strongSwan is supported as IKE daemon. nhrpd connects to strongSwan using VICI protocol based on UNIX socket (hardcoded now as /var/run/charon.vici). strongSwan currently needs few patches applied. Please check out the @uref{http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras-release,release} and @uref{http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras,working tree} git repositories for the patches. @node NHRP Events @section NHRP Events FIXME @node Configuration Example @section Configuration Example FIXME quagga-1.2.4/doc/ospf6d.8000066400000000000000000000051631325323223500150270ustar00rootroot00000000000000.TH OSPF6D 8 "25 November 2004" "Quagga OSPFv3 daemon" "Version 0.97.3" .SH NAME ospf6d \- an OSPFv3 routing engine for use with Quagga routing software. .SH SYNOPSIS .B ospf6d [ .B \-dhv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B ospf6d is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B ospf6d command: .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\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\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 identifier 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\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the ospf6d VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .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 to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\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" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B ospf6d eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-1.2.4/doc/ospf6d.texi000066400000000000000000000126741325323223500156360ustar00rootroot00000000000000@node OSPFv3 @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:: * OSPF6 Configuration Examples:: @end menu @node OSPF6 router @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 @deffn {OSPF6 Command} {timers throttle spf @var{delay} @var{initial-holdtime} @var{max-holdtime}} {} @deffnx {OSPF6 Command} {no timers throttle spf} {} This command sets the initial @var{delay}, the @var{initial-holdtime} and the @var{maximum-holdtime} between when SPF is calculated and the event which triggered the calculation. The times are specified in milliseconds and must be in the range of 0 to 600000 milliseconds. The @var{delay} specifies the minimum amount of time to delay SPF calculation (hence it affects how long SPF calculation is delayed after an event which occurs outside of the holdtime of any previous SPF calculation, and also serves as a minimum holdtime). Consecutive SPF calculations will always be seperated by at least 'hold-time' milliseconds. The hold-time is adaptive and initially is set to the @var{initial-holdtime} configured with the above command. Events which occur within the holdtime of the previous SPF calculation will cause the holdtime to be increased by @var{initial-holdtime}, bounded by the @var{maximum-holdtime} configured with this command. If the adaptive hold-time elapses without any SPF-triggering event occuring then the current holdtime is reset to the @var{initial-holdtime}. @example @group router ospf6 timers throttle spf 200 400 10000 @end group @end example In this example, the @var{delay} is set to 200ms, the @var{initial holdtime} is set to 400ms and the @var{maximum holdtime} to 10s. Hence there will always be at least 200ms between an event which requires SPF calculation and the actual SPF calculation. Further consecutive SPF calculations will always be seperated by between 400ms to 10s, the hold-time increasing by 400ms each time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. @end deffn @deffn {OSPF6 Command} {auto-cost reference-bandwidth @var{cost}} {} @deffnx {OSPF6 Command} {no auto-cost reference-bandwidth} {} This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain. @end deffn @node OSPF6 area @section OSPF6 area Area support for OSPFv3 is not yet implemented. @node OSPF6 interface @section OSPF6 interface @deffn {Interface Command} {ipv6 ospf6 cost COST} {} Sets interface's output cost. Default value depends on the interface bandwidth and on the auto-cost reference bandwidth. @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 @deffn {Interface Command} {ipv6 ospf6 network (broadcast|point-to-point)} {} Set explicitly network type for specifed interface. @end deffn @node Redistribute routes to OSPF6 @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 @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 @node OSPF6 Configuration Examples @section OSPF6 Configuration Examples Example of ospf6d configured on one interface and area: @example interface eth0 ipv6 ospf6 instance-id 0 ! router ospf6 router-id 212.17.55.53 area 0.0.0.0 range 2001:770:105:2::/64 interface eth0 area 0.0.0.0 ! @end example quagga-1.2.4/doc/ospf_fundamentals.texi000066400000000000000000000476011325323223500201430ustar00rootroot00000000000000@c Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. @cindex OSPF Fundamentals @node OSPF Fundamentals @section OSPF Fundamentals @cindex Link-state routing protocol @cindex Distance-vector routing protocol @acronym{OSPF} is, mostly, a link-state routing protocol. In contrast to @dfn{distance-vector} protocols, such as @acronym{RIP} or @acronym{BGP}, where routers describe available @dfn{paths} (i.e@. routes) to each other, in @dfn{link-state} protocols routers instead describe the state of their links to their immediate neighbouring routers. @cindex Link State Announcement @cindex Link State Advertisement @cindex LSA flooding @cindex Link State DataBase Each router describes their link-state information in a message known as an @acronym{LSA,Link State Advertisement}, which is then propogated through to all other routers in a link-state routing domain, by a process called @dfn{flooding}. Each router thus builds up an @acronym{LSDB,Link State Database} of all the link-state messages. From this collection of LSAs in the LSDB, each router can then calculate the shortest path to any other router, based on some common metric, by using an algorithm such as @url{http://www.cs.utexas.edu/users/EWD/, Edgser Dijkstra}'s @acronym{SPF,Shortest Path First}. @cindex Link-state routing protocol advantages By describing connectivity of a network in this way, in terms of routers and links rather than in terms of the paths through a network, a link-state protocol can use less bandwidth and converge more quickly than other protocols. A link-state protocol need distribute only one link-state message throughout the link-state domain when a link on any single given router changes state, in order for all routers to reconverge on the best paths through the network. In contrast, distance vector protocols can require a progression of different path update messages from a series of different routers in order to converge. @cindex Link-state routing protocol disadvantages The disadvantage to a link-state protocol is that the process of computing the best paths can be relatively intensive when compared to distance-vector protocols, in which near to no computation need be done other than (potentially) select between multiple routes. This overhead is mostly negligible for modern embedded CPUs, even for networks with thousands of nodes. The primary scaling overhead lies more in coping with the ever greater frequency of LSA updates as the size of a link-state area increases, in managing the @acronym{LSDB} and required flooding. This section aims to give a distilled, but accurate, description of the more important workings of @acronym{OSPF}@ which an administrator may need to know to be able best configure and trouble-shoot @acronym{OSPF}@. @subsection OSPF Mechanisms @acronym{OSPF} defines a range of mechanisms, concerned with detecting, describing and propogating state through a network. These mechanisms will nearly all be covered in greater detail further on. They may be broadly classed as: @table @dfn @cindex OSPF Hello Protocol overview @item The Hello Protocol @cindex OSPF Hello Protocol The OSPF Hello protocol allows OSPF to quickly detect changes in two-way reachability between routers on a link. OSPF can additionally avail of other sources of reachability information, such as link-state information provided by hardware, or through dedicated reachability protocols such as @acronym{BFD,Bi-directional Forwarding Detection}. OSPF also uses the Hello protocol to propagate certain state between routers sharing a link, for example: @itemize @bullet @item Hello protocol configured state, such as the dead-interval. @item Router priority, for DR/BDR election. @item DR/BDR election results. @item Any optional capabilities supported by each router. @end itemize The Hello protocol is comparatively trivial and will not be explored in greater detail than here. @cindex OSPF LSA overview @item LSAs At the heart of @acronym{OSPF} are @acronym{LSA,Link State Advertisement} messages. Despite the name, some @acronym{LSA}s do not, strictly speaking, describe link-state information. Common @acronym{LSA}s describe information such as: @itemize @bullet @item Routers, in terms of their links. @item Networks, in terms of attached routers. @item Routes, external to a link-state domain: @itemize @bullet @item External Routes Routes entirely external to @acronym{OSPF}@. Routers originating such routes are known as @acronym{ASBR,Autonomous-System Border Router} routers. @item Summary Routes Routes which summarise routing information relating to OSPF areas external to the OSPF link-state area at hand, originated by @acronym{ABR,Area Boundary Router} routers. @end itemize @end itemize @item LSA Flooding OSPF defines several related mechanisms, used to manage synchronisation of @acronym{LSDB}s between neighbours as neighbours form adjacencies and the propogation, or @dfn{flooding} of new or updated @acronym{LSA}s. @xref{OSPF Flooding}. @cindex OSPF Areas overview @item Areas OSPF provides for the protocol to be broken up into multiple smaller and independent link-state areas. Each area must be connected to a common backbone area by an @acronym{ABR,Area Boundary Router}. These @acronym{ABR} routers are responsible for summarising the link-state routing information of an area into @dfn{Summary LSAs}, possibly in a condensed (i.e. aggregated) form, and then originating these summaries into all other areas the @acronym{ABR} is connected to. Note that only summaries and external routes are passed between areas. As these describe @emph{paths}, rather than any router link-states, routing between areas hence is by @dfn{distance-vector}, @strong{not} link-state. @xref{OSPF Areas}. @end table @subsection OSPF LSAs @acronym{LSA}s are the core object in OSPF@. Everything else in OSPF revolves around detecting what to describe in LSAs, when to update them, how to flood them throughout a network and how to calculate routes from them. There are a variety of different @acronym{LSA}s, for purposes such as describing actual link-state information, describing paths (i.e. routes), describing bandwidth usage of links for @acronym{TE,Traffic Engineering} purposes, and even arbitrary data by way of @emph{Opaque} @acronym{LSA}s. @subsubsection LSA Header All LSAs share a common header with the following information: @itemize @bullet @item Type Different types of @acronym{LSA}s describe different things in @acronym{OSPF}@. Types include: @itemize @bullet @item Router LSA @item Network LSA @item Network Summary LSA @item Router Summary LSA @item AS-External LSA @end itemize The specifics of the different types of LSA are examined below. @item Advertising Router The Router ID of the router originating the LSA, see @ref{ospf router-id}. @item LSA ID The ID of the LSA, which is typically derived in some way from the information the LSA describes, e.g. a Router LSA uses the Router ID as the LSA ID, a Network LSA will have the IP address of the @acronym{DR} as its LSA ID@. The combination of the Type, ID and Advertising Router ID must uniquely identify the @acronym{LSA}@. There can however be multiple instances of an LSA with the same Type, LSA ID and Advertising Router ID, see @ref{OSPF LSA sequence number,,LSA Sequence Number}. @item Age A number to allow stale @acronym{LSA}s to, eventually, be purged by routers from their @acronym{LSDB}s. The value nominally is one of seconds. An age of 3600, i.e. 1 hour, is called the @dfn{MaxAge}. MaxAge LSAs are ignored in routing calculations. LSAs must be periodically refreshed by their Advertising Router before reaching MaxAge if they are to remain valid. Routers may deliberately flood LSAs with the age artificially set to 3600 to indicate an LSA is no longer valid. This is called @dfn{flushing} of an LSA@. It is not abnormal to see stale LSAs in the LSDB, this can occur where a router has shutdown without flushing its LSA(s), e.g. where it has become disconnected from the network. Such LSAs do little harm. @anchor{OSPF LSA sequence number} @item Sequence Number A number used to distinguish newer instances of an LSA from older instances. @end itemize @subsubsection Link-State LSAs Of all the various kinds of @acronym{LSA}s, just two types comprise the actual link-state part of @acronym{OSPF}, Router @acronym{LSA}s and Network @acronym{LSA}s. These LSA types are absolutely core to the protocol. Instances of these LSAs are specific to the link-state area in which they are originated. Routes calculated from these two LSA types are called @dfn{intra-area routes}. @itemize @bullet @item Router LSA Each OSPF Router must originate a router @acronym{LSA} to describe itself. In it, the router lists each of its @acronym{OSPF} enabled interfaces, for the given link-state area, in terms of: @itemize @bullet @item Cost The output cost of that interface, scaled inversely to some commonly known reference value, @xref{OSPF auto-cost reference-bandwidth,,auto-cost reference-bandwidth}. @item Link Type @itemize @bullet @item Transit Network A link to a multi-access network, on which the router has at least one Full adjacency with another router. @item @acronym{PtP,Point-to-Point} A link to a single remote router, with a Full adjacency. No @acronym{DR, Designated Router} is elected on such links; no network LSA is originated for such a link. @item Stub A link with no adjacent neighbours, or a host route. @end itemize @item Link ID and Data These values depend on the Link Type: @multitable @columnfractions .18 .32 .32 @headitem Link Type @tab Link ID @tab Link Data @item Transit @tab Link IP address of the @acronym{DR} @tab Interface IP address @item Point-to-Point @tab Router ID of the remote router @tab Local interface IP address, or the @acronym{ifindex,MIB-II interface index} for unnumbered links @item Stub @tab IP address @tab Subnet Mask @end multitable @end itemize Links on a router may be listed multiple times in the Router LSA, e.g. a @acronym{PtP} interface on which OSPF is enabled must @emph{always} be described by a Stub link in the Router @acronym{LSA}, in addition to being listed as PtP link in the Router @acronym{LSA} if the adjacency with the remote router is Full. Stub links may also be used as a way to describe links on which OSPF is @emph{not} spoken, known as @dfn{passive interfaces}, see @ref{OSPF passive-interface,,passive-interface}. @item Network LSA On multi-access links (e.g. ethernets, certain kinds of ATM and X@.25 configurations), routers elect a @acronym{DR}@. The @acronym{DR} is responsible for originating a Network @acronym{LSA}, which helps reduce the information needed to describe multi-access networks with multiple routers attached. The @acronym{DR} also acts as a hub for the flooding of @acronym{LSA}s on that link, thus reducing flooding overheads. The contents of the Network LSA describes the: @itemize @bullet @item Subnet Mask As the @acronym{LSA} ID of a Network LSA must be the IP address of the @acronym{DR}, the Subnet Mask together with the @acronym{LSA} ID gives you the network address. @item Attached Routers Each router fully-adjacent with the @acronym{DR} is listed in the LSA, by their Router-ID. This allows the corresponding Router @acronym{LSA}s to be easily retrieved from the @acronym{LSDB}@. @end itemize @end itemize Summary of Link State LSAs: @multitable @columnfractions .18 .32 .40 @headitem LSA Type @tab LSA ID Describes @tab LSA Data Describes @item Router LSA @tab The Router ID @tab The @acronym{OSPF} enabled links of the router, within a specific link-state area. @item Network LSA @tab The IP address of the @acronym{DR} for the network @tab The Subnet Mask of the network, and the Router IDs of all routers on the network. @end multitable With an LSDB composed of just these two types of @acronym{LSA}, it is possible to construct a directed graph of the connectivity between all routers and networks in a given OSPF link-state area. So, not surprisingly, when OSPF routers build updated routing tables, the first stage of @acronym{SPF} calculation concerns itself only with these two LSA types. @subsubsection Link-State LSA Examples The example below (@pxref{OSPF Link-State LSA Example}) shows two @acronym{LSA}s, both originated by the same router (Router ID 192.168.0.49) and with the same @acronym{LSA} ID (192.168.0.49), but of different LSA types. The first LSA being the router LSA describing 192.168.0.49's links: 2 links to multi-access networks with fully-adjacent neighbours (i.e. Transit links) and 1 being a Stub link (no adjacent neighbours). The second LSA being a Network LSA, for which 192.168.0.49 is the @acronym{DR}, listing the Router IDs of 4 routers on that network which are fully adjacent with 192.168.0.49. @anchor{OSPF Link-State LSA Example} @example # show ip ospf database router 192.168.0.49 OSPF Router with ID (192.168.0.53) Router Link States (Area 0.0.0.0) LS age: 38 Options: 0x2 : *|-|-|-|-|-|E|* LS Flags: 0x6 Flags: 0x2 : ASBR LS Type: router-LSA Link State ID: 192.168.0.49 Advertising Router: 192.168.0.49 LS Seq Number: 80000f90 Checksum: 0x518b Length: 60 Number of Links: 3 Link connected to: a Transit Network (Link ID) Designated Router address: 192.168.1.3 (Link Data) Router Interface address: 192.168.1.3 Number of TOS metrics: 0 TOS 0 Metric: 10 Link connected to: a Transit Network (Link ID) Designated Router address: 192.168.0.49 (Link Data) Router Interface address: 192.168.0.49 Number of TOS metrics: 0 TOS 0 Metric: 10 Link connected to: Stub Network (Link ID) Net: 192.168.3.190 (Link Data) Network Mask: 255.255.255.255 Number of TOS metrics: 0 TOS 0 Metric: 39063 # show ip ospf database network 192.168.0.49 OSPF Router with ID (192.168.0.53) Net Link States (Area 0.0.0.0) LS age: 285 Options: 0x2 : *|-|-|-|-|-|E|* LS Flags: 0x6 LS Type: network-LSA Link State ID: 192.168.0.49 (address of Designated Router) Advertising Router: 192.168.0.49 LS Seq Number: 80000074 Checksum: 0x0103 Length: 40 Network Mask: /29 Attached Router: 192.168.0.49 Attached Router: 192.168.0.52 Attached Router: 192.168.0.53 Attached Router: 192.168.0.54 @end example Note that from one LSA, you can find the other. E.g. Given the Network-LSA you have a list of Router IDs on that network, from which you can then look up, in the local @acronym{LSDB}, the matching Router LSA@. From that Router-LSA you may (potentially) find links to other Transit networks and Routers IDs which can be used to lookup the corresponding Router or Network LSA@. And in that fashion, one can find all the Routers and Networks reachable from that starting @acronym{LSA}@. Given the Router LSA instead, you have the IP address of the @acronym{DR} of any attached transit links. Network LSAs will have that IP as their LSA ID, so you can then look up that Network LSA and from that find all the attached routers on that link, leading potentially to more links and Network and Router LSAs, etc. etc. From just the above two @acronym{LSA}s, one can already see the following partial topology: @example @group --------------------- Network: ...... | Designated Router IP: 192.168.1.3 | IP: 192.168.1.3 (transit link) (cost: 10) Router ID: 192.168.0.49(stub)---------- IP: 192.168.3.190/32 (cost: 10) (cost: 39063) (transit link) IP: 192.168.0.49 | | ------------------------------ Network: 192.168.0.48/29 | | | Designated Router IP: 192.168.0.49 | | | | | Router ID: 192.168.0.54 | | | Router ID: 192.168.0.53 | Router ID: 192.168.0.52 @end group @end example Note the Router IDs, though they look like IP addresses and often are IP addresses, are not strictly speaking IP addresses, nor need they be reachable addresses (though, OSPF will calculate routes to Router IDs). @subsubsection External LSAs External, or "Type 5", @acronym{LSA}s describe routing information which is entirely external to @acronym{OSPF}, and is "injected" into @acronym{OSPF}@. Such routing information may have come from another routing protocol, such as RIP or BGP, they may represent static routes or they may represent a default route. An @acronym{OSPF} router which originates External @acronym{LSA}s is known as an @acronym{ASBR,AS Boundary Router}. Unlike the link-state @acronym{LSA}s, and most other @acronym{LSA}s, which are flooded only within the area in which they originate, External @acronym{LSA}s are flooded through-out the @acronym{OSPF} network to all areas capable of carrying External @acronym{LSA}s (@pxref{OSPF Areas}). Routes internal to OSPF (intra-area or inter-area) are always preferred over external routes. The External @acronym{LSA} describes the following: @itemize @bullet @item IP Network number The IP Network number of the route is described by the @acronym{LSA} ID field. @item IP Network Mask The body of the External LSA describes the IP Network Mask of the route. This, together with the @acronym{LSA} ID, describes the prefix of the IP route concerned. @item Metric The cost of the External Route. This cost may be an OSPF cost (also known as a "Type 1" metric), i.e. equivalent to the normal OSPF costs, or an externally derived cost ("Type 2" metric) which is not comparable to OSPF costs and always considered larger than any OSPF cost. Where there are both Type 1 and 2 External routes for a route, the Type 1 is always preferred. @item Forwarding Address The address of the router to forward packets to for the route. This may be, and usually is, left as 0 to specify that the ASBR originating the External @acronym{LSA} should be used. There must be an internal OSPF route to the forwarding address, for the forwarding address to be useable. @item Tag An arbitrary 4-bytes of data, not interpreted by OSPF, which may carry whatever information about the route which OSPF speakers desire. @end itemize @subsubsection AS External LSA Example To illustrate, below is an example of an External @acronym{LSA} in the @acronym{LSDB} of an OSPF router. It describes a route to the IP prefix of 192.168.165.0/24, originated by the ASBR with Router-ID 192.168.0.49. The metric of 20 is external to OSPF. The forwarding address is 0, so the route should forward to the originating ASBR if selected. @example @group # show ip ospf database external 192.168.165.0 LS age: 995 Options: 0x2 : *|-|-|-|-|-|E|* LS Flags: 0x9 LS Type: AS-external-LSA Link State ID: 192.168.165.0 (External Network Number) Advertising Router: 192.168.0.49 LS Seq Number: 800001d8 Checksum: 0xea27 Length: 36 Network Mask: /24 Metric Type: 2 (Larger than any link state path) TOS: 0 Metric: 20 Forward Address: 0.0.0.0 External Route Tag: 0 @end group @end example We can add this to our partial topology from above, which now looks like: @example @group --------------------- Network: ...... | Designated Router IP: 192.168.1.3 | IP: 192.168.1.3 /---- External route: 192.168.165.0/24 (transit link) / Cost: 20 (External metric) (cost: 10) / Router ID: 192.168.0.49(stub)---------- IP: 192.168.3.190/32 (cost: 10) (cost: 39063) (transit link) IP: 192.168.0.49 | | ------------------------------ Network: 192.168.0.48/29 | | | Designated Router IP: 192.168.0.49 | | | | | Router ID: 192.168.0.54 | | | Router ID: 192.168.0.53 | Router ID: 192.168.0.52 @end group @end example @subsubsection Summary LSAs Summary LSAs are created by @acronym{ABR}s to summarise the destinations available within one area to other areas. These LSAs may describe IP networks, potentially in aggregated form, or @acronym{ASBR} routers. @anchor{OSPF Flooding} @subsection OSPF Flooding @anchor{OSPF Areas} @subsection OSPF Areas quagga-1.2.4/doc/ospfclient.8000066400000000000000000000016661325323223500160000ustar00rootroot00000000000000.\" This file was originally generated by help2man 1.36. .TH OSPFCLIENT "8" "July 2010" .SH NAME ospfclient \- an example ospf-api client .SH SYNOPSIS .B ospfclient .I ospfd .I lsatype .I opaquetype .I opaqueid .I ifaddr .I areaid .SH DESCRIPTION .B ospfclient is a an example ospf-api client to test the ospfd daemon. .SH OPTIONS .TP .I ospfd A router where the API\-enabled OSPF daemon is running. .TP .I lsatype The value has to be either "9", "10", or "11", depending on the flooding scope. .TP .I opaquetype The value has to be in the range of 0\-255 (for example, experimental applications use .I opaquetype larger than 128). .TP .I opaqueid Arbitrary application instance (24 bits). .TP .I ifaddr Interface IP address for type 9, otherwise it will be ignored. .TP .I areaid Area in the IP address format for type 10, otherwise it will be ignored. .SH "SEE ALSO" .BR ospfd (8). .SH AUTHORS See the project homepage at . quagga-1.2.4/doc/ospfd.8000066400000000000000000000052441325323223500147410ustar00rootroot00000000000000.TH OSPFD 8 "25 November 2004" "Quagga OSPFv2 daemon" "Version 0.97.3" .SH NAME ospfd \- an OSPFv2 routing engine for use with Quagga routing software. .SH SYNOPSIS .B ospfd [ .B \-dhlv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B ospfd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B ospfd command: .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\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\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 identifier 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\-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\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the ospfd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-a\fR, \fB\-\-apiserver \fR Enable OSPF apiserver. Default is disabled. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .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 to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\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" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B ospfd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-1.2.4/doc/ospfd.texi000066400000000000000000001116021325323223500155370ustar00rootroot00000000000000 @cindex OSPFv2 @node OSPFv2 @chapter OSPFv2 @acronym{OSPF,Open Shortest Path First} version 2 is a routing protocol which is described in @cite{RFC2328, OSPF Version 2}. OSPF is an @acronym{IGP,Interior Gateway Protocol}. Compared with @acronym{RIP}, @acronym{OSPF} can provide scalable network support and faster convergence times. OSPF is widely used in large networks such as @acronym{ISP,Internet Service Provider} backbone and enterprise networks. @menu * OSPF Fundamentals:: * Configuring ospfd:: * OSPF router:: * OSPF area:: * OSPF interface:: * Redistribute routes to OSPF:: * Showing OSPF information:: * Opaque LSA:: * OSPF Traffic Engineering:: * Router Information:: * Debugging OSPF:: * OSPF Configuration Examples:: @end menu @include ospf_fundamentals.texi @node Configuring ospfd @section Configuring ospfd There are no @command{ospfd} specific options. Common options can be specified (@pxref{Common Invocation Options}) to @command{ospfd}. @command{ospfd} needs to acquire interface information from @command{zebra} in order to function. Therefore @command{zebra} must be running before invoking @command{ospfd}. Also, if @command{zebra} is restarted then @command{ospfd} must be too. Like other daemons, @command{ospfd} configuration is done in @acronym{OSPF} specific configuration file @file{ospfd.conf}. @node OSPF router @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} {} @anchor{ospf router-id}This sets the router-ID of the OSPF process. The router-ID may be an IP address of the router, but need not be - it can be any arbitrary 32bit number. However it MUST be unique within the entire OSPF domain to the OSPF speaker - bad things will happen if multiple OSPF speakers are configured with the same router-ID! If one is not specified then @command{ospfd} will obtain a router-ID automatically from @command{zebra}. @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. The "Cisco" and "IBM" types are equivalent. The OSPF standard for ABR behaviour does not allow an ABR to consider routes through non-backbone areas when its links to the backbone are down, even when there are other ABRs in attached non-backbone areas which still can reach the backbone - this restriction exists primarily to ensure routing-loops are avoided. With the "Cisco" or "IBM" ABR type, the default in this release of Quagga, this restriction is lifted, allowing an ABR to consider summaries learnt from other ABRs through non-backbone areas, and hence route via non-backbone areas as a last resort when, and only when, backbone links are down. Note that areas with fully-adjacent virtual-links are considered to be "transit capable" and can always be used to route backbone traffic, and hence are unaffected by this setting (@pxref{OSPF virtual-link}). More information regarding the behaviour controlled by this command can be found in @cite{RFC 3509, Alternative Implementations of OSPF Area Border Routers}, and @cite{draft-ietf-ospf-shortcut-abr-02.txt}. Quote: "Though the definition of the @acronym{ABR,Area Border Router} 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} {} @cite{RFC2328}, the sucessor to @cite{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 specifically it demands that inter-area paths and intra-area backbone path are now of equal preference but still both preferred to external paths. This command should NOT be set normally. @end deffn @deffn {OSPF Command} {log-adjacency-changes [detail]} {} @deffnx {OSPF Command} {no log-adjacency-changes [detail]} {} Configures ospfd to log changes in adjacency. With the optional detail argument, all changes in adjacency status are shown. Without detail, only changes to full or regressions are shown. @end deffn @deffn {OSPF Command} {passive-interface @var{interface}} {} @deffnx {OSPF Command} {no passive-interface @var{interface}} {} @anchor{OSPF passive-interface} Do not speak OSPF interface on the given interface, but do advertise the interface as a stub link in the router-@acronym{LSA,Link State Advertisement} for this router. This allows one to advertise addresses on such connected interfaces without having to originate AS-External/Type-5 LSAs (which have global flooding scope) - as would occur if connected addresses were redistributed into OSPF (@pxref{Redistribute routes to OSPF})@. This is the only way to advertise non-OSPF links into stub areas. @end deffn @deffn {OSPF Command} {timers throttle spf @var{delay} @var{initial-holdtime} @var{max-holdtime}} {} @deffnx {OSPF Command} {no timers throttle spf} {} This command sets the initial @var{delay}, the @var{initial-holdtime} and the @var{maximum-holdtime} between when SPF is calculated and the event which triggered the calculation. The times are specified in milliseconds and must be in the range of 0 to 600000 milliseconds. The @var{delay} specifies the minimum amount of time to delay SPF calculation (hence it affects how long SPF calculation is delayed after an event which occurs outside of the holdtime of any previous SPF calculation, and also serves as a minimum holdtime). Consecutive SPF calculations will always be seperated by at least 'hold-time' milliseconds. The hold-time is adaptive and initially is set to the @var{initial-holdtime} configured with the above command. Events which occur within the holdtime of the previous SPF calculation will cause the holdtime to be increased by @var{initial-holdtime}, bounded by the @var{maximum-holdtime} configured with this command. If the adaptive hold-time elapses without any SPF-triggering event occuring then the current holdtime is reset to the @var{initial-holdtime}. The current holdtime can be viewed with @ref{show ip ospf}, where it is expressed as a multiplier of the @var{initial-holdtime}. @example @group router ospf timers throttle spf 200 400 10000 @end group @end example In this example, the @var{delay} is set to 200ms, the @var{initial holdtime} is set to 400ms and the @var{maximum holdtime} to 10s. Hence there will always be at least 200ms between an event which requires SPF calculation and the actual SPF calculation. Further consecutive SPF calculations will always be seperated by between 400ms to 10s, the hold-time increasing by 400ms each time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. This command supercedes the @command{timers spf} command in previous Quagga releases. @end deffn @deffn {OSPF Command} {max-metric router-lsa [on-startup|on-shutdown] <5-86400>} {} @deffnx {OSPF Command} {max-metric router-lsa administrative} {} @deffnx {OSPF Command} {no max-metric router-lsa [on-startup|on-shutdown|administrative]} {} This enables @cite{RFC3137, OSPF Stub Router Advertisement} support, where the OSPF process describes its transit links in its router-LSA as having infinite distance so that other routers will avoid calculating transit paths through the router while still being able to reach networks through the router. This support may be enabled administratively (and indefinitely) or conditionally. Conditional enabling of max-metric router-lsas can be for a period of seconds after startup and/or for a period of seconds prior to shutdown. Enabling this for a period after startup allows OSPF to converge fully first without affecting any existing routes used by other routers, while still allowing any connected stub links and/or redistributed routes to be reachable. Enabling this for a period of time in advance of shutdown allows the router to gracefully excuse itself from the OSPF domain. Enabling this feature administratively allows for administrative intervention for whatever reason, for an indefinite period of time. Note that if the configuration is written to file, this administrative form of the stub-router command will also be written to file. If @command{ospfd} is restarted later, the command will then take effect until manually deconfigured. Configured state of this feature as well as current status, such as the number of second remaining till on-startup or on-shutdown ends, can be viewed with the @ref{show ip ospf} command. @end deffn @deffn {OSPF Command} {auto-cost reference-bandwidth <1-4294967>} {} @deffnx {OSPF Command} {no auto-cost reference-bandwidth} {} @anchor{OSPF auto-cost reference-bandwidth}This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain. @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>}} {} @anchor{OSPF network command} This command specifies the OSPF enabled interface(s). If the interface has an address from range 192.168.1.0/24 then the command below enables ospf on this interface so router can provide network information to the other ospf routers via this interface. @example @group router ospf network 192.168.1.0/24 area 0.0.0.0 @end group @end example Prefix length in interface must be equal or bigger (ie. smaller network) than prefix length in network statement. For example statement above doesn't enable ospf on interface with address 192.168.1.1/23, but it does on interface with address 192.168.1.129/25. Note that the behavior when there is a peer address defined on an interface changed after release 0.99.7. Currently, if a peer prefix has been configured, then we test whether the prefix in the network command contains the destination prefix. Otherwise, we test whether the network command prefix contains the local address prefix of the interface. In some cases it may be more convenient to enable OSPF on a per interface/subnet basis (@pxref{OSPF ip ospf area command}). @end deffn @node OSPF area @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}} {} Summarize intra area paths from specified area into one Type-3 summary-LSA announced to other areas. This command can be used only in ABR and ONLY router-LSAs (Type-1) and network-LSAs (Type-2) (ie. LSAs with scope area) can be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS. Summarizing Type-7 AS-external-LSAs isn't supported yet by Quagga. @example @group router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 range 10.0.0.0/8 @end group @end example With configuration above one Type-3 Summary-LSA with routing info 10.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (ie. described with router or network LSA) from this range. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX not-advertise} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX not-advertise} {} Instead of summarizing intra area paths filter them - ie. intra area paths from this range are not advertised into other areas. This command makes sense in ABR only. @end deffn @deffn {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} {} Substitute summarized prefix with another prefix. @example @group router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 range 10.0.0.0/8 substitute 11.0.0.0/8 @end group @end example One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (ie. described with router-LSA or network-LSA) from range 10.0.0.0/8. This command makes sense in ABR only. @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}} {} @anchor{OSPF virtual-link} @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} {} Configure the area as Shortcut capable. See @cite{RFC3509}. This requires that the 'abr-type' be set to '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} {} Configure the area to be a stub area. That is, an area where no router originates routes external to OSPF and hence an area where all external routes are via the ABR(s). Hence, ABRs for such an area do not need to pass AS-External LSAs (type-5s) or ASBR-Summary LSAs (type-4) into the area. They need only pass Network-Summary (type-3) LSAs into such an area, along with a default-route summary. @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} {} Prevents an @command{ospfd} ABR from injecting inter-area summaries into the specified stub area. @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>} {} Set the cost of default-summary LSAs announced to stubby areas. @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} {} Filter Type-3 summary-LSAs announced to other areas originated from intra- area paths from specified area. @example @group router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 export-list foo ! access-list foo permit 10.10.0.0/16 access-list foo deny any @end group @end example With example above any intra-area paths from area 0.0.0.10 and from range 10.10.0.0/16 (for example 10.10.1.0/24 and 10.10.2.128/30) are announced into other areas as Type-3 summary-LSA's, but any others (for example 10.11.0.0/16 or 10.128.30.16/30) aren't. This command is only relevant if the router is an ABR for the specified area. @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} {} Same as export-list, but it applies to paths announced into specified area as Type-3 summary-LSAs. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} filter-list prefix NAME in} {} @deffnx {OSPF Command} {area @var{a.b.c.d} filter-list prefix NAME out} {} @deffnx {OSPF Command} {area <0-4294967295> filter-list prefix NAME in} {} @deffnx {OSPF Command} {area <0-4294967295> filter-list prefix NAME out} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} filter-list prefix NAME in} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} filter-list prefix NAME out} {} @deffnx {OSPF Command} {no area <0-4294967295> filter-list prefix NAME in} {} @deffnx {OSPF Command} {no area <0-4294967295> filter-list prefix NAME out} {} Filtering Type-3 summary-LSAs to/from area using prefix lists. This command makes sense in ABR only. @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} {} Specify that simple password authentication should be used for the given area. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} authentication message-digest} {} @deffnx {OSPF Command} {area <0-4294967295> authentication message-digest} {} @anchor{area authentication message-digest}Specify that OSPF packets must be authenticated with MD5 HMACs within the given area. Keying material must also be configured on a per-interface basis (@pxref{ip ospf message-digest-key}). MD5 authentication may also be configured on a per-interface basis (@pxref{ip ospf authentication message-digest}). Such per-interface settings will override any per-area authentication setting. @end deffn @node OSPF interface @section OSPF interface @deffn {Interface Command} {ip ospf area @var{AREA} [@var{ADDR}]} {} @deffnx {Interface Command} {no ip ospf area [@var{ADDR}]} {} @anchor{OSPF ip ospf area command} Enable OSPF on the interface, optionally restricted to just the IP address given by @var{ADDR}, putting it in the @var{AREA} area. Per interface area settings take precedence to network commands (@pxref{OSPF network command}). If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF via this command may result in a slight performance improvement. @end deffn @deffn {Interface Command} {ip ospf authentication-key @var{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. Simple text password authentication is insecure and deprecated in favour of MD5 HMAC authentication (@pxref{ip ospf authentication message-digest}). @end deffn @deffn {Interface Command} {ip ospf authentication message-digest} {} @anchor{ip ospf authentication message-digest}Specify that MD5 HMAC authentication must be used on this interface. MD5 keying material must also be configured (@pxref{ip ospf message-digest-key}). Overrides any authentication enabled on a per-area basis (@pxref{area authentication message-digest}). Note that OSPF MD5 authentication requires that time never go backwards (correct time is NOT important, only that it never goes backwards), even across resets, if ospfd is to be able to promptly reestabish adjacencies with its neighbours after restarts/reboots. The host should have system time be set at boot from an external or non-volatile source (eg battery backed clock, NTP, etc.) or else the system clock should be periodically saved to non-volative storage and restored at boot if MD5 authentication is to be expected to work reliably. @end deffn @deffn {Interface Command} {ip ospf message-digest-key KEYID md5 KEY} {} @deffnx {Interface Command} {no ip ospf message-digest-key} {} @anchor{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. This ID is part of the protocol and must be consistent across routers on a link. KEY is the actual message digest key, of up to 16 chars (larger strings will be truncated), and is associated with the given KEYID. @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} {ip ospf dead-interval minimal hello-multiplier <2-20>} {} @deffnx {Interface Command} {no ip ospf dead-interval} {} @anchor{ip ospf dead-interval minimal} 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. If 'minimal' is specified instead, then the dead-interval is set to 1 second and one must specify a hello-multiplier. The hello-multiplier specifies how many Hellos to send per second, from 2 (every 500ms) to 20 (every 50ms). Thus one can have 1s convergence time for OSPF. If this form is specified, then the hello-interval advertised in Hello packets is set to 0 and the hello-interval on received Hello packets is not checked, thus the hello-multiplier need NOT be the same across multiple routers on a common link. @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. This command has no effect if @ref{ip ospf dead-interval minimal} is also specified for the interface. @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. The router with the highest priority will be more eligible to become Designated Router. Setting the value to 0, makes the router ineligible to become 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 @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)} {} @anchor{OSPF redistribute}Redistribute routes of the specified protocol or kind into OSPF, with the metric type and metric set if specified, filtering the routes using the given route-map if specified. Redistributed routes may also be filtered with distribute-lists, see @ref{ospf distribute-list}. Redistributed routes are distributed as into OSPF as Type-5 External LSAs into links to areas that accept external routes, Type-7 External LSAs for NSSA areas and are not redistributed at all into Stub areas, where external routes are not permitted. Note that for connected routes, one may instead use @dfn{passive-interface}, see @ref{OSPF passive-interface}. @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} {} Originate an AS-External (type-5) LSA describing a default route into all external-routing capable areas, of the specified metric and metric type. If the 'always' keyword is given then the default is always advertised, even when there is no default present in the routing table. @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} {} @anchor{ospf distribute-list}Apply the access-list filter, NAME, to redistributed routes of the given type before allowing the routes to redistributed into OSPF (@pxref{OSPF redistribute}). @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 @node Showing OSPF information @section Showing OSPF information @deffn {Command} {show ip ospf} {} @anchor{show ip ospf}Show information on a variety of general OSPF and area state and configuration information. @end deffn @deffn {Command} {show ip ospf interface [INTERFACE]} {} Show state and configuration of OSPF the specified interface, or all interfaces if no interface is given. @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} {} @deffnx {Command} {show ip ospf database asbr-summary} {} @deffnx {Command} {show ip ospf database external} {} @deffnx {Command} {show ip ospf database network} {} @deffnx {Command} {show ip ospf database asbr-router} {} @deffnx {Command} {show ip ospf database summary} {} @deffnx {Command} {show ip ospf database @dots{} @var{link-state-id}} {} @deffnx {Command} {show ip ospf database @dots{} @var{link-state-id} adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database @dots{} adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database @dots{} @var{link-state-id} self-originate} {} @deffnx {Command} {show ip ospf database @dots{} 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 route} {} Show the OSPF routing table, as determined by the most recent SPF calculation. @end deffn @node Opaque LSA @section Opaque LSA @deffn {OSPF Command} {ospf opaque-lsa} {} @deffnx {OSPF Command} {capability opaque} {} @deffnx {OSPF Command} {no ospf opaque-lsa} {} @deffnx {OSPF Command} {no capability opaque} {} @command{ospfd} support Opaque LSA (RFC2370) as fondment for MPLS Traffic Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the configuration file. Alternate command could be "mpls-te on" (@ref{OSPF Traffic Engineering}). @end deffn @deffn {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external)} {} @deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id}} {} @deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} self-originate} {} @deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate} {} Show Opaque LSA from the database. @end deffn @node OSPF Traffic Engineering @section Traffic Engineering @deffn {OSPF Command} {mpls-te on} {} @deffnx {OSPF Command} {no mpls-te} {} Enable Traffic Engineering LSA flooding. @end deffn @deffn {OSPF Command} {mpls-te router-address } {} @deffnx {OSPF Command} {no mpls-te} {} Configure stable IP address for MPLS-TE. This IP address is then advertise in Opaque LSA Type-10 TLV=1 (TE) option 1 (Router-Address). @end deffn @deffn {OSPF Command} {mpls-te inter-as area |as} {} @deffnx {OSPF Command} {no mpls-te inter-as} {} Enable RFC5392 suuport - Inter-AS TE v2 - to flood Traffic Engineering parameters of Inter-AS link. 2 modes are supported: AREA and AS; LSA are flood in AREA with Opaque Type-10, respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6. @end deffn @deffn {Command} {show ip ospf mpls-te interface} {} @deffnx {Command} {show ip ospf mpls-te interface @var{interface}} {} Show MPLS Traffic Engineering parameters for all or specified interface. @end deffn @deffn {Command} {show ip ospf mpls-te router} {} Show Traffic Engineering router parameters. @end deffn @node Router Information @section Router Information @deffn {OSPF Command} {router-info [as | area ]} {} @deffnx {OSPF Command} {no router-info} {} Enable Router Information (RFC4970) LSA advertisement with AS scope (default) or Area scope flooding when area is specified. @end deffn @deffn {OSPF Command} {pce address } {} @deffnx {OSPF Command} {no pce address} {} @deffnx {OSPF Command} {pce domain as <0-65535>} {} @deffnx {OSPF Command} {no pce domain as <0-65535>} {} @deffnx {OSPF Command} {pce neighbor as <0-65535>} {} @deffnx {OSPF Command} {no pce neighbor as <0-65535>} {} @deffnx {OSPF Command} {pce flag BITPATTERN} {} @deffnx {OSPF Command} {no pce flag} {} @deffnx {OSPF Command} {pce scope BITPATTERN} {} @deffnx {OSPF Command} {no pce scope} {} The commands are conform to RFC 5088 and allow OSPF router announce Path Compuatation Elemenent (PCE) capabilities through the Router Information (RI) LSA. Router Information must be enable prior to this. The command set/unset respectively the PCE IP adress, Autonomous System (AS) numbers of controlled domains, neighbor ASs, flag and scope. For flag and scope, please refer to RFC5088 for the BITPATTERN recognition. Multiple 'pce neighbor' command could be specified in order to specify all PCE neighbours. @end deffn @deffn {Command} {show ip ospf router-info} {} Show Router Capabilities flag. @end deffn @deffn {Command} {show ip ospf router-info pce} {} Show Router Capabilities PCE parameters. @end deffn @node Debugging OSPF @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]} {} Dump Packet for debugging @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)} {} Show debug information of Interface State Machine @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)} {} Show debug information of Network State Machine @end deffn @deffn {Command} {debug ospf event} {} @deffnx {Command} {no debug ospf event} {} Show debug information of OSPF event @end deffn @deffn {Command} {debug ospf nssa} {} @deffnx {Command} {no debug ospf nssa} {} Show debug information about Not So Stub Area @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)} {} Show debug detail of Link State messages @end deffn @deffn {Command} {debug ospf te} {} @deffnx {Command} {no debug ospf te} {} Show debug information about Traffic Engineering LSA @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)} {} Show debug information of ZEBRA API @end deffn @deffn {Command} {show debugging ospf} {} @end deffn @node OSPF Configuration Examples @section OSPF Configuration Examples A simple example, with MD5 authentication enabled: @example @group ! interface bge0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 ABCDEFGHIJK ! router ospf network 192.168.0.0/16 area 0.0.0.1 area 0.0.0.1 authentication message-digest @end group @end example An @acronym{ABR} router, with MD5 authentication and performing summarisation of networks between the areas: @example @group ! password ABCDEF log file /var/log/quagga/ospfd.log service advanced-vty ! interface eth0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 ABCDEFGHIJK ! interface ppp0 ! interface br0 ip ospf authentication message-digest ip ospf message-digest-key 2 md5 XYZ12345 ! router ospf ospf router-id 192.168.0.1 redistribute connected passive interface ppp0 network 192.168.0.0/24 area 0.0.0.0 network 10.0.0.0/16 area 0.0.0.0 network 192.168.1.0/24 area 0.0.0.1 area 0.0.0.0 authentication message-digest area 0.0.0.0 range 10.0.0.0/16 area 0.0.0.0 range 192.168.0.0/24 area 0.0.0.1 authentication message-digest area 0.0.0.1 range 10.2.0.0/16 ! @end group @end example A Traffic Engineering configuration, with Inter-ASv2 support. - First, the 'zebra.conf' part: @example @group hostname HOSTNAME password PASSWORD log file /var/log/zebra.log ! interface eth0 ip address 198.168.1.1/24 mpls-te on mpls-te link metric 10 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab ! interface eth1 ip address 192.168.2.1/24 mpls-te on mpls-te link metric 10 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab mpls-te neighbor 192.168.2.2 as 65000 @end group @end example - Then the 'ospfd.conf' itself: @example @group hostname HOSTNAME password PASSWORD log file /var/log/ospfd.log ! ! interface eth0 ip ospf hello-interval 60 ip ospf dead-interval 240 ! interface eth1 ip ospf hello-interval 60 ip ospf dead-interval 240 ! ! router ospf ospf router-id 192.168.1.1 network 192.168.0.0/16 area 1 ospf opaque-lsa mpls-te mpls-te router-address 192.168.1.1 mpls-te inter-as area 1 ! line vty @end group @end example A router information example with PCE advsertisement: @example @group ! router ospf ospf router-id 192.168.1.1 network 192.168.0.0/16 area 1 capability opaque mpls-te mpls-te router-address 192.168.1.1 router-info area 0.0.0.1 pce address 192.168.1.1 pce flag 0x80 pce domain as 65400 pce neighbor as 65500 pce neighbor as 65200 pce scope 0x80 ! @end group @end example quagga-1.2.4/doc/overview.texi000066400000000000000000000277051325323223500163040ustar00rootroot00000000000000@node Overview @chapter Overview @cindex Overview @uref{http://www.quagga.net,,Quagga} is a routing software package that provides TCP/IP based routing services with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, IS-IS, BGP-4, and BGP-4+ (@pxref{Supported RFCs}). Quagga also supports special BGP Route Reflector and Route Server behavior. In addition to traditional IPv4 routing protocols, Quagga also supports IPv6 routing protocols. With SNMP daemon which supports SMUX and AgentX protocol, Quagga provides routing protocol MIBs (@pxref{SNMP Support}). Quagga uses an advanced software architecture to provide you with a high quality, multi server routing engine. Quagga has an interactive user interface for each routing protocol and supports common client commands. Due to this design, you can add new protocol daemons to Quagga easily. You can use Quagga library as your program's client user interface. Quagga is distributed under the @sc{gnu} General Public License. @menu * About Quagga:: Basic information about Quagga * System Architecture:: The Quagga system architecture * Supported Platforms:: Supported platforms and future plans * Supported RFCs:: Supported RFCs * How to get Quagga:: * Mailing List:: Mailing list information * Bug Reports:: Mail address for bug data @end menu @node About Quagga @comment node-name, next, previous, up @section About Quagga @cindex About Quagga 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 Quagga installed acts as a dedicated router. With Quagga, your machine exchanges routing information with other routers using routing protocols. Quagga 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 Quagga terminal interface. Adding to routing protocol support, Quagga 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 Quagga 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 Quagga's dynamic routing protocol support for protocols such as RIP, OSPF, IS-IS or BGP. 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. Quagga has a different system administration method. There are two user modes in Quagga. 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, Quagga supports common unicast routing protocols, that is BGP, OSPF, RIP and IS-IS. Upcoming for MPLS support, an implementation of LDP is currently being prepared for merging. Implementations of BFD and PIM-SSM (IPv4) also exist, but are not actively being worked on. The ultimate goal of the Quagga project is making a productive, quality, free TCP/IP routing software package. @node System Architecture @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. Quagga 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 +----+ +----+ +-----+ +-----+ |bgpd| |ripd| |ospfd| |zebra| +----+ +----+ +-----+ +-----+ | +---------------------------|--+ | v | | UNIX Kernel routing table | | | +------------------------------+ Quagga System 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, Quagga 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. Quagga 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. @node Supported Platforms @comment node-name, next, previous, up @section Supported Platforms @cindex Supported platforms @cindex Quagga on other systems @cindex Compatibility with other systems @cindex Operating systems that support Quagga Currently Quagga supports @sc{gnu}/Linux and BSD. Porting Quagga to other platforms is not too difficult as platform dependent code should most be limited to the @command{zebra} daemon. Protocol daemons are mostly platform independent. Please let us know when you find out Quagga runs on a platform which is not listed below. The list of officially supported platforms are listed below. Note that Quagga may run correctly on other platforms, and may run with partial functionality on further platforms. @sp 1 @itemize @bullet @item @sc{gnu}/Linux @item FreeBSD @item NetBSD @item OpenBSD @end itemize Versions of these platforms that are older than around 2 years from the point of their original release (in case of @sc{gnu}/Linux, this is since the kernel's release on kernel.org) may need some work. Similarly, the following platforms may work with some effort: @sp 1 @itemize @bullet @item Solaris @item Mac OSX @end itemize Also note that, in particular regarding proprietary platforms, compiler and C library choice will affect Quagga. Only recent versions of the following C compilers are well-tested: @sp 1 @itemize @bullet @item @sc{gnu}'s GCC @item LLVM's clang @item Intel's ICC @end itemize @node Supported RFCs @comment node-name, next, previous, up @section Supported RFCs 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{RFC2370} @cite{The OSPF Opaque LSA Option R. Coltun. July 1998.} @item @asis{RFC3101} @cite{The OSPF Not-So-Stubby Area (NSSA) Option P. Murphy. January 2003.} @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.} @item @asis{RFC3137} @cite{OSPF Stub Router Advertisement, A. Retana, L. Nguyen, R. White, A. Zinin, D. McPherson. June 2001} @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.} @item @asis{RFC2741} @cite{Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.} @end table @node How to get Quagga @comment node-name, next, previous, up @section How to get Quagga The official Quagga web-site is located at: @uref{http://www.quagga.net/} and contains further information, as well as links to additional resources. @uref{http://www.quagga.net/,Quagga} is a fork of GNU Zebra, whose web-site is located at: @uref{http://www.zebra.org/}. @node Mailing List @comment node-name, next, previous, up @section Mailing List @cindex How to get in touch with Quagga @cindex Mailing Quagga @cindex Contact information @cindex Mailing lists There is a mailing list for discussions about Quagga. If you have any comments or suggestions to Quagga, please subscribe to: @uref{http://lists.quagga.net/mailman/listinfo/quagga-users}. The @uref{http://www.quagga.net/,,Quagga} site has further information on the available mailing lists, see: @uref{http://www.quagga.net/lists.php} @node Bug Reports @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: @uref{http://bugzilla.quagga.net} 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 Quagga. Quagga is still in the development stage, but please don't hesitate to send a bug report to @uref{http://bugzilla.quagga.net}. quagga-1.2.4/doc/pimd.8000066400000000000000000000054751325323223500145650ustar00rootroot00000000000000.TH PIM 8 "10 December 2008" "Quagga PIM daemon" "Version 0.99.11" .SH NAME pimd \- a PIM routing for use with Quagga Routing Suite. .SH SYNOPSIS .B pimd [ .B \-dhvZ ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-z .I path ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B pimd is a protocol-independent multicast component that works with the .B Quagga Routing Suite. .SH OPTIONS Options available for the .B pimd command: .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/pimd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When pimd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart pimd. The likely default is \fB\fI/var/run/pimd.pid\fR. .TP \fB\-z\fR, \fB\-\-socket \fR\fIpath\fR Specify the socket path for contacting the zebra daemon. The likely default is \fB\fI/var/run/zserv.api\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the pimd VTY will listen on. This defaults to 2611, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the pimd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .TP \fB\-Z\fR, \fB\-\-debug_zclient\fR Enable logging information for zclient debugging. .SH FILES .TP .BI /usr/local/sbin/pimd The default location of the .B pimd binary. .TP .BI /usr/local/etc/pimd.conf The default location of the .B pimd config file. .TP .BI /var/run/pimd.pid The default location of the .B pimd pid file. .TP .BI /var/run/zserv.api The default location of the .B zebra unix socket file. .TP .BI $(PWD)/pimd.log If the .B pimd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBpimd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. .SH DIAGNOSTICS The pimd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. .SH "SEE ALSO" .BR zebra (8), .BR vtysh (1) .SH BUGS \fBpimd\fR is in early development at the moment and is not ready for production use. .B pimd eats bugs for breakfast. If you have food for the maintainers try .BI https://github.com/udhos/qpimd .SH AUTHORS See .BI https://github.com/udhos/qpimd for an accurate list of authors. quagga-1.2.4/doc/protocol.texi000066400000000000000000000102501325323223500162620ustar00rootroot00000000000000@node Zebra Protocol @appendix Zebra Protocol @appendixsection Overview of the Zebra Protocol Zebra Protocol is used by protocol daemons to communicate with the zebra daemon. Each protocol daemon may request and send information to and from the zebra daemon such as interface states, routing state, nexthop-validation, and so on. Protocol daemons may also install routes with zebra. The zebra daemon manages which route is installed into the forwarding table with the kernel. Zebra Protocol is a streaming protocol, with a common header. The protocol is versioned to allow for incompatible changes. Version 0 is implicitely versioned. Version 1 onwards has an explicit version field. Version 0 can be distinguished from all other versions by examining the 3rd byte of the header, which contains a marker value of 255 for all versions bar version 0. The marker byte corresponds to the command field in version 0, and the marker value is a reserved command in version 0. Version 0 is used by all versions of GNU Zebra as of this writing, and versions of Quagga up to and including Quagga 0.98. The version 1 header was introduced with Quagga 0.99.3. The version 3 header was introduced with Quagga 1.0.20160309. @appendixsection Zebra Protocol Definition @appendixsubsec Zebra Protocol Header (version 0) @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 @appendixsubsec Zebra Protocol Common Header (version 1 and 2) @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) | Marker (1) | Version (1) | +-------------------------------+---------------+-------------+ | Command (2) | +-------------------------------+ @end group @end example @appendixsubsec Zebra Protocol Common Header (version 3) @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) | Marker (1) | Version (1) | +-------------------------------+---------------+-------------+ | VRF ID (2) | Command (2) | +-------------------------------+-----------------------------+ @end group @end example @appendixsubsec Zebra Protocol Header Field Definitions @table @samp @item Length Total packet length including this header. The minimum length is 3 bytes for version 0 messages, 6 bytes for version 1 and 2 messages, and 8 bytes for version 3. @item Marker Static marker with a value of 255 always. This is to allow version 0 Zserv headers (which do not include version explicitely) to be distinguished from versioned headers. Not present in version 0 messages. @item Version Version number of the Zserv message. Clients should not continue processing messages past the version field for versions they do not recognise. Not present in version 0 messages. @item VRF ID Virtual Routing/Forwarding context ID, to which the message applies. Only present from version 3 onwards. @item Command The Zebra Protocol command. @end table @appendixsubsec Zebra Protocol Commands @multitable {ZEBRA_REDISTRIBUTE_DEFAULT_DELETE_WHATEVER} {99999} @headitem Command @tab Value @item ZEBRA_INTERFACE_ADD @tab 1 @item ZEBRA_INTERFACE_DELETE @tab 2 @item ZEBRA_INTERFACE_ADDRESS_ADD @tab 3 @item ZEBRA_INTERFACE_ADDRESS_DELETE @tab 4 @item ZEBRA_INTERFACE_UP @tab 5 @item ZEBRA_INTERFACE_DOWN @tab 6 @item ZEBRA_IPV4_ROUTE_ADD @tab 7 @item ZEBRA_IPV4_ROUTE_DELETE @tab 8 @item ZEBRA_IPV6_ROUTE_ADD @tab 9 @item ZEBRA_IPV6_ROUTE_DELETE @tab 10 @item ZEBRA_REDISTRIBUTE_ADD @tab 11 @item ZEBRA_REDISTRIBUTE_DELETE @tab 12 @item ZEBRA_REDISTRIBUTE_DEFAULT_ADD @tab 13 @item ZEBRA_REDISTRIBUTE_DEFAULT_DELETE @tab 14 @item ZEBRA_IPV4_NEXTHOP_LOOKUP @tab 15 @item ZEBRA_IPV6_NEXTHOP_LOOKUP @tab 16 @end multitable quagga-1.2.4/doc/quagga.info000066400000000000000000000216331325323223500156570ustar00rootroot00000000000000This is quagga.info, produced by makeinfo version 6.3 from quagga.texi. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. 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. INFO-DIR-SECTION Routing Software: START-INFO-DIR-ENTRY * Quagga: (quagga). The Quagga Software Routing Suite END-INFO-DIR-ENTRY This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. This is Edition 1.2.4, last updated 19 February 2018 of 'The Quagga Manual', for Quagga Version 1.2.4. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. 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: quagga.info-1: 1938 quagga.info-2: 302477  Tag Table: (Indirect) Node: Top1938 Node: Overview3320 Node: About Quagga4754 Node: System Architecture7040 Node: Supported Platforms9729 Node: Supported RFCs10975 Node: How to get Quagga13156 Node: Mailing List13580 Node: Bug Reports14026 Node: Installation14902 Node: Configure the Software15336 Node: The Configure script and its options15584 Node: Least-Privilege support19471 Node: Linux notes21210 Ref: Linux notes-Footnote-123068 Node: Build the Software23134 Node: Install the Software23684 Node: Basic commands25231 Node: Config Commands26005 Node: Basic Config Commands26863 Node: Sample Config File33229 Node: Terminal Mode Commands34002 Node: Common Invocation Options35133 Node: Virtual Terminal Interfaces36549 Node: VTY Overview37060 Node: VTY Modes38311 Node: VTY View Mode38761 Node: VTY Enable Mode39011 Node: VTY Other Modes39289 Node: VTY CLI Commands39465 Node: CLI Movement Commands39925 Node: CLI Editing Commands40448 Node: CLI Advanced Commands41209 Node: Zebra42089 Node: Invoking zebra42804 Node: Interface Commands43334 Node: Standard Commands43567 Node: Link Parameters Commands45128 Node: Static Route Commands47745 Node: Multicast RIB Commands51001 Node: zebra Route Filtering54133 Node: zebra FIB push interface55277 Node: zebra Terminal Mode Commands58792 Node: RIP60197 Node: Starting and Stopping ripd61264 Node: RIP netmask62692 Node: RIP Configuration63789 Node: RIP Version Control66787 Node: How to Announce RIP route68974 Node: Filtering RIP Routes71543 Node: RIP Metric Manipulation73010 Node: RIP distance73923 Node: RIP route-map74738 Node: RIP Authentication77287 Node: RIP Timers79532 Node: Show RIP Information80822 Node: RIP Debug Commands82198 Node: RIPng83194 Node: Invoking ripngd83540 Node: ripngd Configuration83789 Node: ripngd Terminal Mode Commands84540 Node: ripngd Filtering Commands84904 Node: OSPFv285413 Node: OSPF Fundamentals86234 Ref: OSPF LSA sequence number93855 Ref: OSPF Link-State LSA Example99178 Ref: OSPF Flooding106823 Ref: OSPF Areas106864 Node: Configuring ospfd106899 Node: OSPF router107474 Ref: ospf router-id108021 Ref: OSPF passive-interface111232 Ref: OSPF auto-cost reference-bandwidth115697 Ref: OSPF network command116358 Node: OSPF area117509 Ref: OSPF virtual-link119856 Ref: area authentication message-digest123568 Node: OSPF interface123991 Ref: OSPF ip ospf area command124235 Ref: ip ospf authentication message-digest125132 Ref: ip ospf message-digest-key126117 Ref: ip ospf dead-interval minimal126936 Node: Redistribute routes to OSPF129354 Ref: OSPF redistribute130410 Ref: ospf distribute-list132321 Node: Showing OSPF information132764 Ref: show ip ospf132971 Node: Opaque LSA134213 Node: OSPF Traffic Engineering135475 Node: Router Information136625 Node: Debugging OSPF138118 Node: OSPF Configuration Examples139790 Node: OSPFv3143406 Node: OSPF6 router143812 Node: OSPF6 area146528 Node: OSPF6 interface146706 Node: Redistribute routes to OSPF6147776 Node: Showing OSPF6 information148092 Node: OSPF6 Configuration Examples148949 Node: ISIS149370 Node: Configuring isisd150046 Node: ISIS router150593 Ref: router isis WORD150917 Ref: metric-style152007 Node: ISIS Timer152377 Node: ISIS region154064 Node: ISIS interface154473 Ref: ip router isis WORD154709 Node: Showing ISIS information157884 Node: ISIS Traffic Engineering159295 Node: Debugging ISIS159976 Node: ISIS Configuration Examples161517 Node: NHRP163663 Node: Routing Design164466 Node: Configuring NHRP166119 Node: Hub Functionality166277 Node: Integration with IKE167626 Node: NHRP Events168306 Node: Configuration Example168459 Node: BGP168603 Node: Starting BGP169693 Node: BGP router170525 Node: BGP distance171825 Node: BGP decision process172346 Ref: bgp bestpath as-path multipath-relax174908 Ref: bgp bestpath compare-routerid175176 Node: BGP route flap dampening176143 Node: BGP MED176861 Ref: bgp deterministic-med188104 Ref: bgp always-compare-med188970 Ref: BGP MED-Footnote-1189590 Node: BGP network190273 Node: BGP route190501 Node: Route Aggregation191055 Node: Redistribute to BGP191626 Node: BGP Peer192155 Node: Defining Peer192384 Node: BGP Peer commands192999 Node: Peer filtering197523 Node: BGP Peer Group198314 Node: BGP Address Family198629 Node: Autonomous System199753 Node: AS Path Regular Expression200656 Node: Display BGP Routes by AS Path201898 Node: AS Path Access List202340 Node: Using AS Path in Route Map202809 Node: Private AS Numbers203281 Node: BGP Communities Attribute203441 Node: BGP Community Lists205916 Node: Numbered BGP Community Lists208568 Node: BGP Community in Route Map210157 Node: Display BGP Routes by Community212103 Node: Using BGP Communities Attribute213274 Node: BGP Extended Communities Attribute216845 Node: BGP Extended Community Lists218626 Node: BGP Extended Communities in Route Map220515 Node: Displaying BGP routes220978 Node: Show IP BGP221246 Node: More Show IP BGP221948 Node: Capability Negotiation223270 Node: Route Reflector226743 Node: Route Server227024 Node: Multiple instance228137 Node: BGP instance and view229984 Node: Routing policy231367 Node: Viewing the view232137 Node: How to set up a 6-Bone connection232424 Node: Dump BGP packets and table233798 Node: BGP Configuration Examples235425 Node: Configuring Quagga as a Route Server244382 Node: Description of the Route Server model245293 Ref: fig:normal-processing246886 Ref: filter-delegation247879 Ref: Route Server tasks249053 Ref: Route-server path filter process249424 Ref: fig:rs-processing251754 Node: Commands for configuring a Route Server254162 Node: Example of Route Server Configuration257207 Node: Configuration of the BGP routers without Route Server258129 Node: Configuration of the BGP routers with Route Server261013 Node: Configuration of the Route Server itself262315 Node: Further considerations about Import and Export route-maps267316 Node: VTY shell270364 Node: VTY shell username271033 Node: VTY shell integrated configuration271666 Node: Filtering273111 Node: IP Access List273492 Node: IP Prefix List273878 Node: ip prefix-list description276921 Node: ip prefix-list sequential number control277448 Node: Showing ip prefix-list277990 Node: Clear counter of ip prefix-list279096 Node: Route Map279535 Node: Route Map Command283006 Node: Route Map Match Command283315 Node: Route Map Set Command284038 Ref: routemap set metric284513 Node: Route Map Call Command284946 Node: Route Map Exit Action Command285277 Node: Route Map Examples285759 Node: IPv6 Support286271 Node: Router Advertisement286852 Node: Kernel Interface293189 Node: SNMP Support295146 Node: Getting and installing an SNMP agent295805 Node: AgentX configuration296616 Node: SMUX configuration298419 Node: MIB and command reference302477 Node: Handling SNMP Traps304002 Node: Zebra Protocol310108 Node: Packet Binary Dump Format314850 Node: Command Index327401 Node: VTY Key Index410567 Node: Index413556  End Tag Table quagga-1.2.4/doc/quagga.info-1000066400000000000000000011127731325323223500160240ustar00rootroot00000000000000This is quagga.info, produced by makeinfo version 6.3 from quagga.texi. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. 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. INFO-DIR-SECTION Routing Software: START-INFO-DIR-ENTRY * Quagga: (quagga). The Quagga Software Routing Suite END-INFO-DIR-ENTRY This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. This is Edition 1.2.4, last updated 19 February 2018 of 'The Quagga Manual', for Quagga Version 1.2.4. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. 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.  File: quagga.info, Node: Top, Next: Overview, Up: (dir) Quagga ****** Quagga is an advanced routing software package that provides a suite of TCP/IP based routing protocols. This is the Manual for Quagga 1.2.4. Quagga is a fork of GNU Zebra. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. 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. * Menu: * Overview:: * Installation:: * Basic commands:: * Zebra:: * RIP:: * RIPng:: * OSPFv2:: * OSPFv3:: * ISIS:: * NHRP:: * BGP:: * Configuring Quagga as a Route Server:: * VTY shell:: * Filtering:: * Route Map:: * IPv6 Support:: * Kernel Interface:: * SNMP Support:: * Zebra Protocol:: * Packet Binary Dump Format:: * Command Index:: * VTY Key Index:: * Index::  File: quagga.info, Node: Overview, Next: Installation, Prev: Top, Up: Top 1 Overview ********** Quagga is a routing software package that provides TCP/IP based routing services with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, IS-IS, BGP-4, and BGP-4+ (*note Supported RFCs::). Quagga also supports special BGP Route Reflector and Route Server behavior. In addition to traditional IPv4 routing protocols, Quagga also supports IPv6 routing protocols. With SNMP daemon which supports SMUX and AgentX protocol, Quagga provides routing protocol MIBs (*note SNMP Support::). Quagga uses an advanced software architecture to provide you with a high quality, multi server routing engine. Quagga has an interactive user interface for each routing protocol and supports common client commands. Due to this design, you can add new protocol daemons to Quagga easily. You can use Quagga library as your program's client user interface. Quagga is distributed under the GNU General Public License. * Menu: * About Quagga:: Basic information about Quagga * System Architecture:: The Quagga system architecture * Supported Platforms:: Supported platforms and future plans * Supported RFCs:: Supported RFCs * How to get Quagga:: * Mailing List:: Mailing list information * Bug Reports:: Mail address for bug data  File: quagga.info, Node: About Quagga, Next: System Architecture, Up: Overview 1.1 About Quagga ================ 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 Quagga installed acts as a dedicated router. With Quagga, your machine exchanges routing information with other routers using routing protocols. Quagga 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 Quagga terminal interface. Adding to routing protocol support, Quagga 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 Quagga 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 Quagga's dynamic routing protocol support for protocols such as RIP, OSPF, IS-IS or BGP. Traditionally, UNIX based router configuration is done by 'ifconfig' and 'route' commands. Status of routing table is displayed by 'netstat' utility. Almost of these commands work only if the user has root privileges. Quagga has a different system administration method. There are two user modes in Quagga. 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, Quagga supports common unicast routing protocols, that is BGP, OSPF, RIP and IS-IS. Upcoming for MPLS support, an implementation of LDP is currently being prepared for merging. Implementations of BFD and PIM-SSM (IPv4) also exist, but are not actively being worked on. The ultimate goal of the Quagga project is making a productive, quality, free TCP/IP routing software package.  File: quagga.info, Node: System Architecture, Next: Supported Platforms, Prev: About Quagga, Up: Overview 1.2 System Architecture ======================= Traditional routing software is made as a one process program which provides all of the routing protocol functionalities. Quagga 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 'ripd' daemon handles the RIP protocol, while 'ospfd' is a daemon which supports OSPF version 2. '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 '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. +----+ +----+ +-----+ +-----+ |bgpd| |ripd| |ospfd| |zebra| +----+ +----+ +-----+ +-----+ | +---------------------------|--+ | v | | UNIX Kernel routing table | | | +------------------------------+ Quagga System Architecture 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 'zebra' configuration file. When you configure BGP network it must be done in 'bgpd' configuration file. This can be a very annoying thing. To resolve the problem, Quagga provides integrated user interface shell called 'vtysh'. 'vtysh' connects to each daemon with UNIX domain socket and then works as a proxy for user input. Quagga 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 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 'select(2)' system call for multiplexing the events.  File: quagga.info, Node: Supported Platforms, Next: Supported RFCs, Prev: System Architecture, Up: Overview 1.3 Supported Platforms ======================= Currently Quagga supports GNU/Linux and BSD. Porting Quagga to other platforms is not too difficult as platform dependent code should most be limited to the 'zebra' daemon. Protocol daemons are mostly platform independent. Please let us know when you find out Quagga runs on a platform which is not listed below. The list of officially supported platforms are listed below. Note that Quagga may run correctly on other platforms, and may run with partial functionality on further platforms. * GNU/Linux * FreeBSD * NetBSD * OpenBSD Versions of these platforms that are older than around 2 years from the point of their original release (in case of GNU/Linux, this is since the kernel's release on kernel.org) may need some work. Similarly, the following platforms may work with some effort: * Solaris * Mac OSX Also note that, in particular regarding proprietary platforms, compiler and C library choice will affect Quagga. Only recent versions of the following C compilers are well-tested: * GNU's GCC * LLVM's clang * Intel's ICC  File: quagga.info, Node: Supported RFCs, Next: How to get Quagga, Prev: Supported Platforms, Up: Overview 1.4 Supported RFCs ================== Below is the list of currently supported RFC's. RFC1058 'Routing Information Protocol. C.L. Hedrick. Jun-01-1988.' RF2082 'RIP-2 MD5 Authentication. F. Baker, R. Atkinson. January 1997.' RFC2453 'RIP Version 2. G. Malkin. November 1998.' RFC2080 'RIPng for IPv6. G. Malkin, R. Minnear. January 1997.' RFC2328 'OSPF Version 2. J. Moy. April 1998.' RFC2370 'The OSPF Opaque LSA Option R. Coltun. July 1998.' RFC3101 'The OSPF Not-So-Stubby Area (NSSA) Option P. Murphy. January 2003.' RFC2740 'OSPF for IPv6. R. Coltun, D. Ferguson, J. Moy. December 1999.' RFC1771 'A Border Gateway Protocol 4 (BGP-4). Y. Rekhter & T. Li. March 1995.' RFC1965 'Autonomous System Confederations for BGP. P. Traina. June 1996.' RFC1997 'BGP Communities Attribute. R. Chandra, P. Traina & T. Li. August 1996.' RFC2545 'Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P. Marques, F. Dupont. March 1999.' RFC2796 'BGP Route Reflection An alternative to full mesh IBGP. T. Bates & R. Chandrasekeran. June 1996.' RFC2858 'Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.' RFC2842 'Capabilities Advertisement with BGP-4. R. Chandra, J. Scudder. May 2000.' RFC3137 'OSPF Stub Router Advertisement, A. Retana, L. Nguyen, R. White, A. Zinin, D. McPherson. June 2001' When SNMP support is enabled, below RFC is also supported. RFC1227 'SNMP MUX protocol and MIB. M.T. Rose. May-01-1991.' RFC1657 '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.' RFC1724 'RIP Version 2 MIB Extension. G. Malkin & F. Baker. November 1994.' RFC1850 'OSPF Version 2 Management Information Base. F. Baker, R. Coltun. November 1995.' RFC2741 'Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.'  File: quagga.info, Node: How to get Quagga, Next: Mailing List, Prev: Supported RFCs, Up: Overview 1.5 How to get Quagga ===================== The official Quagga web-site is located at: and contains further information, as well as links to additional resources. Quagga (http://www.quagga.net/) is a fork of GNU Zebra, whose web-site is located at: .  File: quagga.info, Node: Mailing List, Next: Bug Reports, Prev: How to get Quagga, Up: Overview 1.6 Mailing List ================ There is a mailing list for discussions about Quagga. If you have any comments or suggestions to Quagga, please subscribe to: . The Quagga site has further information on the available mailing lists, see:  File: quagga.info, Node: Bug Reports, Prev: Mailing List, Up: Overview 1.7 Bug Reports =============== If you think you have found a bug, please send a bug report to: When you send a bug report, please be careful about the points below. * Please note what kind of OS you are using. If you use the IPv6 stack please note that as well. * Please show us the results of 'netstat -rn' and 'ifconfig -a'. Information from zebra's VTY command 'show ip route' will also be helpful. * Please send your configuration file with the report. If you specify arguments to the configure script please note that too. Bug reports are very important for us to improve the quality of Quagga. Quagga is still in the development stage, but please don't hesitate to send a bug report to .  File: quagga.info, Node: Installation, Next: Basic commands, Prev: Overview, Up: Top 2 Installation ************** There are three steps for installing the software: configuration, compilation, and installation. * Menu: * Configure the Software:: * Build the Software:: * Install the Software:: The easiest way to get Quagga running is to issue the following commands: % configure % make % make install  File: quagga.info, Node: Configure the Software, Next: Build the Software, Up: Installation 2.1 Configure the Software ========================== * Menu: * The Configure script and its options:: * Least-Privilege support:: * Linux notes::  File: quagga.info, Node: The Configure script and its options, Next: Least-Privilege support, Up: Configure the Software 2.1.1 The Configure script and its options ------------------------------------------ Quagga 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. '--disable-ipv6' Turn off IPv6 related features and daemons. Quagga configure script automatically detects IPv6 stack. But sometimes you might want to disable IPv6 support of Quagga. '--disable-zebra' Do not build zebra daemon. '--disable-ripd' Do not build ripd. '--disable-ripngd' Do not build ripngd. '--disable-ospfd' Do not build ospfd. '--disable-ospf6d' Do not build ospf6d. '--disable-bgpd' Do not build bgpd. '--disable-bgp-announce' Make 'bgpd' which does not make bgp announcements at all. This feature is good for using 'bgpd' as a BGP announcement listener. '--enable-netlink' Force to enable GNU/Linux netlink interface. Quagga 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. '--enable-snmp' Enable SNMP support. By default, SNMP support is disabled. '--disable-opaque-lsa' Disable support for Opaque LSAs (RFC2370) in ospfd. '--disable-ospfapi' Disable support for OSPF-API, an API to interface directly with ospfd. OSPF-API is enabled if -enable-opaque-lsa is set. '--disable-ospfclient' Disable building of the example OSPF-API client. '--disable-ospf-te' Disable support for OSPF Traffic Engineering Extension (RFC3630) this requires support for Opaque LSAs. '--disable-ospf-ri' Disable support for OSPF Router Information (RFC4970 & RFC5088) this requires support for Opaque LSAs and Traffic Engineering. '--enable-isisd' Build isisd. '--enable-isis-topology' Enable IS-IS topology generator. '--enable-isis-te' Enable Traffic Engineering Extension for ISIS (RFC5305) '--enable-multipath=ARG' Enable support for Equal Cost Multipath. ARG is the maximum number of ECMP paths to allow, set to 0 to allow unlimited number of paths. '--disable-rtadv' Disable support IPV6 router advertisement in zebra. '--enable-gcc-rdynamic' Pass the '-rdynamic' option to the linker driver. This is in most cases neccessary for getting usable backtraces. This option defaults to on if the compiler is detected as gcc, but giving an explicit enable/disable is suggested. '--enable-backtrace' Controls backtrace support for the crash handlers. This is autodetected by default. Using the switch will enforce the requested behaviour, failing with an error if support is requested but not available. On BSD systems, this needs libexecinfo, while on glibc support for this is part of libc itself. You may specify any combination of the above options to the configure script. By default, the executables are placed in '/usr/local/sbin' and the configuration files in '/usr/local/etc'. The '/usr/local/' installation prefix and other directories may be changed using the following options to the configuration script. '--prefix=PREFIX' Install architecture-independent files in PREFIX [/usr/local]. '--sysconfdir=DIR' Look for configuration files in DIR [PREFIX/etc]. Note that sample configuration files will be installed here. '--localstatedir=DIR' Configure zebra to use DIR for local state files, such as pid files and unix sockets. % ./configure --disable-ipv6 This command will configure zebra and the routing daemons.  File: quagga.info, Node: Least-Privilege support, Next: Linux notes, Prev: The Configure script and its options, Up: Configure the Software 2.1.2 Least-Privilege support ----------------------------- Additionally, you may configure zebra to drop its elevated privileges shortly after startup and switch to another user. The configure script will automatically try to configure this support. There are three configure options to control the behaviour of Quagga daemons. '--enable-user=USER' Switch to user ARG shortly after startup, and run as user ARG in normal operation. '--enable-group=GROUP' Switch real and effective group to GROUP shortly after startup. '--enable-vty-group=GROUP' Create Unix Vty sockets (for use with vtysh) with group owndership set to GROUP. This allows one to create a seperate group which is restricted to accessing only the Vty sockets, hence allowing one to delegate this group to individual users, or to run vtysh setgid to this group. The default user and group which will be configured is 'quagga' if no user or group is specified. Note that this user or group requires write access to the local state directory (see -localstatedir) and requires at least read access, and write access if you wish to allow daemons to write out their configuration, to the configuration directory (see -sysconfdir). On systems which have the 'libcap' capabilities manipulation library (currently only linux), the quagga system will retain only minimal capabilities required, further it will only raise these capabilities for brief periods. On systems without libcap, quagga will run as the user specified and only raise its uid back to uid 0 for brief periods.  File: quagga.info, Node: Linux notes, Prev: Least-Privilege support, Up: Configure the Software 2.1.3 Linux Notes ----------------- There are several options available only to GNU/Linux systems: (1). If you use GNU/Linux, make sure that the current kernel configuration is what you want. Quagga will run with any kernel configuration but some recommendations do exist. CONFIG_NETLINK Kernel/User netlink socket. This is a brand new feature which enables an advanced interface between the Linux kernel and zebra (*note Kernel Interface::). CONFIG_RTNETLINK Routing messages. This makes it possible to receive netlink routing messages. If you specify this option, 'zebra' can detect routing information updates directly from the kernel (*note Kernel Interface::). CONFIG_IP_MULTICAST IP: multicasting. This option should be specified when you use 'ripd' (*note RIP::) or 'ospfd' (*note OSPFv2::) because these protocols use multicast. IPv6 support has been added in GNU/Linux kernel version 2.2. If you try to use the Quagga IPv6 feature on a GNU/Linux kernel, please make sure the following libraries have been installed. Please note that these libraries will not be needed when you uses GNU C library 2.1 or upper. 'inet6-apps' The 'inet6-apps' package includes basic IPv6 related libraries such as 'inet_ntop' and 'inet_pton'. Some basic IPv6 programs such as 'ping', 'ftp', and 'inetd' are also included. The 'inet-apps' can be found at . 'net-tools' The 'net-tools' package provides an IPv6 enabled interface and routing utility. It contains 'ifconfig', 'route', 'netstat', and other tools. 'net-tools' may be found at . ---------- Footnotes ---------- (1) GNU/Linux has very flexible kernel configuration features  File: quagga.info, Node: Build the Software, Next: Install the Software, Prev: Configure the Software, Up: Installation 2.2 Build the Software ====================== After configuring the software, you will need to compile it for your system. Simply issue the 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 *Note Bug Reports::. % ./configure . . . ./configure output . . . % make  File: quagga.info, Node: Install the Software, Prev: Build the Software, Up: Installation 2.3 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 '/usr/local/bin', and '/usr/local/etc'. To install the Quagga suite, issue the following command at your shell prompt: 'make install'. % % make install % Quagga 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 '/etc/services'. 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 ospfapi 2607/tcp # ospfapi isisd 2608/tcp # ISISd vty pimd 2611/tcp # PIMd vty nhrpd 2612/tcp # nhrpd vty If you use a FreeBSD newer than 2.2.8, the above entries are already added to '/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 '/etc/quagga/*.conf'. *Note Config Commands::.  File: quagga.info, Node: Basic commands, Next: Zebra, Prev: Installation, Up: Top 3 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: * 'ripd', 'ripngd', 'ospfd', 'ospf6d', 'bgpd' * 'zebra' The following sections discuss commands common to all the routing daemons. * Menu: * Config Commands:: Commands used in config files * Terminal Mode Commands:: Common commands used in a VTY * Common Invocation Options:: Starting the daemons * Virtual Terminal Interfaces:: Interacting with the daemons  File: quagga.info, Node: Config Commands, Next: Terminal Mode Commands, Up: Basic commands 3.1 Config Commands =================== * Menu: * Basic Config Commands:: Some of the generic config commands * Sample Config File:: An example config file 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: '/etc/quagga/*.conf' Each of the daemons has its own config file. For example, zebra's default config file name is: '/etc/quagga/zebra.conf' The daemon name plus '.conf' is the default config file name. You can specify a config file using the '-f' or '--config-file' options when starting the daemon.  File: quagga.info, Node: Basic Config Commands, Next: Sample Config File, Up: Config Commands 3.1.1 Basic Config Commands --------------------------- -- Command: hostname HOSTNAME Set hostname of the router. -- Command: password PASSWORD Set password for vty interface. If there is no password, a vty won't accept connections. -- Command: enable password PASSWORD Set enable password. -- Command: log trap LEVEL -- Command: no log trap These commands are deprecated and are present only for historical compatibility. The log trap command sets the current logging level for all enabled logging destinations, and it sets the default for all future logging commands that do not specify a level. The normal default logging level is debugging. The 'no' form of the command resets the default level for future logging commands to debugging, but it does not change the logging level of existing logging destinations. -- Command: log stdout -- Command: log stdout LEVEL -- Command: no log stdout Enable logging output to stdout. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated 'log trap' command) will be used. The 'no' form of the command disables logging to stdout. The 'level' argument must have one of these values: emergencies, alerts, critical, errors, warnings, notifications, informational, or debugging. Note that the existing code logs its most important messages with severity 'errors'. -- Command: log file FILENAME -- Command: log file FILENAME LEVEL -- Command: no log file If you want to log into a file, please specify 'filename' as in this example: log file /var/log/quagga/bgpd.log informational If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated 'log trap' command) will be used. The 'no' form of the command disables logging to a file. Note: if you do not configure any file logging, and a daemon crashes due to a signal or an assertion failure, it will attempt to save the crash information in a file named /var/tmp/quagga..crashlog. For security reasons, this will not happen if the file exists already, so it is important to delete the file after reporting the crash information. -- Command: log syslog -- Command: log syslog LEVEL -- Command: no log syslog Enable logging output to syslog. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated 'log trap' command) will be used. The 'no' form of the command disables logging to syslog. -- Command: log monitor -- Command: log monitor LEVEL -- Command: no log monitor Enable logging output to vty terminals that have enabled logging using the 'terminal monitor' command. By default, monitor logging is enabled at the debugging level, but this command (or the deprecated 'log trap' command) can be used to change the monitor logging level. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated 'log trap' command) will be used. The 'no' form of the command disables logging to terminal monitors. -- Command: log facility FACILITY -- Command: no log facility This command changes the facility used in syslog messages. The default facility is 'daemon'. The 'no' form of the command resets the facility to the default 'daemon' facility. -- Command: log record-priority -- Command: no log record-priority To include the severity in all messages logged to a file, to stdout, or to a terminal monitor (i.e. anything except syslog), use the 'log record-priority' global configuration command. To disable this option, use the 'no' form of the command. By default, the severity level is not included in logged messages. Note: some versions of syslogd (including Solaris) can be configured to include the facility and level in the messages emitted. -- Command: log timestamp precision <0-6> -- Command: no log timestamp precision This command sets the precision of log message timestamps to the given number of digits after the decimal point. Currently, the value must be in the range 0 to 6 (i.e. the maximum precision is microseconds). To restore the default behavior (1-second accuracy), use the 'no' form of the command, or set the precision explicitly to 0. log timestamp precision 3 In this example, the precision is set to provide timestamps with millisecond accuracy. -- Command: log commands This command enables the logging of all commands typed by a user to all enabled log destinations. The note that logging includes full command lines, including passwords. Once set, command logging can only be turned off by restarting the daemon. -- Command: service password-encryption Encrypt password. -- Command: service advanced-vty Enable advanced mode VTY. -- Command: service terminal-length <0-512> Set system wide line configuration. This configuration command applies to all VTY interfaces. -- Command: line vty Enter vty configuration mode. -- Command: banner motd default Set default motd string. -- Command: no banner motd No motd banner string will be printed. -- Line Command: exec-timeout MINUTE -- Line Command: exec-timeout MINUTE 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. -- Line Command: no exec-timeout Do not perform timeout at all. This command is as same as 'exec-timeout 0 0'. -- Line Command: access-class ACCESS-LIST Restrict vty connections with an access list.  File: quagga.info, Node: Sample Config File, Prev: Basic Config Commands, Up: Config Commands 3.1.2 Sample Config File ------------------------ Below is a sample configuration file for the zebra daemon. ! ! Zebra configuration file ! hostname Router password zebra enable password zebra ! log stdout ! ! '!' 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. password zebra!password 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'.  File: quagga.info, Node: Terminal Mode Commands, Next: Common Invocation Options, Prev: Config Commands, Up: Basic commands 3.2 Terminal Mode Commands ========================== -- Command: write terminal Displays the current configuration to the vty interface. -- Command: write file Write current configuration to configuration file. -- Command: configure terminal Change to configuration mode. This command is the first step to configuration. -- Command: terminal length <0-512> Set terminal display length to <0-512>. If length is 0, no display control is performed. -- Command: who Show a list of currently connected vty sessions. -- Command: list List all available commands. -- Command: show version Show the current version of Quagga and its build host information. -- Command: show logging Shows the current configuration of the logging system. This includes the status of all logging destinations. -- Command: logmsg LEVEL MESSAGE Send a message to all logging destinations that are enabled for messages of the given severity.  File: quagga.info, Node: Common Invocation Options, Next: Virtual Terminal Interfaces, Prev: Terminal Mode Commands, Up: Basic commands 3.3 Common Invocation Options ============================= These options apply to all Quagga daemons. '-d' '--daemon' Runs in daemon mode. '-f FILE' '--config_file=FILE' Set configuration file name. '-h' '--help' Display this help and exit. '-i FILE' '--pid_file=FILE' Upon startup the process identifier of the daemon is written to a file, typically in '/var/run'. This file can be used by the init system to implement commands such as '.../init.d/zebra status', '.../init.d/zebra restart' or '.../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 Quagga to implement a routing looking glass. One machine can be used to collect differing routing views from differing points in the network. '-A ADDRESS' '--vty_addr=ADDRESS' Set the VTY local address to bind to. If set, the VTY socket will only be bound to this address. '-P PORT' '--vty_port=PORT' Set the VTY TCP port number. If set to 0 then the TCP VTY sockets will not be opened. '-u USER' '--vty_addr=USER' Set the user and group to run as. '-v' '--version' Print program version.  File: quagga.info, Node: Virtual Terminal Interfaces, Prev: Common Invocation Options, Up: Basic commands 3.4 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  File: quagga.info, Node: VTY Overview, Next: VTY Modes, Up: Virtual Terminal Interfaces 3.4.1 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. % telnet localhost 2601 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello, this is Quagga (version 1.2.4) Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. 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# '?' is very useful for looking up commands.  File: quagga.info, Node: VTY Modes, Next: VTY CLI Commands, Prev: VTY Overview, Up: Virtual Terminal Interfaces 3.4.2 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) There are commands that may be restricted to specific VTY modes.  File: quagga.info, Node: VTY View Mode, Next: VTY Enable Mode, Up: VTY Modes 3.4.2.1 VTY View Mode ..................... This mode is for read-only access to the CLI. One may exit the mode by leaving the system, or by entering 'enable' mode.  File: quagga.info, Node: VTY Enable Mode, Next: VTY Other Modes, Prev: VTY View Mode, Up: VTY Modes 3.4.2.2 VTY Enable Mode ....................... 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.  File: quagga.info, Node: VTY Other Modes, Prev: VTY Enable Mode, Up: VTY Modes 3.4.2.3 VTY Other Modes ....................... This page is for describing other modes.  File: quagga.info, Node: VTY CLI Commands, Prev: VTY Modes, Up: Virtual Terminal Interfaces 3.4.3 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  File: quagga.info, Node: CLI Movement Commands, Next: CLI Editing Commands, Up: VTY CLI Commands 3.4.3.1 CLI Movement Commands ............................. These commands are used for moving the CLI cursor. The character means press the Control Key. 'C-f' '' Move forward one character. 'C-b' '' Move backward one character. 'M-f' Move forward one word. 'M-b' Move backward one word. 'C-a' Move to the beginning of the line. 'C-e' Move to the end of the line.  File: quagga.info, Node: CLI Editing Commands, Next: CLI Advanced Commands, Prev: CLI Movement Commands, Up: VTY CLI Commands 3.4.3.2 CLI Editing Commands ............................ These commands are used for editing text on a line. The character means press the Control Key. 'C-h' '' Delete the character before point. 'C-d' Delete the character after point. 'M-d' Forward kill word. 'C-w' Backward kill word. 'C-k' Kill to the end of the line. 'C-u' Kill line from the beginning, erasing input. 'C-t' Transpose character. 'C-v' Interpret following character literally. Do not treat it specially. This can be used to, e.g., type in a literal '?' rather than do help completion.  File: quagga.info, Node: CLI Advanced Commands, Prev: CLI Editing Commands, Up: VTY CLI Commands 3.4.3.3 CLI Advanced Commands ............................. There are several additional CLI commands for command line completions, insta-help, and VTY session management. 'C-c' Interrupt current input and moves to the next line. 'C-z' End current configuration session and move to top node. 'C-n' '' Move down to next line in the history buffer. 'C-p' '' Move up to previous line in the history buffer. 'TAB' Use command line completion by typing . '?' You can use command line help by typing 'help' at the beginning of the line. Typing '?' at any point in the line will show possible completions. To enter an actual '?' character rather show completions, e.g. to enter into a regexp, use '-v ?'.  File: quagga.info, Node: Zebra, Next: RIP, Prev: Basic commands, Up: Top 4 Zebra ******* '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 * Multicast RIB Commands:: Commands for controlling MRIB behavior * zebra Route Filtering:: Commands for zebra route filtering * zebra FIB push interface:: Interface to optional FPM component * zebra Terminal Mode Commands:: Commands for zebra's VTY  File: quagga.info, Node: Invoking zebra, Next: Interface Commands, Up: Zebra 4.1 Invoking zebra ================== Besides the common invocation options (*note Common Invocation Options::), the 'zebra' specific invocation options are listed below. '-b' '--batch' Runs in batch mode. 'zebra' parses configuration file and terminates immediately. '-k' '--keep_kernel' When zebra starts up, don't delete old self inserted routes. '-r' '--retain' When program terminates, retain routes added by zebra.  File: quagga.info, Node: Interface Commands, Next: Static Route Commands, Prev: Invoking zebra, Up: Zebra 4.2 Interface Commands ====================== * Menu: * Standard Commands:: * Link Parameters Commands::  File: quagga.info, Node: Standard Commands, Next: Link Parameters Commands, Up: Interface Commands 4.2.1 Standard Commands ----------------------- -- Command: interface IFNAME -- Interface Command: shutdown -- Interface Command: no shutdown Up or down the current interface. -- Interface Command: ip address ADDRESS/PREFIX -- Interface Command: ipv6 address ADDRESS/PREFIX -- Interface Command: no ip address ADDRESS/PREFIX -- Interface Command: no ipv6 address ADDRESS/PREFIX Set the IPv4 or IPv6 address/prefix for the interface. -- Interface Command: ip address ADDRESS/PREFIX secondary -- Interface Command: no ip address ADDRESS/PREFIX secondary Set the secondary flag for this address. This causes ospfd to not treat the address as a distinct subnet. -- Interface Command: description DESCRIPTION ... Set description for the interface. -- Interface Command: multicast -- Interface Command: no multicast Enable or disables multicast flag for the interface. -- Interface Command: bandwidth <1-10000000> -- Interface Command: no bandwidth <1-10000000> Set bandwidth value of the interface in kilobits/sec. This is for calculating OSPF cost. This command does not affect the actual device configuration. -- Interface Command: link-detect -- Interface Command: no link-detect Enable/disable link-detect on platforms which support this. Currently only Linux and Solaris, and only where network interface drivers support reporting link-state via the IFF_RUNNING flag.  File: quagga.info, Node: Link Parameters Commands, Prev: Standard Commands, Up: Interface Commands 4.2.2 Link Parameters Commands ------------------------------ -- Interface Command: link-params -- Interface Command: no link-param Enter into the link parameters sub node. At least 'enable' must be set to activate the link parameters, and consequently Traffic Engineering on this interface. MPLS-TE must be enable at the OSPF (*note OSPF Traffic Engineering::) or ISIS (*note ISIS Traffic Engineering::) router level in complement to this. Disable link parameters for this interface. Under link parameter statement, the following commands set the different TE values: -- link-params: enable Enable link parameters for this interface. -- link-params: metric <0-4294967295> -- link-params: max-bw BANDWIDTH -- link-params: max-rsv-bw BANDWIDTH -- link-params: unrsv-bw <0-7> BANDWIDTH -- link-params: admin-grp BANDWIDTH These commands specifies the Traffic Engineering parameters of the interface in conformity to RFC3630 (OSPF) or RFC5305 (ISIS). There are respectively the TE Metric (different from the OSPF or ISIS metric), Maximum Bandwidth (interface speed by default), Maximum Reservable Bandwidth, Unreserved Bandwidth for each 0-7 priority and Admin Group (ISIS) or Resource Class/Color (OSPF). Note that BANDWIDTH are specified in IEEE floating point format and express in Bytes/second. -- link-param: delay <0-16777215> [min <0-16777215> | max <0-16777215>] -- link-param: delay-variation <0-16777215> -- link-param: packet-loss PERCENTAGE -- link-param: res-bw BANDWIDTH -- link-param: ava-bw BANDWIDTH -- link-param: use-bw BANDWIDTH These command specifies additionnal Traffic Engineering parameters of the interface in conformity to draft-ietf-ospf-te-metrics-extension-05.txt and draft-ietf-isis-te-metrics-extension-03.txt. There are respectively the delay, jitter, loss, available bandwidth, reservable bandwidth and utilized bandwidth. Note that BANDWIDTH are specified in IEEE floating point format and express in Bytes/second. Delays and delay variation are express in micro-second (µs). Loss is specified in PERCENTAGE ranging from 0 to 50.331642% by step of 0.000003. -- link-param: neighbor as <0-65535> -- link-param: no neighbor Specifies the remote ASBR IP address and Autonomous System (AS) number for InterASv2 link in OSPF (RFC5392). Note that this option is not yet supported for ISIS (RFC5316).  File: quagga.info, Node: Static Route Commands, Next: Multicast RIB Commands, Prev: Interface Commands, Up: Zebra 4.3 Static Route Commands ========================= Static routing is a very fundamental feature of routing technology. It defines static prefix and gateway. -- Command: ip route NETWORK GATEWAY NETWORK is destination prefix with format of A.B.C.D/M. GATEWAY is gateway for the prefix. When GATEWAY is A.B.C.D format. It is taken as a IPv4 address gateway. Otherwise it is treated as an interface name. If the interface name is NULL0 then zebra installs a blackhole route. ip route 10.0.0.0/8 10.0.0.2 ip route 10.0.0.0/8 ppp0 ip route 10.0.0.0/8 null0 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. The third install a blackhole route. -- Command: ip route NETWORK NETMASK GATEWAY This is alternate version of above command. When NETWORK is A.B.C.D format, user must define NETMASK value with A.B.C.D format. GATEWAY is same option as above command ip route 10.0.0.0 255.0.0.0 10.0.0.2 ip route 10.0.0.0 255.0.0.0 ppp0 ip route 10.0.0.0 255.0.0.0 null0 These statements are equivalent to those in the previous example. -- Command: ip route NETWORK GATEWAY DISTANCE Installs the route with the specified distance. Multiple nexthop static route 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. If zebra has been compiled with multipath support, and both 10.0.0.2 and 10.0.0.3 are reachable, zebra will install a multipath route via both nexthops, if the platform supports this. 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 ip route 10.0.0.0/8 10.0.0.2 ip route 10.0.0.0/8 10.0.0.3 ip route 10.0.0.0/8 null0 255 This will install a multihop route via the specified next-hops if they are reachable, as well as a high-metric blackhole route, which can be useful to prevent traffic destined for a prefix to match less-specific routes (eg default) should the specified gateways not be reachable. Eg: zebra> show ip route 10.0.0.0/8 Routing entry for 10.0.0.0/8 Known via "static", distance 1, metric 0 10.0.0.2 inactive 10.0.0.3 inactive Routing entry for 10.0.0.0/8 Known via "static", distance 255, metric 0 directly connected, Null0 -- Command: ipv6 route NETWORK GATEWAY -- Command: ipv6 route NETWORK GATEWAY DISTANCE These behave similarly to their ipv4 counterparts. -- Command: table 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 TABLENO with this command, static routes defined after this are added to the specified table.  File: quagga.info, Node: Multicast RIB Commands, Next: zebra Route Filtering, Prev: Static Route Commands, Up: Zebra 4.4 Multicast RIB Commands ========================== The Multicast RIB provides a separate table of unicast destinations which is used for Multicast Reverse Path Forwarding decisions. It is used with a multicast source's IP address, hence contains not multicast group addresses but unicast addresses. This table is fully separate from the default unicast table. However, RPF lookup can include the unicast table. WARNING: RPF lookup results are non-responsive in this version of Quagga, i.e. multicast routing does not actively react to changes in underlying unicast topology! -- Command: ip multicast rpf-lookup-mode MODE -- Command: no ip multicast rpf-lookup-mode [MODE] MODE sets the method used to perform RPF lookups. Supported modes: 'urib-only' Performs the lookup on the Unicast RIB. The Multicast RIB is never used. 'mrib-only' Performs the lookup on the Multicast RIB. The Unicast RIB is never used. 'mrib-then-urib' Tries to perform the lookup on the Multicast RIB. If any route is found, that route is used. Otherwise, the Unicast RIB is tried. 'lower-distance' Performs a lookup on the Multicast RIB and Unicast RIB each. The result with the lower administrative distance is used; if they're equal, the Multicast RIB takes precedence. 'longer-prefix' Performs a lookup on the Multicast RIB and Unicast RIB each. The result with the longer prefix length is used; if they're equal, the Multicast RIB takes precedence. The 'mrib-then-urib' setting is the default behavior if nothing is configured. If this is the desired behavior, it should be explicitly configured to make the configuration immune against possible changes in what the default behavior is. WARNING: Unreachable routes do not receive special treatment and do not cause fallback to a second lookup. -- Command: show ip rpf ADDR Performs a Multicast RPF lookup, as configured with 'ip multicast rpf-lookup-mode MODE'. ADDR specifies the multicast source address to look up. > show ip rpf 192.0.2.1 Routing entry for 192.0.2.0/24 using Unicast RIB Known via "kernel", distance 0, metric 0, best * 198.51.100.1, via eth0 Indicates that a multicast source lookup for 192.0.2.1 would use an Unicast RIB entry for 192.0.2.0/24 with a gateway of 198.51.100.1. -- Command: show ip rpf Prints the entire Multicast RIB. Note that this is independent of the configured RPF lookup mode, the Multicast RIB may be printed yet not used at all. -- Command: ip mroute PREFIX NEXTHOP [DISTANCE] -- Command: no ip mroute PREFIX NEXTHOP [DISTANCE] Adds a static route entry to the Multicast RIB. This performs exactly as the 'ip route' command, except that it inserts the route in the Multicast RIB instead of the Unicast RIB.  File: quagga.info, Node: zebra Route Filtering, Next: zebra FIB push interface, Prev: Multicast RIB Commands, Up: Zebra 4.5 zebra Route Filtering ========================= Zebra supports 'prefix-list' and 'route-map' to match routes received from other quagga components. The 'permit'/'deny' facilities provided by these commands can be used to filter which routes zebra will install in the kernel. -- Command: ip protocol PROTOCOL route-map ROUTEMAP Apply a route-map filter to routes for the specified protocol. PROTOCOL can be any or one of system, kernel, connected, static, rip, ripng, ospf, ospf6, isis, bgp, hsls. -- Route Map: set src ADDRESS Within a route-map, set the preferred source address for matching routes when installing in the kernel. The following creates a prefix-list that matches all addresses, a route-map that sets the preferred source address, and applies the route-map to all 'rip' routes. ip prefix-list ANY permit 0.0.0.0/0 le 32 route-map RM1 permit 10 match ip address prefix-list ANY set src 10.0.0.1 ip protocol rip route-map RM1  File: quagga.info, Node: zebra FIB push interface, Next: zebra Terminal Mode Commands, Prev: zebra Route Filtering, Up: Zebra 4.6 zebra FIB push interface ============================ Zebra supports a 'FIB push' interface that allows an external component to learn the forwarding information computed by the Quagga routing suite. In Quagga, the Routing Information Base (RIB) resides inside zebra. Routing protocols communicate their best routes to zebra, and zebra computes the best route across protocols for each prefix. This latter information makes up the Forwarding Information Base (FIB). Zebra feeds the FIB to the kernel, which allows the IP stack in the kernel to forward packets according to the routes computed by Quagga. The kernel FIB is updated in an OS-specific way. For example, the 'netlink' interface is used on Linux, and route sockets are used on FreeBSD. The FIB push interface aims to provide a cross-platform mechanism to support scenarios where the router has a forwarding path that is distinct from the kernel, commonly a hardware-based fast path. In these cases, the FIB needs to be maintained reliably in the fast path as well. We refer to the component that programs the forwarding plane (directly or indirectly) as the Forwarding Plane Manager or FPM. The FIB push interface comprises of a TCP connection between zebra and the FPM. The connection is initiated by zebra - that is, the FPM acts as the TCP server. The relevant zebra code kicks in when zebra is configured with the '--enable-fpm' flag. Zebra periodically attempts to connect to the well-known FPM port. Once the connection is up, zebra starts sending messages containing routes over the socket to the FPM. Zebra sends a complete copy of the forwarding table to the FPM, including routes that it may have picked up from the kernel. The existing interaction of zebra with the kernel remains unchanged - that is, the kernel continues to receive FIB updates as before. The encapsulation header for the messages exchanged with the FPM is defined by the file 'fpm/fpm.h' in the quagga tree. The routes themselves are encoded in netlink or protobuf format, with netlink being the default. Protobuf is one of a number of new serialization formats wherein the message schema is expressed in a purpose-built language. Code for encoding/decoding to/from the wire format is generated from the schema. Protobuf messages can be extended easily while maintaining backward-compatibility with older code. Protobuf has the following advantages over netlink: * Code for serialization/deserialization is generated automatically. This reduces the likelihood of bugs, allows third-party programs to be integrated quickly, and makes it easy to add fields. * The message format is not tied to an OS (Linux), and can be evolved independently. As mentioned before, zebra encodes routes sent to the FPM in netlink format by default. The format can be controlled via the '--fpm_format' command-line option to zebra, which currently takes the values 'netlink' and 'protobuf'. The zebra FPM interface uses replace semantics. That is, if a 'route add' message for a prefix is followed by another 'route add' message, the information in the second message is complete by itself, and replaces the information sent in the first message. If the connection to the FPM goes down for some reason, zebra sends the FPM a complete copy of the forwarding table(s) when it reconnects.  File: quagga.info, Node: zebra Terminal Mode Commands, Prev: zebra FIB push interface, Up: Zebra 4.7 zebra Terminal Mode Commands ================================ -- Command: show ip route Display current routes which zebra holds in its database. 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 -- Command: show ipv6 route -- Command: show interface -- Command: show ip prefix-list [NAME] -- Command: show route-map [NAME] -- Command: show ip protocol -- 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. -- Command: show ipv6forward Display whether the host's IP v6 forwarding is enabled or not. -- Command: show zebra fpm stats Display statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component. -- Command: clear zebra fpm stats Reset statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component.  File: quagga.info, Node: RIP, Next: RIPng, Prev: Zebra, Up: Top 5 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 "distance-vector" protocol and is based on the "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. 'ripd' supports RIP version 2 as described in RFC2453 and RIP version 1 as described in RFC1058. * Menu: * Starting and Stopping ripd:: * RIP Configuration:: * RIP Version Control:: * 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::  File: quagga.info, Node: Starting and Stopping ripd, Next: RIP Configuration, Up: RIP 5.1 Starting and Stopping ripd ============================== The default configuration file name of 'ripd''s is 'ripd.conf'. When invocation 'ripd' searches directory /etc/quagga. If 'ripd.conf' is not there next search current directory. RIP uses UDP port 520 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 'zebra' daemon. So running 'zebra' is mandatory to run 'ripd'. Thus minimum sequence for running RIP is like below: # zebra -d # ripd -d Please note that 'zebra' must be invoked before 'ripd'. To stop 'ripd'. Please use 'kill `cat /var/run/ripd.pid`'. Certain signals have special meaningss to 'ripd'. 'SIGHUP' Reload configuration file 'ripd.conf'. All configurations are reseted. All routes learned so far are cleared and removed from routing table. 'SIGUSR1' Rotate 'ripd' logfile. 'SIGINT' 'SIGTERM' 'ripd' sweeps all installed RIP routes then terminates properly. 'ripd' invocation options. Common options that can be specified (*note Common Invocation Options::). '-r' '--retain' When the program terminates, retain routes added by 'ripd'. * Menu: * RIP netmask::  File: quagga.info, Node: RIP netmask, Up: Starting and Stopping ripd 5.1.1 RIP netmask ----------------- The netmask features of '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. Quagga '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.  File: quagga.info, Node: RIP Configuration, Next: RIP Version Control, Prev: Starting and Stopping ripd, Up: RIP 5.2 RIP Configuration ===================== -- Command: router rip The 'router rip' command is necessary to enable RIP. To disable RIP, use the 'no router rip' command. RIP must be enabled before carrying out any of the RIP commands. -- Command: no router rip Disable RIP. -- RIP Command: network NETWORK -- RIP Command: no network NETWORK Set the RIP enable interface by NETWORK. The interfaces which have addresses matching with 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 'no network' command will disable RIP for the specified network. -- RIP Command: network IFNAME -- RIP Command: no network IFNAME Set a RIP enabled interface by IFNAME. Both the sending and receiving of RIP packets will be enabled on the port specified in the 'network ifname' command. The 'no network ifname' command will disable RIP on the specified interface. -- RIP Command: neighbor A.B.C.D -- RIP Command: no neighbor 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 'no neighbor a.b.c.d' command will disable the RIP neighbor. Below is very simple RIP configuration. Interface 'eth0' and interface which address match to '10.0.0.0/8' are RIP enabled. ! router rip network 10.0.0.0/8 network eth0 ! Passive interface -- RIP command: passive-interface (IFNAME|default) -- RIP command: no passive-interface 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 'neighbor' command. The interface may be specified as DEFAULT to make ripd default to passive on all interfaces. The default is to be passive on all interfaces. RIP split-horizon -- Interface command: ip split-horizon -- Interface command: no ip split-horizon Control split-horizon on the interface. Default is 'ip split-horizon'. If you don't perform split-horizon on the interface, please specify 'no ip split-horizon'.  File: quagga.info, Node: RIP Version Control, Next: How to Announce RIP route, Prev: RIP Configuration, Up: RIP 5.3 RIP Version Control ======================= RIP can be configured to send either Version 1 or Version 2 packets. The default is to send RIPv2 while accepting both RIPv1 and RIPv2 (and replying with packets of the appropriate version for REQUESTS / triggered updates). The version to receive and send can be specified globally, and further overriden on a per-interface basis if needs be for send and receive seperately (see below). It is important to note that RIPv1 can not be authenticated. Further, if RIPv1 is enabled then RIP will reply to REQUEST packets, sending the state of its RIP routing table to any remote routers that ask on demand. For a more detailed discussion on the security implications of RIPv1 see *note RIP Authentication::. -- RIP Command: version VERSION Set RIP version to accept for reads and send. VERSION can be either '1" or '2". Disabling RIPv1 by specifying version 2 is STRONGLY encouraged, *Note RIP Authentication::. This may become the default in a future release. Default: Send Version 2, and accept either version. -- RIP Command: no version Reset the global version setting back to the default. -- Interface command: ip rip send version VERSION VERSION can be '1', '2' or '1 2'. This interface command overrides the global rip version setting, and selects which version of RIP to send packets with, for this interface specifically. Choice of RIP Version 1, RIP Version 2, or both versions. In the latter case, where '1 2' is specified, packets will be both broadcast and multicast. Default: Send packets according to the global version (version 2) -- Interface command: ip rip receive version VERSION VERSION can be '1', '2' or '1 2'. This interface command overrides the global rip version setting, and selects which versions of RIP packets will be accepted on this interface. Choice of RIP Version 1, RIP Version 2, or both. Default: Accept packets according to the global setting (both 1 and 2).  File: quagga.info, Node: How to Announce RIP route, Next: Filtering RIP Routes, Prev: RIP Version Control, Up: RIP 5.4 How to Announce RIP route ============================= -- RIP command: redistribute kernel -- RIP command: redistribute kernel metric <0-16> -- RIP command: redistribute kernel route-map ROUTE-MAP -- RIP command: no redistribute kernel 'redistribute kernel' redistributes routing information from kernel route entries into the RIP tables. 'no redistribute kernel' disables the routes. -- RIP command: redistribute static -- RIP command: redistribute static metric <0-16> -- RIP command: redistribute static route-map ROUTE-MAP -- RIP command: no redistribute static 'redistribute static' redistributes routing information from static route entries into the RIP tables. 'no redistribute static' disables the routes. -- RIP command: redistribute connected -- RIP command: redistribute connected metric <0-16> -- RIP command: redistribute connected route-map ROUTE-MAP -- RIP command: no redistribute connected Redistribute connected routes into the RIP tables. '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. -- RIP command: redistribute ospf -- RIP command: redistribute ospf metric <0-16> -- RIP command: redistribute ospf route-map ROUTE-MAP -- RIP command: no redistribute ospf 'redistribute ospf' redistributes routing information from ospf route entries into the RIP tables. 'no redistribute ospf' disables the routes. -- RIP command: redistribute bgp -- RIP command: redistribute bgp metric <0-16> -- RIP command: redistribute bgp route-map ROUTE-MAP -- RIP command: no redistribute bgp 'redistribute bgp' redistributes routing information from bgp route entries into the RIP tables. 'no redistribute bgp' disables the routes. If you want to specify RIP only static routes: -- RIP command: default-information originate -- RIP command: route A.B.C.D/M -- RIP command: no route A.B.C.D/M This command is specific to Quagga. The '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 Quagga and redistributing it in RIP using 'redistribute static'.  File: quagga.info, Node: Filtering RIP Routes, Next: RIP Metric Manipulation, Prev: How to Announce RIP route, Up: RIP 5.5 Filtering RIP Routes ======================== RIP routes can be filtered by a distribute-list. -- Command: distribute-list ACCESS_LIST DIRECT IFNAME You can apply access lists to the interface with a 'distribute-list' command. ACCESS_LIST is the access list name. DIRECT is 'in' or 'out'. If DIRECT is 'in' the access list is applied to input packets. The 'distribute-list' command can be used to filter the RIP path. '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 'eth0' will permit only the paths that match the route 10.0.0.0/8 ! router rip distribute-list private in eth0 ! access-list private permit 10 10.0.0.0/8 access-list private deny any ! 'distribute-list' can be applied to both incoming and outgoing data. -- Command: distribute-list prefix PREFIX_LIST (in|out) IFNAME You can apply prefix lists to the interface with a 'distribute-list' command. PREFIX_LIST is the prefix list name. Next is the direction of 'in' or 'out'. If DIRECT is 'in' the access list is applied to input packets.  File: quagga.info, Node: RIP Metric Manipulation, Next: RIP distance, Prev: Filtering RIP Routes, Up: RIP 5.6 RIP Metric Manipulation =========================== RIP metric is a value for distance for the network. Usually 'ripd' increment the metric when the network information is received. Redistributed routes' metric is set to 1. -- RIP command: default-metric <1-16> -- 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 'redistribute connected'. To modify connected route's metric value, please use 'redistribute connected metric' or 'route-map'. 'offset-list' also affects connected routes. -- RIP command: offset-list ACCESS-LIST (in|out) -- RIP command: offset-list ACCESS-LIST (in|out) IFNAME  File: quagga.info, Node: RIP distance, Next: RIP route-map, Prev: RIP Metric Manipulation, Up: RIP 5.7 RIP distance ================ Distance value is used in zebra daemon. Default RIP distance is 120. -- RIP command: distance <1-255> -- RIP command: no distance <1-255> Set default RIP distance to specified value. -- RIP command: distance <1-255> A.B.C.D/M -- RIP command: no distance <1-255> A.B.C.D/M Set default RIP distance to specified value when the route's source IP address matches the specified prefix. -- RIP command: distance <1-255> A.B.C.D/M ACCESS-LIST -- RIP command: no distance <1-255> A.B.C.D/M 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.  File: quagga.info, Node: RIP route-map, Next: RIP Authentication, Prev: RIP distance, Up: RIP 5.8 RIP route-map ================= Usage of 'ripd''s route-map support. Optional argument route-map MAP_NAME can be added to each 'redistribute' statement. redistribute static [route-map MAP_NAME] redistribute connected [route-map MAP_NAME] ..... Cisco applies route-map _before_ routes will exported to rip route table. In current Quagga's test implementation, '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 (*note Route Map::) is needed to use route-map functionality. -- Route Map: match interface 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. -- Route Map: match ip address WORD -- Route Map: match ip address prefix-list WORD Match if route destination is permitted by access-list. -- Route Map: match ip next-hop WORD -- Route Map: match ip next-hop prefix-list WORD Match if route next-hop (meaning next-hop listed in the rip route-table as displayed by "show ip rip") is permitted by access-list. -- 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. -- 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. -- 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.  File: quagga.info, Node: RIP Authentication, Next: RIP Timers, Prev: RIP route-map, Up: RIP 5.9 RIP Authentication ====================== RIPv2 allows packets to be authenticated via either an insecure plain text password, included with the packet, or via a more secure MD5 based HMAC (keyed-Hashing for Message AuthentiCation), RIPv1 can not be authenticated at all, thus when authentication is configured 'ripd' will discard routing updates received via RIPv1 packets. However, unless RIPv1 reception is disabled entirely, *Note RIP Version Control::, RIPv1 REQUEST packets which are received, which query the router for routing information, will still be honoured by 'ripd', and 'ripd' WILL reply to such packets. This allows 'ripd' to honour such REQUESTs (which sometimes is used by old equipment and very simple devices to bootstrap their default route), while still providing security for route updates which are received. In short: Enabling authentication prevents routes being updated by unauthenticated remote routers, but still can allow routes (I.e. the entire RIP routing table) to be queried remotely, potentially by anyone on the internet, via RIPv1. To prevent such unauthenticated querying of routes disable RIPv1, *Note RIP Version Control::. -- Interface command: ip rip authentication mode md5 -- Interface command: no ip rip authentication mode md5 Set the interface with RIPv2 MD5 authentication. -- Interface command: ip rip authentication mode text -- Interface command: no ip rip authentication mode text Set the interface with RIPv2 simple password authentication. -- Interface command: ip rip authentication string STRING -- Interface command: no ip rip authentication string STRING RIP version 2 has simple text authentication. This command sets authentication string. The string must be shorter than 16 characters. -- Interface command: ip rip authentication key-chain KEY-CHAIN -- Interface command: no ip rip authentication key-chain KEY-CHAIN Specifiy Keyed MD5 chain. ! key chain test key 1 key-string test ! interface eth1 ip rip authentication mode md5 ip rip authentication key-chain test !  File: quagga.info, Node: RIP Timers, Next: Show RIP Information, Prev: RIP Authentication, Up: RIP 5.10 RIP Timers =============== -- RIP command: timers basic UPDATE TIMEOUT GARBAGE RIP protocol has several timers. User can configure those timers' values by 'timers basic' command. The default settings for the timers are as follows: * 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. * 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. * The garbage collect timer is 120 seconds. Upon expiration of the garbage-collection timer, the route is finally removed from the routing table. The 'timers basic' command allows the the default values of the timers listed above to be changed. -- RIP command: no timers basic The 'no timers basic' command will reset the timers to the default settings listed above.  File: quagga.info, Node: Show RIP Information, Next: RIP Debug Commands, Prev: RIP Timers, Up: RIP 5.11 Show RIP Information ========================= To display RIP routes. -- Command: show ip rip Show RIP routes. 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. -- Command: show ip rip status The command displays current RIP status. It includes RIP timer, filtering, version, RIP enabled interface and RIP peer inforation. ripd> show ip rip status 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  File: quagga.info, Node: RIP Debug Commands, Prev: Show RIP Information, Up: RIP 5.12 RIP Debug Commands ======================= Debug for RIP protocol. -- Command: debug rip events Debug rip events. 'debug rip' will show RIP events. Sending and receiving packets, timers, and changes in interfaces are events shown with 'ripd'. -- Command: debug rip packet Debug rip packet. '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. -- Command: debug rip zebra Debug rip between zebra communication. This command will show the communication between 'ripd' and 'zebra'. The main information will include addition and deletion of paths to the kernel and the sending and receiving of interface information. -- Command: show debugging rip Display 'ripd''s debugging option. 'show debugging rip' will show all information currently set for ripd debug.  File: quagga.info, Node: RIPng, Next: OSPFv2, Prev: RIP, Up: Top 6 RIPng ******* '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::  File: quagga.info, Node: Invoking ripngd, Next: ripngd Configuration, Up: RIPng 6.1 Invoking ripngd =================== There are no 'ripngd' specific invocation options. Common options can be specified (*note Common Invocation Options::).  File: quagga.info, Node: ripngd Configuration, Next: ripngd Terminal Mode Commands, Prev: Invoking ripngd, Up: RIPng 6.2 ripngd Configuration ======================== Currently ripngd supports the following commands: -- Command: router ripng Enable RIPng. -- RIPng Command: flush_timer TIME Set flush timer. -- RIPng Command: network NETWORK Set RIPng enabled interface by NETWORK -- RIPng Command: network IFNAME Set RIPng enabled interface by IFNAME -- RIPng Command: route NETWORK Set RIPng static routing announcement of NETWORK. -- Command: router zebra This command is the default and does not appear in the configuration. With this statement, RIPng routes go to the 'zebra' daemon.  File: quagga.info, Node: ripngd Terminal Mode Commands, Next: ripngd Filtering Commands, Prev: ripngd Configuration, Up: RIPng 6.3 ripngd Terminal Mode Commands ================================= -- Command: show ip ripng -- Command: show debugging ripng -- Command: debug ripng events -- Command: debug ripng packet -- Command: debug ripng zebra  File: quagga.info, Node: ripngd Filtering Commands, Prev: ripngd Terminal Mode Commands, Up: RIPng 6.4 ripngd Filtering Commands ============================= -- Command: distribute-list ACCESS_LIST (in|out) IFNAME You can apply an access-list to the interface using the 'distribute-list' command. ACCESS_LIST is an access-list name. DIRECT is 'in' or 'out'. If DIRECT is 'in', the access-list is applied only to incoming packets. distribute-list local-only out sit1  File: quagga.info, Node: OSPFv2, Next: OSPFv3, Prev: RIPng, Up: Top 7 OSPFv2 ******** OSPF (Open Shortest Path First) version 2 is a routing protocol which is described in 'RFC2328, OSPF Version 2'. OSPF is an IGP (Interior Gateway Protocol). Compared with RIP, OSPF can provide scalable network support and faster convergence times. OSPF is widely used in large networks such as ISP (Internet Service Provider) backbone and enterprise networks. * Menu: * OSPF Fundamentals:: * Configuring ospfd:: * OSPF router:: * OSPF area:: * OSPF interface:: * Redistribute routes to OSPF:: * Showing OSPF information:: * Opaque LSA:: * OSPF Traffic Engineering:: * Router Information:: * Debugging OSPF:: * OSPF Configuration Examples::  File: quagga.info, Node: OSPF Fundamentals, Next: Configuring ospfd, Up: OSPFv2 7.1 OSPF Fundamentals ===================== OSPF is, mostly, a link-state routing protocol. In contrast to "distance-vector" protocols, such as RIP or BGP, where routers describe available "paths" (i.e. routes) to each other, in "link-state" protocols routers instead describe the state of their links to their immediate neighbouring routers. Each router describes their link-state information in a message known as an LSA (Link State Advertisement), which is then propogated through to all other routers in a link-state routing domain, by a process called "flooding". Each router thus builds up an LSDB (Link State Database) of all the link-state messages. From this collection of LSAs in the LSDB, each router can then calculate the shortest path to any other router, based on some common metric, by using an algorithm such as Edgser Dijkstra (http://www.cs.utexas.edu/users/EWD/)'s SPF (Shortest Path First). By describing connectivity of a network in this way, in terms of routers and links rather than in terms of the paths through a network, a link-state protocol can use less bandwidth and converge more quickly than other protocols. A link-state protocol need distribute only one link-state message throughout the link-state domain when a link on any single given router changes state, in order for all routers to reconverge on the best paths through the network. In contrast, distance vector protocols can require a progression of different path update messages from a series of different routers in order to converge. The disadvantage to a link-state protocol is that the process of computing the best paths can be relatively intensive when compared to distance-vector protocols, in which near to no computation need be done other than (potentially) select between multiple routes. This overhead is mostly negligible for modern embedded CPUs, even for networks with thousands of nodes. The primary scaling overhead lies more in coping with the ever greater frequency of LSA updates as the size of a link-state area increases, in managing the LSDB and required flooding. This section aims to give a distilled, but accurate, description of the more important workings of OSPF which an administrator may need to know to be able best configure and trouble-shoot OSPF. 7.1.1 OSPF Mechanisms --------------------- OSPF defines a range of mechanisms, concerned with detecting, describing and propogating state through a network. These mechanisms will nearly all be covered in greater detail further on. They may be broadly classed as: "The Hello Protocol" The OSPF Hello protocol allows OSPF to quickly detect changes in two-way reachability between routers on a link. OSPF can additionally avail of other sources of reachability information, such as link-state information provided by hardware, or through dedicated reachability protocols such as BFD (Bi-directional Forwarding Detection). OSPF also uses the Hello protocol to propagate certain state between routers sharing a link, for example: * Hello protocol configured state, such as the dead-interval. * Router priority, for DR/BDR election. * DR/BDR election results. * Any optional capabilities supported by each router. The Hello protocol is comparatively trivial and will not be explored in greater detail than here. "LSAs" At the heart of OSPF are LSA (Link State Advertisement) messages. Despite the name, some LSAs do not, strictly speaking, describe link-state information. Common LSAs describe information such as: * Routers, in terms of their links. * Networks, in terms of attached routers. * Routes, external to a link-state domain: * External Routes Routes entirely external to OSPF. Routers originating such routes are known as ASBR (Autonomous-System Border Router) routers. * Summary Routes Routes which summarise routing information relating to OSPF areas external to the OSPF link-state area at hand, originated by ABR (Area Boundary Router) routers. "LSA Flooding" OSPF defines several related mechanisms, used to manage synchronisation of LSDBs between neighbours as neighbours form adjacencies and the propogation, or "flooding" of new or updated LSAs. *Note OSPF Flooding::. "Areas" OSPF provides for the protocol to be broken up into multiple smaller and independent link-state areas. Each area must be connected to a common backbone area by an ABR (Area Boundary Router). These ABR routers are responsible for summarising the link-state routing information of an area into "Summary LSAs", possibly in a condensed (i.e. aggregated) form, and then originating these summaries into all other areas the ABR is connected to. Note that only summaries and external routes are passed between areas. As these describe _paths_, rather than any router link-states, routing between areas hence is by "distance-vector", *not* link-state. *Note OSPF Areas::. 7.1.2 OSPF LSAs --------------- LSAs are the core object in OSPF. Everything else in OSPF revolves around detecting what to describe in LSAs, when to update them, how to flood them throughout a network and how to calculate routes from them. There are a variety of different LSAs, for purposes such as describing actual link-state information, describing paths (i.e. routes), describing bandwidth usage of links for TE (Traffic Engineering) purposes, and even arbitrary data by way of _Opaque_ LSAs. 7.1.2.1 LSA Header .................. All LSAs share a common header with the following information: * Type Different types of LSAs describe different things in OSPF. Types include: * Router LSA * Network LSA * Network Summary LSA * Router Summary LSA * AS-External LSA The specifics of the different types of LSA are examined below. * Advertising Router The Router ID of the router originating the LSA, see *note ospf router-id::. * LSA ID The ID of the LSA, which is typically derived in some way from the information the LSA describes, e.g. a Router LSA uses the Router ID as the LSA ID, a Network LSA will have the IP address of the DR as its LSA ID. The combination of the Type, ID and Advertising Router ID must uniquely identify the LSA. There can however be multiple instances of an LSA with the same Type, LSA ID and Advertising Router ID, see *note LSA Sequence Number: OSPF LSA sequence number. * Age A number to allow stale LSAs to, eventually, be purged by routers from their LSDBs. The value nominally is one of seconds. An age of 3600, i.e. 1 hour, is called the "MaxAge". MaxAge LSAs are ignored in routing calculations. LSAs must be periodically refreshed by their Advertising Router before reaching MaxAge if they are to remain valid. Routers may deliberately flood LSAs with the age artificially set to 3600 to indicate an LSA is no longer valid. This is called "flushing" of an LSA. It is not abnormal to see stale LSAs in the LSDB, this can occur where a router has shutdown without flushing its LSA(s), e.g. where it has become disconnected from the network. Such LSAs do little harm. * Sequence Number A number used to distinguish newer instances of an LSA from older instances. 7.1.2.2 Link-State LSAs ....................... Of all the various kinds of LSAs, just two types comprise the actual link-state part of OSPF, Router LSAs and Network LSAs. These LSA types are absolutely core to the protocol. Instances of these LSAs are specific to the link-state area in which they are originated. Routes calculated from these two LSA types are called "intra-area routes". * Router LSA Each OSPF Router must originate a router LSA to describe itself. In it, the router lists each of its OSPF enabled interfaces, for the given link-state area, in terms of: * Cost The output cost of that interface, scaled inversely to some commonly known reference value, *Note auto-cost reference-bandwidth: OSPF auto-cost reference-bandwidth. * Link Type * Transit Network A link to a multi-access network, on which the router has at least one Full adjacency with another router. * PtP (Point-to-Point) A link to a single remote router, with a Full adjacency. No DR (Designated Router) is elected on such links; no network LSA is originated for such a link. * Stub A link with no adjacent neighbours, or a host route. * Link ID and Data These values depend on the Link Type: Link Type Link ID Link Data -------------------------------------------------------------- Transit Link IP address of Interface IP address the DR Point-to-PointRouter ID of the Local interface IP remote router address, or the ifindex (MIB-II interface index) for unnumbered links Stub IP address Subnet Mask Links on a router may be listed multiple times in the Router LSA, e.g. a PtP interface on which OSPF is enabled must _always_ be described by a Stub link in the Router LSA, in addition to being listed as PtP link in the Router LSA if the adjacency with the remote router is Full. Stub links may also be used as a way to describe links on which OSPF is _not_ spoken, known as "passive interfaces", see *note passive-interface: OSPF passive-interface. * Network LSA On multi-access links (e.g. ethernets, certain kinds of ATM and X.25 configurations), routers elect a DR. The DR is responsible for originating a Network LSA, which helps reduce the information needed to describe multi-access networks with multiple routers attached. The DR also acts as a hub for the flooding of LSAs on that link, thus reducing flooding overheads. The contents of the Network LSA describes the: * Subnet Mask As the LSA ID of a Network LSA must be the IP address of the DR, the Subnet Mask together with the LSA ID gives you the network address. * Attached Routers Each router fully-adjacent with the DR is listed in the LSA, by their Router-ID. This allows the corresponding Router LSAs to be easily retrieved from the LSDB. Summary of Link State LSAs: LSA Type LSA ID Describes LSA Data Describes -------------------------------------------------------------------- Router LSA The Router ID The OSPF enabled links of the router, within a specific link-state area. Network LSA The IP address of the The Subnet Mask of the DR for the network network, and the Router IDs of all routers on the network. With an LSDB composed of just these two types of LSA, it is possible to construct a directed graph of the connectivity between all routers and networks in a given OSPF link-state area. So, not surprisingly, when OSPF routers build updated routing tables, the first stage of SPF calculation concerns itself only with these two LSA types. 7.1.2.3 Link-State LSA Examples ............................... The example below (*note OSPF Link-State LSA Example::) shows two LSAs, both originated by the same router (Router ID 192.168.0.49) and with the same LSA ID (192.168.0.49), but of different LSA types. The first LSA being the router LSA describing 192.168.0.49's links: 2 links to multi-access networks with fully-adjacent neighbours (i.e. Transit links) and 1 being a Stub link (no adjacent neighbours). The second LSA being a Network LSA, for which 192.168.0.49 is the DR, listing the Router IDs of 4 routers on that network which are fully adjacent with 192.168.0.49. # show ip ospf database router 192.168.0.49 OSPF Router with ID (192.168.0.53) Router Link States (Area 0.0.0.0) LS age: 38 Options: 0x2 : *|-|-|-|-|-|E|* LS Flags: 0x6 Flags: 0x2 : ASBR LS Type: router-LSA Link State ID: 192.168.0.49 Advertising Router: 192.168.0.49 LS Seq Number: 80000f90 Checksum: 0x518b Length: 60 Number of Links: 3 Link connected to: a Transit Network (Link ID) Designated Router address: 192.168.1.3 (Link Data) Router Interface address: 192.168.1.3 Number of TOS metrics: 0 TOS 0 Metric: 10 Link connected to: a Transit Network (Link ID) Designated Router address: 192.168.0.49 (Link Data) Router Interface address: 192.168.0.49 Number of TOS metrics: 0 TOS 0 Metric: 10 Link connected to: Stub Network (Link ID) Net: 192.168.3.190 (Link Data) Network Mask: 255.255.255.255 Number of TOS metrics: 0 TOS 0 Metric: 39063 # show ip ospf database network 192.168.0.49 OSPF Router with ID (192.168.0.53) Net Link States (Area 0.0.0.0) LS age: 285 Options: 0x2 : *|-|-|-|-|-|E|* LS Flags: 0x6 LS Type: network-LSA Link State ID: 192.168.0.49 (address of Designated Router) Advertising Router: 192.168.0.49 LS Seq Number: 80000074 Checksum: 0x0103 Length: 40 Network Mask: /29 Attached Router: 192.168.0.49 Attached Router: 192.168.0.52 Attached Router: 192.168.0.53 Attached Router: 192.168.0.54 Note that from one LSA, you can find the other. E.g. Given the Network-LSA you have a list of Router IDs on that network, from which you can then look up, in the local LSDB, the matching Router LSA. From that Router-LSA you may (potentially) find links to other Transit networks and Routers IDs which can be used to lookup the corresponding Router or Network LSA. And in that fashion, one can find all the Routers and Networks reachable from that starting LSA. Given the Router LSA instead, you have the IP address of the DR of any attached transit links. Network LSAs will have that IP as their LSA ID, so you can then look up that Network LSA and from that find all the attached routers on that link, leading potentially to more links and Network and Router LSAs, etc. etc. From just the above two LSAs, one can already see the following partial topology: --------------------- Network: ...... | Designated Router IP: 192.168.1.3 | IP: 192.168.1.3 (transit link) (cost: 10) Router ID: 192.168.0.49(stub)---------- IP: 192.168.3.190/32 (cost: 10) (cost: 39063) (transit link) IP: 192.168.0.49 | | ------------------------------ Network: 192.168.0.48/29 | | | Designated Router IP: 192.168.0.49 | | | | | Router ID: 192.168.0.54 | | | Router ID: 192.168.0.53 | Router ID: 192.168.0.52 Note the Router IDs, though they look like IP addresses and often are IP addresses, are not strictly speaking IP addresses, nor need they be reachable addresses (though, OSPF will calculate routes to Router IDs). 7.1.2.4 External LSAs ..................... External, or "Type 5", LSAs describe routing information which is entirely external to OSPF, and is "injected" into OSPF. Such routing information may have come from another routing protocol, such as RIP or BGP, they may represent static routes or they may represent a default route. An OSPF router which originates External LSAs is known as an ASBR (AS Boundary Router). Unlike the link-state LSAs, and most other LSAs, which are flooded only within the area in which they originate, External LSAs are flooded through-out the OSPF network to all areas capable of carrying External LSAs (*note OSPF Areas::). Routes internal to OSPF (intra-area or inter-area) are always preferred over external routes. The External LSA describes the following: * IP Network number The IP Network number of the route is described by the LSA ID field. * IP Network Mask The body of the External LSA describes the IP Network Mask of the route. This, together with the LSA ID, describes the prefix of the IP route concerned. * Metric The cost of the External Route. This cost may be an OSPF cost (also known as a "Type 1" metric), i.e. equivalent to the normal OSPF costs, or an externally derived cost ("Type 2" metric) which is not comparable to OSPF costs and always considered larger than any OSPF cost. Where there are both Type 1 and 2 External routes for a route, the Type 1 is always preferred. * Forwarding Address The address of the router to forward packets to for the route. This may be, and usually is, left as 0 to specify that the ASBR originating the External LSA should be used. There must be an internal OSPF route to the forwarding address, for the forwarding address to be useable. * Tag An arbitrary 4-bytes of data, not interpreted by OSPF, which may carry whatever information about the route which OSPF speakers desire. 7.1.2.5 AS External LSA Example ............................... To illustrate, below is an example of an External LSA in the LSDB of an OSPF router. It describes a route to the IP prefix of 192.168.165.0/24, originated by the ASBR with Router-ID 192.168.0.49. The metric of 20 is external to OSPF. The forwarding address is 0, so the route should forward to the originating ASBR if selected. # show ip ospf database external 192.168.165.0 LS age: 995 Options: 0x2 : *|-|-|-|-|-|E|* LS Flags: 0x9 LS Type: AS-external-LSA Link State ID: 192.168.165.0 (External Network Number) Advertising Router: 192.168.0.49 LS Seq Number: 800001d8 Checksum: 0xea27 Length: 36 Network Mask: /24 Metric Type: 2 (Larger than any link state path) TOS: 0 Metric: 20 Forward Address: 0.0.0.0 External Route Tag: 0 We can add this to our partial topology from above, which now looks like: --------------------- Network: ...... | Designated Router IP: 192.168.1.3 | IP: 192.168.1.3 /---- External route: 192.168.165.0/24 (transit link) / Cost: 20 (External metric) (cost: 10) / Router ID: 192.168.0.49(stub)---------- IP: 192.168.3.190/32 (cost: 10) (cost: 39063) (transit link) IP: 192.168.0.49 | | ------------------------------ Network: 192.168.0.48/29 | | | Designated Router IP: 192.168.0.49 | | | | | Router ID: 192.168.0.54 | | | Router ID: 192.168.0.53 | Router ID: 192.168.0.52 7.1.2.6 Summary LSAs .................... Summary LSAs are created by ABRs to summarise the destinations available within one area to other areas. These LSAs may describe IP networks, potentially in aggregated form, or ASBR routers. 7.1.3 OSPF Flooding ------------------- 7.1.4 OSPF Areas ----------------  File: quagga.info, Node: Configuring ospfd, Next: OSPF router, Prev: OSPF Fundamentals, Up: OSPFv2 7.2 Configuring ospfd ===================== There are no 'ospfd' specific options. Common options can be specified (*note Common Invocation Options::) to 'ospfd'. 'ospfd' needs to acquire interface information from 'zebra' in order to function. Therefore 'zebra' must be running before invoking 'ospfd'. Also, if 'zebra' is restarted then 'ospfd' must be too. Like other daemons, 'ospfd' configuration is done in OSPF specific configuration file 'ospfd.conf'.  File: quagga.info, Node: OSPF router, Next: OSPF area, Prev: Configuring ospfd, Up: OSPFv2 7.3 OSPF router =============== To start OSPF process you have to specify the OSPF router. As of this writing, 'ospfd' does not support multiple OSPF processes. -- Command: router ospf -- Command: no router ospf Enable or disable the OSPF process. 'ospfd' does not yet support multiple OSPF processes. So you can not specify an OSPF process number. -- OSPF Command: ospf router-id A.B.C.D -- OSPF Command: no ospf router-id This sets the router-ID of the OSPF process. The router-ID may be an IP address of the router, but need not be - it can be any arbitrary 32bit number. However it MUST be unique within the entire OSPF domain to the OSPF speaker - bad things will happen if multiple OSPF speakers are configured with the same router-ID! If one is not specified then 'ospfd' will obtain a router-ID automatically from 'zebra'. -- OSPF Command: ospf abr-type TYPE -- OSPF Command: no ospf abr-type TYPE TYPE can be cisco|ibm|shortcut|standard. The "Cisco" and "IBM" types are equivalent. The OSPF standard for ABR behaviour does not allow an ABR to consider routes through non-backbone areas when its links to the backbone are down, even when there are other ABRs in attached non-backbone areas which still can reach the backbone - this restriction exists primarily to ensure routing-loops are avoided. With the "Cisco" or "IBM" ABR type, the default in this release of Quagga, this restriction is lifted, allowing an ABR to consider summaries learnt from other ABRs through non-backbone areas, and hence route via non-backbone areas as a last resort when, and only when, backbone links are down. Note that areas with fully-adjacent virtual-links are considered to be "transit capable" and can always be used to route backbone traffic, and hence are unaffected by this setting (*note OSPF virtual-link::). More information regarding the behaviour controlled by this command can be found in 'RFC 3509, Alternative Implementations of OSPF Area Border Routers', and 'draft-ietf-ospf-shortcut-abr-02.txt'. Quote: "Though the definition of the ABR (Area Border Router) 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." -- OSPF Command: ospf rfc1583compatibility -- OSPF Command: no ospf rfc1583compatibility '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 specifically it demands that inter-area paths and intra-area backbone path are now of equal preference but still both preferred to external paths. This command should NOT be set normally. -- OSPF Command: log-adjacency-changes [detail] -- OSPF Command: no log-adjacency-changes [detail] Configures ospfd to log changes in adjacency. With the optional detail argument, all changes in adjacency status are shown. Without detail, only changes to full or regressions are shown. -- OSPF Command: passive-interface INTERFACE -- OSPF Command: no passive-interface INTERFACE Do not speak OSPF interface on the given interface, but do advertise the interface as a stub link in the router-LSA (Link State Advertisement) for this router. This allows one to advertise addresses on such connected interfaces without having to originate AS-External/Type-5 LSAs (which have global flooding scope) - as would occur if connected addresses were redistributed into OSPF (*note Redistribute routes to OSPF::). This is the only way to advertise non-OSPF links into stub areas. -- OSPF Command: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME -- OSPF Command: no timers throttle spf This command sets the initial DELAY, the INITIAL-HOLDTIME and the MAXIMUM-HOLDTIME between when SPF is calculated and the event which triggered the calculation. The times are specified in milliseconds and must be in the range of 0 to 600000 milliseconds. The DELAY specifies the minimum amount of time to delay SPF calculation (hence it affects how long SPF calculation is delayed after an event which occurs outside of the holdtime of any previous SPF calculation, and also serves as a minimum holdtime). Consecutive SPF calculations will always be seperated by at least 'hold-time' milliseconds. The hold-time is adaptive and initially is set to the INITIAL-HOLDTIME configured with the above command. Events which occur within the holdtime of the previous SPF calculation will cause the holdtime to be increased by INITIAL-HOLDTIME, bounded by the MAXIMUM-HOLDTIME configured with this command. If the adaptive hold-time elapses without any SPF-triggering event occuring then the current holdtime is reset to the INITIAL-HOLDTIME. The current holdtime can be viewed with *note show ip ospf::, where it is expressed as a multiplier of the INITIAL-HOLDTIME. router ospf timers throttle spf 200 400 10000 In this example, the DELAY is set to 200ms, the INITIAL HOLDTIME is set to 400ms and the MAXIMUM HOLDTIME to 10s. Hence there will always be at least 200ms between an event which requires SPF calculation and the actual SPF calculation. Further consecutive SPF calculations will always be seperated by between 400ms to 10s, the hold-time increasing by 400ms each time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. This command supercedes the 'timers spf' command in previous Quagga releases. -- OSPF Command: max-metric router-lsa [on-startup|on-shutdown] <5-86400> -- OSPF Command: max-metric router-lsa administrative -- OSPF Command: no max-metric router-lsa [on-startup|on-shutdown|administrative] This enables 'RFC3137, OSPF Stub Router Advertisement' support, where the OSPF process describes its transit links in its router-LSA as having infinite distance so that other routers will avoid calculating transit paths through the router while still being able to reach networks through the router. This support may be enabled administratively (and indefinitely) or conditionally. Conditional enabling of max-metric router-lsas can be for a period of seconds after startup and/or for a period of seconds prior to shutdown. Enabling this for a period after startup allows OSPF to converge fully first without affecting any existing routes used by other routers, while still allowing any connected stub links and/or redistributed routes to be reachable. Enabling this for a period of time in advance of shutdown allows the router to gracefully excuse itself from the OSPF domain. Enabling this feature administratively allows for administrative intervention for whatever reason, for an indefinite period of time. Note that if the configuration is written to file, this administrative form of the stub-router command will also be written to file. If 'ospfd' is restarted later, the command will then take effect until manually deconfigured. Configured state of this feature as well as current status, such as the number of second remaining till on-startup or on-shutdown ends, can be viewed with the *note show ip ospf:: command. -- OSPF Command: auto-cost reference-bandwidth <1-4294967> -- OSPF Command: no auto-cost reference-bandwidth This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain. -- OSPF Command: network A.B.C.D/M area A.B.C.D -- OSPF Command: network A.B.C.D/M area <0-4294967295> -- OSPF Command: no network A.B.C.D/M area A.B.C.D -- OSPF Command: no network A.B.C.D/M area <0-4294967295> This command specifies the OSPF enabled interface(s). If the interface has an address from range 192.168.1.0/24 then the command below enables ospf on this interface so router can provide network information to the other ospf routers via this interface. router ospf network 192.168.1.0/24 area 0.0.0.0 Prefix length in interface must be equal or bigger (ie. smaller network) than prefix length in network statement. For example statement above doesn't enable ospf on interface with address 192.168.1.1/23, but it does on interface with address 192.168.1.129/25. Note that the behavior when there is a peer address defined on an interface changed after release 0.99.7. Currently, if a peer prefix has been configured, then we test whether the prefix in the network command contains the destination prefix. Otherwise, we test whether the network command prefix contains the local address prefix of the interface. In some cases it may be more convenient to enable OSPF on a per interface/subnet basis (*note OSPF ip ospf area command::).  File: quagga.info, Node: OSPF area, Next: OSPF interface, Prev: OSPF router, Up: OSPFv2 7.4 OSPF area ============= -- OSPF Command: area A.B.C.D range A.B.C.D/M -- OSPF Command: area <0-4294967295> range A.B.C.D/M -- OSPF Command: no area A.B.C.D range A.B.C.D/M -- OSPF Command: no area <0-4294967295> range A.B.C.D/M Summarize intra area paths from specified area into one Type-3 summary-LSA announced to other areas. This command can be used only in ABR and ONLY router-LSAs (Type-1) and network-LSAs (Type-2) (ie. LSAs with scope area) can be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS. Summarizing Type-7 AS-external-LSAs isn't supported yet by Quagga. router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 range 10.0.0.0/8 With configuration above one Type-3 Summary-LSA with routing info 10.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (ie. described with router or network LSA) from this range. -- OSPF Command: area A.B.C.D range IPV4_PREFIX not-advertise -- OSPF Command: no area A.B.C.D range IPV4_PREFIX not-advertise Instead of summarizing intra area paths filter them - ie. intra area paths from this range are not advertised into other areas. This command makes sense in ABR only. -- OSPF Command: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX -- OSPF Command: no area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX Substitute summarized prefix with another prefix. router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 range 10.0.0.0/8 substitute 11.0.0.0/8 One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (ie. described with router-LSA or network-LSA) from range 10.0.0.0/8. This command makes sense in ABR only. -- OSPF Command: area A.B.C.D virtual-link A.B.C.D -- OSPF Command: area <0-4294967295> virtual-link A.B.C.D -- OSPF Command: no area A.B.C.D virtual-link A.B.C.D -- OSPF Command: no area <0-4294967295> virtual-link A.B.C.D -- OSPF Command: area A.B.C.D shortcut -- OSPF Command: area <0-4294967295> shortcut -- OSPF Command: no area A.B.C.D shortcut -- OSPF Command: no area <0-4294967295> shortcut Configure the area as Shortcut capable. See 'RFC3509'. This requires that the 'abr-type' be set to 'shortcut'. -- OSPF Command: area A.B.C.D stub -- OSPF Command: area <0-4294967295> stub -- OSPF Command: no area A.B.C.D stub -- OSPF Command: no area <0-4294967295> stub Configure the area to be a stub area. That is, an area where no router originates routes external to OSPF and hence an area where all external routes are via the ABR(s). Hence, ABRs for such an area do not need to pass AS-External LSAs (type-5s) or ASBR-Summary LSAs (type-4) into the area. They need only pass Network-Summary (type-3) LSAs into such an area, along with a default-route summary. -- OSPF Command: area A.B.C.D stub no-summary -- OSPF Command: area <0-4294967295> stub no-summary -- OSPF Command: no area A.B.C.D stub no-summary -- OSPF Command: no area <0-4294967295> stub no-summary Prevents an 'ospfd' ABR from injecting inter-area summaries into the specified stub area. -- OSPF Command: area A.B.C.D default-cost <0-16777215> -- OSPF Command: no area A.B.C.D default-cost <0-16777215> Set the cost of default-summary LSAs announced to stubby areas. -- OSPF Command: area A.B.C.D export-list NAME -- OSPF Command: area <0-4294967295> export-list NAME -- OSPF Command: no area A.B.C.D export-list NAME -- OSPF Command: no area <0-4294967295> export-list NAME Filter Type-3 summary-LSAs announced to other areas originated from intra- area paths from specified area. router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 export-list foo ! access-list foo permit 10.10.0.0/16 access-list foo deny any With example above any intra-area paths from area 0.0.0.10 and from range 10.10.0.0/16 (for example 10.10.1.0/24 and 10.10.2.128/30) are announced into other areas as Type-3 summary-LSA's, but any others (for example 10.11.0.0/16 or 10.128.30.16/30) aren't. This command is only relevant if the router is an ABR for the specified area. -- OSPF Command: area A.B.C.D import-list NAME -- OSPF Command: area <0-4294967295> import-list NAME -- OSPF Command: no area A.B.C.D import-list NAME -- OSPF Command: no area <0-4294967295> import-list NAME Same as export-list, but it applies to paths announced into specified area as Type-3 summary-LSAs. -- OSPF Command: area A.B.C.D filter-list prefix NAME in -- OSPF Command: area A.B.C.D filter-list prefix NAME out -- OSPF Command: area <0-4294967295> filter-list prefix NAME in -- OSPF Command: area <0-4294967295> filter-list prefix NAME out -- OSPF Command: no area A.B.C.D filter-list prefix NAME in -- OSPF Command: no area A.B.C.D filter-list prefix NAME out -- OSPF Command: no area <0-4294967295> filter-list prefix NAME in -- OSPF Command: no area <0-4294967295> filter-list prefix NAME out Filtering Type-3 summary-LSAs to/from area using prefix lists. This command makes sense in ABR only. -- OSPF Command: area A.B.C.D authentication -- OSPF Command: area <0-4294967295> authentication -- OSPF Command: no area A.B.C.D authentication -- OSPF Command: no area <0-4294967295> authentication Specify that simple password authentication should be used for the given area. -- OSPF Command: area A.B.C.D authentication message-digest -- OSPF Command: area <0-4294967295> authentication message-digest Specify that OSPF packets must be authenticated with MD5 HMACs within the given area. Keying material must also be configured on a per-interface basis (*note ip ospf message-digest-key::). MD5 authentication may also be configured on a per-interface basis (*note ip ospf authentication message-digest::). Such per-interface settings will override any per-area authentication setting.  File: quagga.info, Node: OSPF interface, Next: Redistribute routes to OSPF, Prev: OSPF area, Up: OSPFv2 7.5 OSPF interface ================== -- Interface Command: ip ospf area AREA [ADDR] -- Interface Command: no ip ospf area [ADDR] Enable OSPF on the interface, optionally restricted to just the IP address given by ADDR, putting it in the AREA area. Per interface area settings take precedence to network commands (*note OSPF network command::). If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF via this command may result in a slight performance improvement. -- Interface Command: ip ospf authentication-key AUTH_KEY -- Interface Command: no ip ospf authentication-key Set OSPF authentication key to a simple password. After setting AUTH_KEY, all OSPF packets are authenticated. AUTH_KEY has length up to 8 chars. Simple text password authentication is insecure and deprecated in favour of MD5 HMAC authentication (*note ip ospf authentication message-digest::). -- Interface Command: ip ospf authentication message-digest Specify that MD5 HMAC authentication must be used on this interface. MD5 keying material must also be configured (*note ip ospf message-digest-key::). Overrides any authentication enabled on a per-area basis (*note area authentication message-digest::). Note that OSPF MD5 authentication requires that time never go backwards (correct time is NOT important, only that it never goes backwards), even across resets, if ospfd is to be able to promptly reestabish adjacencies with its neighbours after restarts/reboots. The host should have system time be set at boot from an external or non-volatile source (eg battery backed clock, NTP, etc.) or else the system clock should be periodically saved to non-volative storage and restored at boot if MD5 authentication is to be expected to work reliably. -- Interface Command: ip ospf message-digest-key KEYID md5 KEY -- 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. This ID is part of the protocol and must be consistent across routers on a link. KEY is the actual message digest key, of up to 16 chars (larger strings will be truncated), and is associated with the given KEYID. -- Interface Command: ip ospf cost <1-65535> -- 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. -- Interface Command: ip ospf dead-interval <1-65535> -- Interface Command: ip ospf dead-interval minimal hello-multiplier <2-20> -- 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. If 'minimal' is specified instead, then the dead-interval is set to 1 second and one must specify a hello-multiplier. The hello-multiplier specifies how many Hellos to send per second, from 2 (every 500ms) to 20 (every 50ms). Thus one can have 1s convergence time for OSPF. If this form is specified, then the hello-interval advertised in Hello packets is set to 0 and the hello-interval on received Hello packets is not checked, thus the hello-multiplier need NOT be the same across multiple routers on a common link. -- Interface Command: ip ospf hello-interval <1-65535> -- 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. This command has no effect if *note ip ospf dead-interval minimal:: is also specified for the interface. -- Interface Command: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point) -- Interface Command: no ip ospf network Set explicitly network type for specifed interface. -- Interface Command: ip ospf priority <0-255> -- Interface Command: no ip ospf priority Set RouterPriority integer value. The router with the highest priority will be more eligible to become Designated Router. Setting the value to 0, makes the router ineligible to become Designated Router. The default value is 1. -- Interface Command: ip ospf retransmit-interval <1-65535> -- 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. -- Interface Command: ip ospf transmit-delay -- 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.  File: quagga.info, Node: Redistribute routes to OSPF, Next: Showing OSPF information, Prev: OSPF interface, Up: OSPFv2 7.6 Redistribute routes to OSPF =============================== -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) ROUTE-MAP -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD -- OSPF Command: no redistribute (kernel|connected|static|rip|bgp) Redistribute routes of the specified protocol or kind into OSPF, with the metric type and metric set if specified, filtering the routes using the given route-map if specified. Redistributed routes may also be filtered with distribute-lists, see *note ospf distribute-list::. Redistributed routes are distributed as into OSPF as Type-5 External LSAs into links to areas that accept external routes, Type-7 External LSAs for NSSA areas and are not redistributed at all into Stub areas, where external routes are not permitted. Note that for connected routes, one may instead use "passive-interface", see *note OSPF passive-interface::. -- OSPF Command: default-information originate -- OSPF Command: default-information originate metric <0-16777214> -- OSPF Command: default-information originate metric <0-16777214> metric-type (1|2) -- OSPF Command: default-information originate metric <0-16777214> metric-type (1|2) route-map WORD -- OSPF Command: default-information originate always -- OSPF Command: default-information originate always metric <0-16777214> -- OSPF Command: default-information originate always metric <0-16777214> metric-type (1|2) -- OSPF Command: default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD -- OSPF Command: no default-information originate Originate an AS-External (type-5) LSA describing a default route into all external-routing capable areas, of the specified metric and metric type. If the 'always' keyword is given then the default is always advertised, even when there is no default present in the routing table. -- OSPF Command: distribute-list NAME out (kernel|connected|static|rip|ospf -- OSPF Command: no distribute-list NAME out (kernel|connected|static|rip|ospf Apply the access-list filter, NAME, to redistributed routes of the given type before allowing the routes to redistributed into OSPF (*note OSPF redistribute::). -- OSPF Command: default-metric <0-16777214> -- OSPF Command: no default-metric -- OSPF Command: distance <1-255> -- OSPF Command: no distance <1-255> -- OSPF Command: distance ospf (intra-area|inter-area|external) <1-255> -- OSPF Command: no distance ospf  File: quagga.info, Node: Showing OSPF information, Next: Opaque LSA, Prev: Redistribute routes to OSPF, Up: OSPFv2 7.7 Showing OSPF information ============================ -- Command: show ip ospf Show information on a variety of general OSPF and area state and configuration information. -- Command: show ip ospf interface [INTERFACE] Show state and configuration of OSPF the specified interface, or all interfaces if no interface is given. -- Command: show ip ospf neighbor -- Command: show ip ospf neighbor INTERFACE -- Command: show ip ospf neighbor detail -- Command: show ip ospf neighbor INTERFACE detail -- Command: show ip ospf database -- Command: show ip ospf database asbr-summary -- Command: show ip ospf database external -- Command: show ip ospf database network -- Command: show ip ospf database asbr-router -- Command: show ip ospf database summary -- Command: show ip ospf database ... LINK-STATE-ID -- Command: show ip ospf database ... LINK-STATE-ID adv-router ADV-ROUTER -- Command: show ip ospf database ... adv-router ADV-ROUTER -- Command: show ip ospf database ... LINK-STATE-ID self-originate -- Command: show ip ospf database ... self-originate -- Command: show ip ospf database max-age -- Command: show ip ospf database self-originate -- Command: show ip ospf route Show the OSPF routing table, as determined by the most recent SPF calculation.  File: quagga.info, Node: Opaque LSA, Next: OSPF Traffic Engineering, Prev: Showing OSPF information, Up: OSPFv2 7.8 Opaque LSA ============== -- OSPF Command: ospf opaque-lsa -- OSPF Command: capability opaque -- OSPF Command: no ospf opaque-lsa -- OSPF Command: no capability opaque 'ospfd' support Opaque LSA (RFC2370) as fondment for MPLS Traffic Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the configuration file. Alternate command could be "mpls-te on" (*note OSPF Traffic Engineering::). -- Command: show ip ospf database (opaque-link|opaque-area|opaque-external) -- Command: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID -- Command: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER -- Command: show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER -- Command: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate -- Command: show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate Show Opaque LSA from the database.  File: quagga.info, Node: OSPF Traffic Engineering, Next: Router Information, Prev: Opaque LSA, Up: OSPFv2 7.9 Traffic Engineering ======================= -- OSPF Command: mpls-te on -- OSPF Command: no mpls-te Enable Traffic Engineering LSA flooding. -- OSPF Command: mpls-te router-address -- OSPF Command: no mpls-te Configure stable IP address for MPLS-TE. This IP address is then advertise in Opaque LSA Type-10 TLV=1 (TE) option 1 (Router-Address). -- OSPF Command: mpls-te inter-as area |as -- OSPF Command: no mpls-te inter-as Enable RFC5392 suuport - Inter-AS TE v2 - to flood Traffic Engineering parameters of Inter-AS link. 2 modes are supported: AREA and AS; LSA are flood in AREA with Opaque Type-10, respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6. -- Command: show ip ospf mpls-te interface -- Command: show ip ospf mpls-te interface INTERFACE Show MPLS Traffic Engineering parameters for all or specified interface. -- Command: show ip ospf mpls-te router Show Traffic Engineering router parameters.  File: quagga.info, Node: Router Information, Next: Debugging OSPF, Prev: OSPF Traffic Engineering, Up: OSPFv2 7.10 Router Information ======================= -- OSPF Command: router-info [as | area ] -- OSPF Command: no router-info Enable Router Information (RFC4970) LSA advertisement with AS scope (default) or Area scope flooding when area is specified. -- OSPF Command: pce address -- OSPF Command: no pce address -- OSPF Command: pce domain as <0-65535> -- OSPF Command: no pce domain as <0-65535> -- OSPF Command: pce neighbor as <0-65535> -- OSPF Command: no pce neighbor as <0-65535> -- OSPF Command: pce flag BITPATTERN -- OSPF Command: no pce flag -- OSPF Command: pce scope BITPATTERN -- OSPF Command: no pce scope The commands are conform to RFC 5088 and allow OSPF router announce Path Compuatation Elemenent (PCE) capabilities through the Router Information (RI) LSA. Router Information must be enable prior to this. The command set/unset respectively the PCE IP adress, Autonomous System (AS) numbers of controlled domains, neighbor ASs, flag and scope. For flag and scope, please refer to RFC5088 for the BITPATTERN recognition. Multiple 'pce neighbor' command could be specified in order to specify all PCE neighbours. -- Command: show ip ospf router-info Show Router Capabilities flag. -- Command: show ip ospf router-info pce Show Router Capabilities PCE parameters.  File: quagga.info, Node: Debugging OSPF, Next: OSPF Configuration Examples, Prev: Router Information, Up: OSPFv2 7.11 Debugging OSPF =================== -- Command: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] -- Command: no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] Dump Packet for debugging -- Command: debug ospf ism -- Command: debug ospf ism (status|events|timers) -- Command: no debug ospf ism -- Command: no debug ospf ism (status|events|timers) Show debug information of Interface State Machine -- Command: debug ospf nsm -- Command: debug ospf nsm (status|events|timers) -- Command: no debug ospf nsm -- Command: no debug ospf nsm (status|events|timers) Show debug information of Network State Machine -- Command: debug ospf event -- Command: no debug ospf event Show debug information of OSPF event -- Command: debug ospf nssa -- Command: no debug ospf nssa Show debug information about Not So Stub Area -- Command: debug ospf lsa -- Command: debug ospf lsa (generate|flooding|refresh) -- Command: no debug ospf lsa -- Command: no debug ospf lsa (generate|flooding|refresh) Show debug detail of Link State messages -- Command: debug ospf te -- Command: no debug ospf te Show debug information about Traffic Engineering LSA -- Command: debug ospf zebra -- Command: debug ospf zebra (interface|redistribute) -- Command: no debug ospf zebra -- Command: no debug ospf zebra (interface|redistribute) Show debug information of ZEBRA API -- Command: show debugging ospf  File: quagga.info, Node: OSPF Configuration Examples, Prev: Debugging OSPF, Up: OSPFv2 7.12 OSPF Configuration Examples ================================ A simple example, with MD5 authentication enabled: ! interface bge0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 ABCDEFGHIJK ! router ospf network 192.168.0.0/16 area 0.0.0.1 area 0.0.0.1 authentication message-digest An ABR router, with MD5 authentication and performing summarisation of networks between the areas: ! password ABCDEF log file /var/log/quagga/ospfd.log service advanced-vty ! interface eth0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 ABCDEFGHIJK ! interface ppp0 ! interface br0 ip ospf authentication message-digest ip ospf message-digest-key 2 md5 XYZ12345 ! router ospf ospf router-id 192.168.0.1 redistribute connected passive interface ppp0 network 192.168.0.0/24 area 0.0.0.0 network 10.0.0.0/16 area 0.0.0.0 network 192.168.1.0/24 area 0.0.0.1 area 0.0.0.0 authentication message-digest area 0.0.0.0 range 10.0.0.0/16 area 0.0.0.0 range 192.168.0.0/24 area 0.0.0.1 authentication message-digest area 0.0.0.1 range 10.2.0.0/16 ! A Traffic Engineering configuration, with Inter-ASv2 support. - First, the 'zebra.conf' part: hostname HOSTNAME password PASSWORD log file /var/log/zebra.log ! interface eth0 ip address 198.168.1.1/24 mpls-te on mpls-te link metric 10 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab ! interface eth1 ip address 192.168.2.1/24 mpls-te on mpls-te link metric 10 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab mpls-te neighbor 192.168.2.2 as 65000 - Then the 'ospfd.conf' itself: hostname HOSTNAME password PASSWORD log file /var/log/ospfd.log ! ! interface eth0 ip ospf hello-interval 60 ip ospf dead-interval 240 ! interface eth1 ip ospf hello-interval 60 ip ospf dead-interval 240 ! ! router ospf ospf router-id 192.168.1.1 network 192.168.0.0/16 area 1 ospf opaque-lsa mpls-te mpls-te router-address 192.168.1.1 mpls-te inter-as area 1 ! line vty A router information example with PCE advsertisement: ! router ospf ospf router-id 192.168.1.1 network 192.168.0.0/16 area 1 capability opaque mpls-te mpls-te router-address 192.168.1.1 router-info area 0.0.0.1 pce address 192.168.1.1 pce flag 0x80 pce domain as 65400 pce neighbor as 65500 pce neighbor as 65200 pce scope 0x80 !  File: quagga.info, Node: OSPFv3, Next: ISIS, Prev: OSPFv2, Up: Top 8 OSPFv3 ******** '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:: * OSPF6 Configuration Examples::  File: quagga.info, Node: OSPF6 router, Next: OSPF6 area, Up: OSPFv3 8.1 OSPF6 router ================ -- Command: router ospf6 -- OSPF6 Command: router-id A.B.C.D Set router's Router-ID. -- OSPF6 Command: interface IFNAME area AREA Bind interface to specified area, and start sending OSPF packets. AREA can be specified as 0. -- OSPF6 Command: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME -- OSPF6 Command: no timers throttle spf This command sets the initial DELAY, the INITIAL-HOLDTIME and the MAXIMUM-HOLDTIME between when SPF is calculated and the event which triggered the calculation. The times are specified in milliseconds and must be in the range of 0 to 600000 milliseconds. The DELAY specifies the minimum amount of time to delay SPF calculation (hence it affects how long SPF calculation is delayed after an event which occurs outside of the holdtime of any previous SPF calculation, and also serves as a minimum holdtime). Consecutive SPF calculations will always be seperated by at least 'hold-time' milliseconds. The hold-time is adaptive and initially is set to the INITIAL-HOLDTIME configured with the above command. Events which occur within the holdtime of the previous SPF calculation will cause the holdtime to be increased by INITIAL-HOLDTIME, bounded by the MAXIMUM-HOLDTIME configured with this command. If the adaptive hold-time elapses without any SPF-triggering event occuring then the current holdtime is reset to the INITIAL-HOLDTIME. router ospf6 timers throttle spf 200 400 10000 In this example, the DELAY is set to 200ms, the INITIAL HOLDTIME is set to 400ms and the MAXIMUM HOLDTIME to 10s. Hence there will always be at least 200ms between an event which requires SPF calculation and the actual SPF calculation. Further consecutive SPF calculations will always be seperated by between 400ms to 10s, the hold-time increasing by 400ms each time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. -- OSPF6 Command: auto-cost reference-bandwidth COST -- OSPF6 Command: no auto-cost reference-bandwidth This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain.  File: quagga.info, Node: OSPF6 area, Next: OSPF6 interface, Prev: OSPF6 router, Up: OSPFv3 8.2 OSPF6 area ============== Area support for OSPFv3 is not yet implemented.  File: quagga.info, Node: OSPF6 interface, Next: Redistribute routes to OSPF6, Prev: OSPF6 area, Up: OSPFv3 8.3 OSPF6 interface =================== -- Interface Command: ipv6 ospf6 cost COST Sets interface's output cost. Default value depends on the interface bandwidth and on the auto-cost reference bandwidth. -- Interface Command: ipv6 ospf6 hello-interval HELLOINTERVAL Sets interface's Hello Interval. Default 40 -- Interface Command: ipv6 ospf6 dead-interval DEADINTERVAL Sets interface's Router Dead Interval. Default value is 40. -- Interface Command: ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL Sets interface's Rxmt Interval. Default value is 5. -- Interface Command: ipv6 ospf6 priority PRIORITY Sets interface's Router Priority. Default value is 1. -- Interface Command: ipv6 ospf6 transmit-delay TRANSMITDELAY Sets interface's Inf-Trans-Delay. Default value is 1. -- Interface Command: ipv6 ospf6 network (broadcast|point-to-point) Set explicitly network type for specifed interface.  File: quagga.info, Node: Redistribute routes to OSPF6, Next: Showing OSPF6 information, Prev: OSPF6 interface, Up: OSPFv3 8.4 Redistribute routes to OSPF6 ================================ -- OSPF6 Command: redistribute static -- OSPF6 Command: redistribute connected -- OSPF6 Command: redistribute ripng  File: quagga.info, Node: Showing OSPF6 information, Next: OSPF6 Configuration Examples, Prev: Redistribute routes to OSPF6, Up: OSPFv3 8.5 Showing OSPF6 information ============================= -- 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 ". -- Command: show ipv6 ospf6 database This command shows LSA database summary. You can specify the type of LSA. -- Command: show ipv6 ospf6 interface To see OSPF interface configuration like costs. -- Command: show ipv6 ospf6 neighbor Shows state and chosen (Backup) DR of neighbor. -- Command: show ipv6 ospf6 request-list A.B.C.D Shows requestlist of neighbor. -- Command: show ipv6 route ospf6 This command shows internal routing table.  File: quagga.info, Node: OSPF6 Configuration Examples, Prev: Showing OSPF6 information, Up: OSPFv3 8.6 OSPF6 Configuration Examples ================================ Example of ospf6d configured on one interface and area: interface eth0 ipv6 ospf6 instance-id 0 ! router ospf6 router-id 212.17.55.53 area 0.0.0.0 range 2001:770:105:2::/64 interface eth0 area 0.0.0.0 !  File: quagga.info, Node: ISIS, Next: NHRP, Prev: OSPFv3, Up: Top 9 ISIS ****** ISIS (Intermediate System to Intermediate System) is a routing protocol which is described in 'ISO10589, RFC1195, RFC5308'. ISIS is an IGP (Interior Gateway Protocol). Compared with RIP, ISIS can provide scalable network support and faster convergence times like OSPF. ISIS is widely used in large networks such as ISP (Internet Service Provider) and carrier backbone networks. * Menu: * Configuring isisd:: * ISIS router:: * ISIS Timer:: * ISIS region:: * ISIS interface:: * Showing ISIS information:: * ISIS Traffic Engineering:: * Debugging ISIS:: * ISIS Configuration Examples::  File: quagga.info, Node: Configuring isisd, Next: ISIS router, Up: ISIS 9.1 Configuring isisd ===================== There are no 'isisd' specific options. Common options can be specified (*note Common Invocation Options::) to 'isisd'. 'isisd' needs to acquire interface information from 'zebra' in order to function. Therefore 'zebra' must be running before invoking 'isisd'. Also, if 'zebra' is restarted then 'isisd' must be too. Like other daemons, 'isisd' configuration is done in ISIS specific configuration file 'isisd.conf'.  File: quagga.info, Node: ISIS router, Next: ISIS Timer, Prev: Configuring isisd, Up: ISIS 9.2 ISIS router =============== To start ISIS process you have to specify the ISIS router. As of this writing, 'isisd' does not support multiple ISIS processes. -- Command: router isis WORD -- Command: no router isis WORD Enable or disable the ISIS process by specifying the ISIS domain with 'WORD'. 'isisd' does not yet support multiple ISIS processes but you must specify the name of ISIS process. The ISIS process name 'WORD' is then used for interface (see command *note ip router isis WORD::). -- ISIS Command: net XX.XXXX. ... .XXX.XX -- ISIS Command: no net XX.XXXX. ... .XXX.XX Set/Unset network entity title (NET) provided in ISO format. -- ISIS Command: hostname dynamic -- ISIS Command: no hostname dynamic Enable support for dynamic hostname. -- ISIS Command: area-password [clear | md5] -- ISIS Command: domain-password [clear | md5] -- ISIS Command: no area-password -- ISIS Command: no domain-password Configure the authentication password for an area, respectively a domain, as clear text or md5 one. -- ISIS Command: log-adjacency-changes -- ISIS Command: no log-adjacency-changes Log changes in adjacency state. -- ISIS Command: metric-style [narrow | transition | wide] -- ISIS Command: no metric-style Set old-style (ISO 10589) or new-style packet formats: - narrow Use old style of TLVs with narrow metric - transition Send and accept both styles of TLVs during transition - wide Use new style of TLVs to carry wider metric -- ISIS Command: set-overload-bit -- ISIS Command: no set-overload-bit Set overload bit to avoid any transit traffic.  File: quagga.info, Node: ISIS Timer, Next: ISIS region, Prev: ISIS router, Up: ISIS 9.3 ISIS Timer ============== -- ISIS Command: lsp-gen-interval <1-120> -- ISIS Command: lsp-gen-interval [level-1 | level-2] <1-120> -- ISIS Command: no lsp-gen-interval -- ISIS Command: no lsp-gen-interval [level-1 | level-2] Set minimum interval in seconds between regenerating same LSP, globally, for an area (level-1) or a domain (level-2). -- ISIS Command: lsp-refresh-interval <1-65235> -- ISIS Command: lsp-refresh-interval [level-1 | level-2] <1-65235> -- ISIS Command: no lsp-refresh-interval -- ISIS Command: no lsp-refresh-interval [level-1 | level-2] Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). -- ISIS Command: lsp-refresh-interval <1-65235> -- ISIS Command: lsp-refresh-interval [level-1 | level-2] <1-65235> -- ISIS Command: no lsp-refresh-interval -- ISIS Command: no lsp-refresh-interval [level-1 | level-2] Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). -- ISIS Command: max-lsp-lifetime <360-65535> -- ISIS Command: max-lsp-lifetime [level-1 | level-2] <360-65535> -- ISIS Command: no max-lsp-lifetime -- ISIS Command: no max-lsp-lifetime [level-1 | level-2] Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or a domain (level-2). -- ISIS Command: spf-interval <1-120> -- ISIS Command: spf-interval [level-1 | level-2] <1-120> -- ISIS Command: no spf-interval -- ISIS Command: no spf-interval [level-1 | level-2] Set minimum interval between consecutive SPF calculations in seconds.  File: quagga.info, Node: ISIS region, Next: ISIS interface, Prev: ISIS Timer, Up: ISIS 9.4 ISIS region =============== -- ISIS Command: is-type [level-1 | level-1-2 | level-2-only] -- ISIS Command: no is-type Define the ISIS router behavior: - level-1 Act as a station router only - level-1-2 Act as both a station router and an area router - level-2-only Act as an area router only  File: quagga.info, Node: ISIS interface, Next: Showing ISIS information, Prev: ISIS region, Up: ISIS 9.5 ISIS interface ================== -- Interface Command: ip router isis WORD -- Interface Command: no ip router isis WORD Activate ISIS adjacency on this interface. Note that the name of ISIS instance must be the same as the one used to configure the ISIS process (see command *note router isis WORD::). -- Interface Command: isis circuit-type [level-1 | level-1-2 | level-2] -- Interface Command: no isis circuit-type Configure circuit type for interface: - level-1 Level-1 only adjacencies are formed - level-1-2 Level-1-2 adjacencies are formed - level-2-only Level-2 only adjacencies are formed -- Interface Command: isis csnp-interval <1-600> -- Interface Command: isis csnp-interval <1-600> [level-1 | level-2] -- Interface Command: no isis csnp-interval -- Interface Command: no isis csnp-interval [level-1 | level-2] Set CSNP interval in seconds globally, for an area (level-1) or a domain (level-2). -- Interface Command: isis hello padding Add padding to IS-IS hello packets. -- Interface Command: isis hello-interval <1-600> -- Interface Command: isis hello-interval <1-600> [level-1 | level-2] -- Interface Command: no isis hello-interval -- Interface Command: no isis hello-interval [level-1 | level-2] Set Hello interval in seconds globally, for an area (level-1) or a domain (level-2). -- Interface Command: isis hello-multiplier <2-100> -- Interface Command: isis hello-multiplier <2-100> [level-1 | level-2] -- Interface Command: no isis hello-multiplier -- Interface Command: no isis hello-multiplier [level-1 | level-2] Set multiplier for Hello holding time globally, for an area (level-1) or a domain (level-2). -- Interface Command: isis metric [<0-255> | <0-16777215>] -- Interface Command: isis metric [<0-255> | <0-16777215>] [level-1 | level-2] -- Interface Command: no isis metric -- Interface Command: no isis metric [level-1 | level-2] Set default metric value globally, for an area (level-1) or a domain (level-2). Max value depend if metric support narrow or wide value (see command *note metric-style::). -- Interface Command: isis network point-to-point -- Interface Command: no isis network point-to-point Set network type to 'Point-to-Point' (broadcast by default). -- Interface Command: isis passive -- Interface Command: no isis passive Configure the passive mode for this interface. -- Interface Command: isis password [clear | md5] -- Interface Command: no isis password Configure the authentication password (clear or encoded text) for the interface. -- Interface Command: isis priority <0-127> -- Interface Command: isis priority <0-127> [level-1 | level-2] -- Interface Command: no isis priority -- Interface Command: no isis priority [level-1 | level-2] Set priority for Designated Router election, globally, for the area (level-1) or the domain (level-2). -- Interface Command: isis psnp-interval <1-120> -- Interface Command: isis psnp-interval <1-120> [level-1 | level-2] -- Interface Command: no isis psnp-interval -- Interface Command: no isis psnp-interval [level-1 | level-2] Set PSNP interval in seconds globally, for an area (level-1) or a domain (level-2).  File: quagga.info, Node: Showing ISIS information, Next: ISIS Traffic Engineering, Prev: ISIS interface, Up: ISIS 9.6 Showing ISIS information ============================ -- Command: show isis summary Show summary information about ISIS. -- Command: show isis hostname Show information about ISIS node. -- Command: show isis interface -- Command: show isis interface detail -- Command: show isis interface Show state and configuration of ISIS specified interface, or all interfaces if no interface is given with or without details. -- Command: show isis neighbor -- Command: show isis neighbor -- Command: show isis neighbor detail Show state and information of ISIS specified neighbor, or all neighbors if no system id is given with or without details. -- Command: show isis database -- Command: show isis database [detail] -- Command: show isis database [detail] -- Command: show isis database detail Show the ISIS database globally, for a specific LSP id without or with details. -- Command: show isis topology -- Command: show isis topology [level-1|level-2] Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). -- Command: show ip route isis Show the ISIS routing table, as determined by the most recent SPF calculation.  File: quagga.info, Node: ISIS Traffic Engineering, Next: Debugging ISIS, Prev: Showing ISIS information, Up: ISIS 9.7 Traffic Engineering ======================= -- ISIS Command: mpls-te on -- ISIS Command: no mpls-te Enable Traffic Engineering LSP flooding. -- ISIS Command: mpls-te router-address -- ISIS Command: no mpls-te router-address Configure stable IP address for MPLS-TE. -- Command: show isis mpls-te interface -- Command: show isis mpls-te interface INTERFACE Show MPLS Traffic Engineering parameters for all or specified interface. -- Command: show isis mpls-te router Show Traffic Engineering router parameters.  File: quagga.info, Node: Debugging ISIS, Next: ISIS Configuration Examples, Prev: ISIS Traffic Engineering, Up: ISIS 9.8 Debugging ISIS ================== -- Command: debug isis adj-packets -- Command: no debug isis adj-packets IS-IS Adjacency related packets. -- Command: debug isis checksum-errors -- Command: no debug isis checksum-errors IS-IS LSP checksum errors. -- Command: debug isis events -- Command: no debug isis events IS-IS Events. -- Command: debug isis local-updates -- Command: no debug isis local-updates IS-IS local update packets. -- Command: debug isis packet-dump -- Command: no debug isis packet-dump IS-IS packet dump. -- Command: debug isis protocol-errors -- Command: no debug isis protocol-errors IS-IS LSP protocol errors. -- Command: debug isis route-events -- Command: no debug isis route-events IS-IS Route related events. -- Command: debug isis snp-packets -- Command: no debug isis snp-packets IS-IS CSNP/PSNP packets. -- Command: debug isis spf-events -- Command: debug isis spf-statistics -- Command: debug isis spf-triggers -- Command: no debug isis spf-events -- Command: no debug isis spf-statistics -- Command: no debug isis spf-triggers IS-IS Shortest Path First Events, Timing and Statistic Data and triggering events. -- Command: debug isis update-packets -- Command: no debug isis update-packets Update related packets. -- Command: show debugging isis Print which ISIS debug level is activate.  File: quagga.info, Node: ISIS Configuration Examples, Prev: Debugging ISIS, Up: ISIS 9.9 ISIS Configuration Examples =============================== A simple example, with MD5 authentication enabled: ! interface eth0 ip router isis FOO isis network point-to-point isis circuit-type level-2-only ! router isis FOO net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 metric-style wide is-type level-2-only A Traffic Engineering configuration, with Inter-ASv2 support. - First, the 'zebra.conf' part: hostname HOSTNAME password PASSWORD log file /var/log/zebra.log ! interface eth0 ip address 10.2.2.2/24 mpls-te on mpls-te link metric 10 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab ! interface eth1 ip address 10.1.1.1/24 mpls-te on mpls-te link metric 10 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab mpls-te neighbor 10.1.1.2 as 65000 - Then the 'isisd.conf' itself: hostname HOSTNAME password PASSWORD log file /var/log/isisd.log ! ! interface eth0 ip router isis FOO ! interface eth1 ip router isis FOO ! ! router isis FOO isis net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 mpls-te on mpls-te router-address 10.1.1.1 ! line vty  File: quagga.info, Node: NHRP, Next: BGP, Prev: ISIS, Up: Top 10 NHRP ******* 'nhrpd' is a daemon to support Next Hop Routing Protocol (NHRP). NHRP is described in RFC2332. NHRP is used to improve the efficiency of routing computer network traffic over Non-Broadcast, Multiple Access (NBMA) Networks. NHRP provides an ARP-like solution that allows a system to dynamically learn the NBMA address of the other systems that are part of that network, allowing these systems to directly communicate without requiring traffic to use an intermediate hop. Cisco Dynamic Multipoint VPN (DMVPN) is based on NHRP, and Quagga nrhpd implements this scenario. * Menu: * Routing Design:: * Configuring NHRP:: * Hub Functionality:: * Integration with IKE:: * NHRP Events:: * Configuration Example::  File: quagga.info, Node: Routing Design, Next: Configuring NHRP, Up: NHRP 10.1 Routing Design =================== nhrpd never handles routing of prefixes itself. You need to run some real routing protocol (e.g. BGP) to advertise routes over the tunnels. What nhrpd does it establishes 'shortcut routes' that optimizes the routing protocol to avoid going through extra nodes in NBMA GRE mesh. nhrpd does route NHRP domain addresses individually using per-host prefixes. This is similar to Cisco FlexVPN; but in contrast to opennhrp which uses a generic subnet route. To create NBMA GRE tunnel you might use the following (linux terminal commands): ip tunnel add gre1 mode gre key 42 ttl 64 ip addr add 10.255.255.2/32 dev gre1 ip link set gre1 up Note that the IP-address is assigned as host prefix to gre1. nhrpd will automatically create additional host routes pointing to gre1 when a connection with these hosts is established. The gre1 subnet prefix should be announced by routing protocol from the hub nodes (e.g. BGP 'network' announce). This allows the routing protocol to decide which is the closest hub and determine the relay hub on prefix basis when direct tunnel is not established. nhrpd will redistribute directly connected neighbors to zebra. Within hub nodes, these routes should be internally redistributed using some routing protocol (e.g. iBGP) to allow hubs to be able to relay all traffic. This can be achieved in hubs with the following bgp configuration (network command defines the GRE subnet): router bgp 65555 network 172.16.0.0/16 redistribute nhrp  File: quagga.info, Node: Configuring NHRP, Next: Hub Functionality, Prev: Routing Design, Up: NHRP 10.2 Configuring NHRP ===================== FIXME  File: quagga.info, Node: Hub Functionality, Next: Integration with IKE, Prev: Configuring NHRP, Up: NHRP 10.3 Hub Functionality ====================== In addition to routing nhrp redistributed host prefixes, the hub nodes are also responsible to send NHRP Traffic Indication messages that trigger creation of the shortcut tunnels. nhrpd sends Traffic Indication messages based on network traffic captured using NFLOG. Typically you want to send Traffic Indications for network traffic that is routed from gre1 back to gre1 in rate limited manner. This can be achieved with the following iptables rule. iptables -A FORWARD -i gre1 -o gre1 \ -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \ --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 \ --hashlimit-dstmask 24 --hashlimit-name loglimit-0 \ -j NFLOG --nflog-group 1 --nflog-range 128 You can fine tune the src/dstmask according to the prefix lengths you announce internal, add additional IP range matches, or rate limitation if needed. However, the above should be good in most cases. This kernel NFLOG target's nflog-group is configured in global nhrp config with: nhrp nflog-group 1 To start sending these traffic notices out from hubs, use the nhrp per-interface directive: interface gre1 ip nhrp redirect  File: quagga.info, Node: Integration with IKE, Next: NHRP Events, Prev: Hub Functionality, Up: NHRP 10.4 Integration with IKE ========================= nhrpd needs tight integration with IKE daemon for various reasons. Currently only strongSwan is supported as IKE daemon. nhrpd connects to strongSwan using VICI protocol based on UNIX socket (hardcoded now as /var/run/charon.vici). strongSwan currently needs few patches applied. Please check out the release (http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras-release) and working tree (http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras) git repositories for the patches.  File: quagga.info, Node: NHRP Events, Next: Configuration Example, Prev: Integration with IKE, Up: NHRP 10.5 NHRP Events ================ FIXME  File: quagga.info, Node: Configuration Example, Prev: NHRP Events, Up: NHRP 10.6 Configuration Example ========================== FIXME  File: quagga.info, Node: BGP, Next: Configuring Quagga as a Route Server, Prev: NHRP, Up: Top 11 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 'RFC1771, A Border Gateway Protocol 4 (BGP-4)'. Many extensions have been added to 'RFC1771'. 'RFC2858, Multiprotocol Extensions for BGP-4' provides multiprotocol support to BGP-4. * Menu: * Starting BGP:: * BGP router:: * BGP MED:: * 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:: * BGP Configuration Examples::  File: quagga.info, Node: Starting BGP, Next: BGP router, Up: BGP 11.1 Starting BGP ================= Default configuration file of 'bgpd' is 'bgpd.conf'. 'bgpd' searches the current directory first then /etc/quagga/bgpd.conf. All of bgpd's command must be configured in 'bgpd.conf'. 'bgpd' specific invocation options are described below. Common options may also be specified (*note Common Invocation Options::). '-p PORT' '--bgp_port=PORT' Set the bgp protocol's port number. '-r' '--retain' When program terminates, retain BGP routes added by zebra. '-l' '--listenon' Specify a specific IP address for bgpd to listen on, rather than its default of INADDR_ANY / IN6ADDR_ANY. This can be useful to constrain bgpd to an internal address, or to run multiple bgpd processes on one host.  File: quagga.info, Node: BGP router, Next: BGP MED, Prev: Starting BGP, Up: BGP 11.2 BGP router =============== First of all you must configure BGP router with '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. -- Command: router bgp ASN Enable a BGP protocol process with the specified ASN. After this statement you can input any 'BGP Commands'. You can not create different BGP process under different ASN without specifying 'multiple-instance' (*note Multiple instance::). -- Command: no router bgp ASN Destroy a BGP protocol process with the specified ASN. -- BGP: bgp router-id A.B.C.D This command specifies the router-ID. If 'bgpd' connects to '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 'router zebra' is not enabled 'bgpd' can't get interface information so 'router-id' is set to 0.0.0.0. So please set router-id by hand. * Menu: * BGP distance:: * BGP decision process:: * BGP route flap dampening::  File: quagga.info, Node: BGP distance, Next: BGP decision process, Up: BGP router 11.2.1 BGP distance ------------------- -- 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. To have this command applied to existing routes requires a hard clear. -- BGP: distance <1-255> A.B.C.D/M -- BGP: distance <1-255> A.B.C.D/M WORD This command set distance value to  File: quagga.info, Node: BGP decision process, Next: BGP route flap dampening, Prev: BGP distance, Up: BGP router 11.2.2 BGP decision process --------------------------- The decision process Quagga BGP uses to select routes is as follows: 1. Weight check prefer higher local weight routes to lower routes. 2. Local preference check prefer higher local preference routes to lower. 3. Local route check Prefer local routes (statics, aggregates, redistributed) to received routes. 4. AS path length check Prefer shortest hop-count AS_PATHs. 5. Origin check Prefer the lowest origin type route. That is, prefer IGP origin routes to EGP, to Incomplete routes. 6. MED check Where routes with a MED were received from the same AS, prefer the route with the lowest MED. *Note BGP MED::. 7. External check Prefer the route received from an external, eBGP peer over routes received from other types of peers. 8. IGP cost check Prefer the route with the lower IGP cost. 9. Multi-path check If multi-pathing is enabled, then check whether the routes not yet distinguished in preference may be considered equal. If *note bgp bestpath as-path multipath-relax:: is set, all such routes are considered equal, otherwise routes received via iBGP with identical AS_PATHs or routes received from eBGP neighbours in the same AS are considered equal. 10 Already-selected external check Where both routes were received from eBGP peers, then prefer the route which is already selected. Note that this check is not applied if *note bgp bestpath compare-routerid:: is configured. This check can prevent some cases of oscillation. 11. Router-ID check Prefer the route with the lowest router-ID. If the route has an ORIGINATOR_ID attribute, through iBGP reflection, then that router ID is used, otherwise the router-ID of the peer the route was received from is used. 12. Cluster-List length check The route with the shortest cluster-list length is used. The cluster-list reflects the iBGP reflection path the route has taken. 13. Peer address Prefer the route received from the peer with the higher transport layer address, as a last-resort tie-breaker. -- BGP: bgp bestpath as-path confed This command specifies that the length of confederation path sets and sequences should should be taken into account during the BGP best path decision process. -- BGP: bgp bestpath as-path multipath-relax This command specifies that BGP decision process should consider paths of equal AS_PATH length candidates for multipath computation. Without the knob, the entire AS_PATH must match for multipath computation. -- BGP: bgp bestpath compare-routerid Ensure that when comparing routes where both are equal on most metrics, including local-pref, AS_PATH length, IGP cost, MED, that the tie is broken based on router-ID. If this option is enabled, then the already-selected check, where already selected eBGP routes are preferred, is skipped. If a route has an ORIGINATOR_ID attribute because it has been reflected, that ORIGINATOR_ID will be used. Otherwise, the router-ID of the peer the route was received from will be used. The advantage of this is that the route-selection (at this point) will be more deterministic. The disadvantage is that a few or even one lowest-ID router may attract all trafic to otherwise-equal paths because of this check. It may increase the possibility of MED or IGP oscillation, unless other measures were taken to avoid these. The exact behaviour will be sensitive to the iBGP and reflection topology.  File: quagga.info, Node: BGP route flap dampening, Prev: BGP decision process, Up: BGP router 11.2.3 BGP route flap dampening ------------------------------- -- BGP: bgp dampening <1-45> <1-20000> <1-20000> <1-255> This command enables BGP route-flap dampening and specifies dampening parameters. half-life Half-life time for the penalty reuse-threshold Value to start reusing a route suppress-threshold Value to start suppressing a route max-suppress Maximum duration to suppress a stable route The route-flap damping algorithm is compatible with 'RFC2439'. The use of this command is not recommended nowadays, see RIPE-378.  File: quagga.info, Node: BGP MED, Next: BGP network, Prev: BGP router, Up: BGP 11.3 BGP MED ============ The BGP MED (Multi_Exit_Discriminator) attribute has properties which can cause subtle convergence problems in BGP. These properties and problems have proven to be hard to understand, at least historically, and may still not be widely understood. The following attempts to collect together and present what is known about MED, to help operators and Quagga users in designing and configuring their networks. The BGP MED (Multi_Exit_Discriminator) attribute is intended to allow one AS to indicate its preferences for its ingress points to another AS. The MED attribute will not be propagated on to another AS by the receiving AS - it is 'non-transitive' in the BGP sense. E.g., if AS X and AS Y have 2 different BGP peering points, then AS X might set a MED of 100 on routes advertised at one and a MED of 200 at the other. When AS Y selects between otherwise equal routes to or via AS X, AS Y should prefer to take the path via the lower MED peering of 100 with AS X. Setting the MED allows an AS to influence the routing taken to it within another, neighbouring AS. In this use of MED it is not really meaningful to compare the MED value on routes where the next AS on the paths differs. E.g., if AS Y also had a route for some destination via AS Z in addition to the routes from AS X, and AS Z had also set a MED, it wouldn't make sense for AS Y to compare AS Z's MED values to those of AS X. The MED values have been set by different administrators, with different frames of reference. The default behaviour of BGP therefore is to not compare MED values across routes received from different neighbouring ASes. In Quagga this is done by comparing the neighbouring, left-most AS in the received AS_PATHs of the routes and only comparing MED if those are the same. Unfortunately, this behaviour of MED, of sometimes being compared across routes and sometimes not, depending on the properties of those other routes, means MED can cause the order of preference over all the routes to be undefined. That is, given routes A, B, and C, if A is preferred to B, and B is preferred to C, then a well-defined order should mean the preference is transitive (in the sense of orders (1)) and that A would be preferred to C. However, when MED is involved this need not be the case. With MED it is possible that C is actually preferred over A. So A is preferred to B, B is preferred to C, but C is preferred to A. This can be true even where BGP defines a deterministic "most preferred" route out of the full set of A,B,C. With MED, for any given set of routes there may be a deterministically preferred route, but there need not be any way to arrange them into any order of preference. With unmodified MED, the order of preference of routes literally becomes undefined. That MED can induce non-transitive preferences over routes can cause issues. Firstly, it may be perceived to cause routing table churn locally at speakers; secondly, and more seriously, it may cause routing instability in iBGP topologies, where sets of speakers continually oscillate between different paths. The first issue arises from how speakers often implement routing decisions. Though BGP defines a selection process that will deterministically select the same route as best at any given speaker, even with MED, that process requires evaluating all routes together. For performance and ease of implementation reasons, many implementations evaluate route preferences in a pair-wise fashion instead. Given there is no well-defined order when MED is involved, the best route that will be chosen becomes subject to implementation details, such as the order the routes are stored in. That may be (locally) non-deterministic, e.g. it may be the order the routes were received in. This indeterminism may be considered undesirable, though it need not cause problems. It may mean additional routing churn is perceived, as sometimes more updates may be produced than at other times in reaction to some event . This first issue can be fixed with a more deterministic route selection that ensures routes are ordered by the neighbouring AS during selection. *Note bgp deterministic-med::. This may reduce the number of updates as routes are received, and may in some cases reduce routing churn. Though, it could equally deterministically produce the largest possible set of updates in response to the most common sequence of received updates. A deterministic order of evaluation tends to imply an additional overhead of sorting over any set of n routes to a destination. The implementation of deterministic MED in Quagga scales significantly worse than most sorting algorithms at present, with the number of paths to a given destination. That number is often low enough to not cause any issues, but where there are many paths, the deterministic comparison may quickly become increasingly expensive in terms of CPU. Deterministic local evaluation can _not_ fix the second, more major, issue of MED however. Which is that the non-transitive preference of routes MED can cause may lead to routing instability or oscillation across multiple speakers in iBGP topologies. This can occur with full-mesh iBGP, but is particularly problematic in non-full-mesh iBGP topologies that further reduce the routing information known to each speaker. This has primarily been documented with iBGP route-reflection topologies. However, any route-hiding technologies potentially could also exacerbate oscillation with MED. This second issue occurs where speakers each have only a subset of routes, and there are cycles in the preferences between different combinations of routes - as the undefined order of preference of MED allows - and the routes are distributed in a way that causes the BGP speakers to 'chase' those cycles. This can occur even if all speakers use a deterministic order of evaluation in route selection. E.g., speaker 4 in AS A might receive a route from speaker 2 in AS X, and from speaker 3 in AS Y; while speaker 5 in AS A might receive that route from speaker 1 in AS Y. AS Y might set a MED of 200 at speaker 1, and 100 at speaker 3. I.e, using ASN:ID:MED to label the speakers: /---------------\ X:2------|--A:4-------A:5--|-Y:1:200 Y:3:100--|-/ | \---------------/ Assuming all other metrics are equal (AS_PATH, ORIGIN, 0 IGP costs), then based on the RFC4271 decision process speaker 4 will choose X:2 over Y:3:100, based on the lower ID of 2. Speaker 4 advertises X:2 to speaker 5. Speaker 5 will continue to prefer Y:1:200 based on the ID, and advertise this to speaker 4. Speaker 4 will now have the full set of routes, and the Y:1:200 it receives from 5 will beat X:2, but when speaker 4 compares Y:1:200 to Y:3:100 the MED check now becomes active as the ASes match, and now Y:3:100 is preferred. Speaker 4 therefore now advertises Y:3:100 to 5, which will also agrees that Y:3:100 is preferred to Y:1:200, and so withdraws the latter route from 4. Speaker 4 now has only X:2 and Y:3:100, and X:2 beats Y:3:100, and so speaker 4 implicitly updates its route to speaker 5 to X:2. Speaker 5 sees that Y:1:200 beats X:2 based on the ID, and advertises Y:1:200 to speaker 4, and the cycle continues. The root cause is the lack of a clear order of preference caused by how MED sometimes is and sometimes is not compared, leading to this cycle in the preferences between the routes: /---> X:2 ---beats---> Y:3:100 --\ | | | | \---beats--- Y:1:200 <---beats---/ This particular type of oscillation in full-mesh iBGP topologies can be avoided by speakers preferring already selected, external routes rather than choosing to update to new a route based on a post-MED metric (e.g. router-ID), at the cost of a non-deterministic selection process. Quagga implements this, as do many other implementations, so long as it is not overridden by setting *note bgp bestpath compare-routerid::, and see also *note BGP decision process::, . However, more complex and insidious cycles of oscillation are possible with iBGP route-reflection, which are not so easily avoided. These have been documented in various places. See, e.g., 'McPherson, D. and Gill, V. and Walton, D., "Border Gateway Protocol (BGP) Persistent Route Oscillation Condition", IETF RFC3345', and 'Flavel, A. and M. Roughan, "Stable and flexible iBGP", ACM SIGCOMM 2009', and 'Griffin, T. and G. Wilfong, "On the correctness of IBGP configuration", ACM SIGCOMM 2002' for concrete examples and further references. There is as of this writing _no_ known way to use MED for its original purpose; _and_ reduce routing information in iBGP topologies; _and_ be sure to avoid the instability problems of MED due the non-transitive routing preferences it can induce; in general on arbitrary networks. There may be iBGP topology specific ways to reduce the instability risks, even while using MED, e.g. by constraining the reflection topology and by tuning IGP costs between route-reflector clusters, see RFC3345 for details. In the near future, the Add-Path extension to BGP may also solve MED oscillation while still allowing MED to be used as intended, by distributing "best-paths per neighbour AS". This would be at the cost of distributing at least as many routes to all speakers as a full-mesh iBGP would, if not more, while also imposing similar CPU overheads as the "Deterministic MED" feature at each Add-Path reflector. More generally, the instability problems that MED can introduce on more complex, non-full-mesh, iBGP topologies may be avoided either by: * Setting *note bgp always-compare-med::, however this allows MED to be compared across values set by different neighbour ASes, which may not produce coherent desirable results, of itself. * Effectively ignoring MED by setting MED to the same value (e.g. 0) using *note routemap set metric:: on all received routes, in combination with setting *note bgp always-compare-med:: on all speakers. This is the simplest and most performant way to avoid MED oscillation issues, where an AS is happy not to allow neighbours to inject this problematic metric. As MED is evaluated after the AS_PATH length check, another possible use for MED is for intra-AS steering of routes with equal AS_PATH length, as an extension of the last case above. As MED is evaluated before IGP metric, this can allow cold-potato routing to be implemented to send traffic to preferred hand-offs with neighbours, rather than the closest hand-off according to the IGP metric. Note that even if action is taken to address the MED non-transitivity issues, other oscillations may still be possible. E.g., on IGP cost if iBGP and IGP topologies are at cross-purposes with each other - see the Flavel and Roughan paper above for an example. Hence the guideline that the iBGP topology should follow the IGP topology. -- BGP: bgp deterministic-med Carry out route-selection in way that produces deterministic answers locally, even in the face of MED and the lack of a well-defined order of preference it can induce on routes. Without this option the preferred route with MED may be determined largely by the order that routes were received in. Setting this option will have a performance cost that may be noticeable when there are many routes for each destination. Currently in Quagga it is implemented in a way that scales poorly as the number of routes per destination increases. The default is that this option is not set. Note that there are other sources of indeterminism in the route selection process, specifically, the preference for older and already selected routes from eBGP peers, *Note BGP decision process::. -- BGP: bgp always-compare-med Always compare the MED on routes, even when they were received from different neighbouring ASes. Setting this option makes the order of preference of routes more defined, and should eliminate MED induced oscillations. If using this option, it may also be desirable to use *note routemap set metric:: to set MED to 0 on routes received from external neighbours. This option can be used, together with *note routemap set metric:: to use MED as an intra-AS metric to steer equal-length AS_PATH routes to, e.g., desired exit points. ---------- Footnotes ---------- (1) For some set of objects to have an order, there _must_ be some binary ordering relation that is defined for _every_ combination of those objects, and that relation _must_ be transitive. I.e., if the relation operator is ≺, and if a ≺ b and b ≺ c then that relation must carry over and it _must_ be that a ≺ c for the objects to have an order. The ordering relation may allow for equality, i.e. a ≺ b and b ≺ a may both be true amd imply that a and b are equal in the order and not distinguished by it, in which case the set has a partial order. Otherwise, if there is an order, all the objects have a distinct place in the order and the set has a total order.  File: quagga.info, Node: BGP network, Next: BGP Peer, Prev: BGP MED, Up: BGP 11.4 BGP network ================ * Menu: * BGP route:: * Route Aggregation:: * Redistribute to BGP::  File: quagga.info, Node: BGP route, Next: Route Aggregation, Up: BGP network 11.4.1 BGP route ---------------- -- BGP: network A.B.C.D/M This command adds the announcement network. router bgp 1 network 10.0.0.0/8 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; 'bgpd' doesn't care about IGP routes when announcing its routes. -- BGP: no network A.B.C.D/M  File: quagga.info, Node: Route Aggregation, Next: Redistribute to BGP, Prev: BGP route, Up: BGP network 11.4.2 Route Aggregation ------------------------ -- BGP: aggregate-address A.B.C.D/M This command specifies an aggregate address. -- BGP: aggregate-address A.B.C.D/M as-set This command specifies an aggregate address. Resulting routes include AS set. -- BGP: aggregate-address A.B.C.D/M summary-only This command specifies an aggregate address. Aggreated routes will not be announce. -- BGP: no aggregate-address A.B.C.D/M  File: quagga.info, Node: Redistribute to BGP, Prev: Route Aggregation, Up: BGP network 11.4.3 Redistribute to BGP -------------------------- -- BGP: redistribute kernel Redistribute kernel route to BGP process. -- BGP: redistribute static Redistribute static route to BGP process. -- BGP: redistribute connected Redistribute connected route to BGP process. -- BGP: redistribute rip Redistribute RIP route to BGP process. -- BGP: redistribute ospf Redistribute OSPF route to BGP process.  File: quagga.info, Node: BGP Peer, Next: BGP Peer Group, Prev: BGP network, Up: BGP 11.5 BGP Peer ============= * Menu: * Defining Peer:: * BGP Peer commands:: * Peer filtering::  File: quagga.info, Node: Defining Peer, Next: BGP Peer commands, Up: BGP Peer 11.5.1 Defining Peer -------------------- -- BGP: neighbor PEER remote-as ASN Creates a new neighbor whose remote-as is ASN. PEER can be an IPv4 address or an IPv6 address. router bgp 1 neighbor 10.0.0.1 remote-as 2 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, 'bgpd' will complain like this: can't find neighbor 10.0.0.1  File: quagga.info, Node: BGP Peer commands, Next: Peer filtering, Prev: Defining Peer, Up: BGP Peer 11.5.2 BGP Peer commands ------------------------ In a 'router bgp' clause there are neighbor specific configurations required. -- BGP: neighbor PEER shutdown -- BGP: no neighbor PEER shutdown Shutdown the peer. We can delete the neighbor's configuration by 'no neighbor PEER remote-as 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. -- BGP: neighbor PEER ebgp-multihop -- BGP: no neighbor PEER ebgp-multihop -- BGP: neighbor PEER description ... -- BGP: no neighbor PEER description ... Set description of the peer. -- BGP: neighbor PEER version VERSION Set up the neighbor's BGP version. VERSION can be 4, 4+ or 4-. BGP version 4 is the default value used for BGP peering. BGP version 4+ means that the neighbor supports Multiprotocol Extensions for BGP-4. BGP version 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. -- BGP: neighbor PEER interface IFNAME -- BGP: no neighbor PEER interface IFNAME When you connect to a BGP peer over an IPv6 link-local address, you have to specify the IFNAME of the interface used for the connection. To specify IPv4 session addresses, see the 'neighbor PEER update-source' command below. This command is deprecated and may be removed in a future release. Its use should be avoided. -- BGP: neighbor PEER next-hop-self [all] -- BGP: no neighbor PEER next-hop-self [all] This command specifies an announced route's nexthop as being equivalent to the address of the bgp router if it is learned via eBGP. If the optional keyword 'all' is specified the modifiation is done also for routes learned via iBGP. -- BGP: neighbor PEER update-source -- BGP: no neighbor PEER update-source Specify the IPv4 source address to use for the BGP session to this neighbour, may be specified as either an IPv4 address directly or as an interface name (in which case the 'zebra' daemon MUST be running in order for 'bgpd' to be able to retrieve interface state). router bgp 64555 neighbor foo update-source 192.168.0.1 neighbor bar update-source lo0 -- BGP: neighbor PEER default-originate -- BGP: no neighbor PEER default-originate '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. -- BGP: neighbor PEER port PORT -- BGP: neighbor PEER port PORT -- BGP: neighbor PEER send-community -- BGP: neighbor PEER send-community -- BGP: neighbor PEER weight WEIGHT -- BGP: no neighbor PEER weight WEIGHT This command specifies a default WEIGHT value for the neighbor's routes. -- BGP: neighbor PEER maximum-prefix NUMBER -- BGP: no neighbor PEER maximum-prefix NUMBER -- BGP: neighbor PEER local-as AS-NUMBER -- BGP: neighbor PEER local-as AS-NUMBER no-prepend -- BGP: neighbor PEER local-as AS-NUMBER no-prepend replace-as -- BGP: no neighbor PEER local-as Specify an alternate AS for this BGP process when interacting with the specified peer. With no modifiers, the specified local-as is prepended to the received AS_PATH when receiving routing updates from the peer, and prepended to the outgoing AS_PATH (after the process local AS) when transmitting local routes to the peer. If the no-prepend attribute is specified, then the supplied local-as is not prepended to the received AS_PATH. If the replace-as attribute is specified, then only the supplied local-as is prepended to the AS_PATH when transmitting local-route updates to this peer. Note that replace-as can only be specified if no-prepend is. This command is only allowed for eBGP peers. -- BGP: neighbor PEER ttl-security hops NUMBER -- BGP: no neighbor PEER ttl-security hops NUMBER This command enforces Generalized TTL Security Mechanism (GTSM), as specified in RFC 5082. With this command, only neighbors that are the specified number of hops away will be allowed to become neighbors. This command is mututally exclusive with 'ebgp-multihop'.  File: quagga.info, Node: Peer filtering, Prev: BGP Peer commands, Up: BGP Peer 11.5.3 Peer filtering --------------------- -- BGP: neighbor PEER distribute-list NAME [in|out] This command specifies a distribute-list for the peer. DIRECT is 'in' or 'out'. -- BGP command: neighbor PEER prefix-list NAME [in|out] -- BGP command: neighbor PEER filter-list NAME [in|out] -- BGP: neighbor PEER route-map NAME [in|out] Apply a route-map on the neighbor. DIRECT must be 'in' or 'out'. -- BGP: bgp route-reflector allow-outbound-policy By default, attribute modification via route-map policy out is not reflected on reflected routes. This option allows the modifications to be reflected as well. Once enabled, it affects all reflected routes.  File: quagga.info, Node: BGP Peer Group, Next: BGP Address Family, Prev: BGP Peer, Up: BGP 11.6 BGP Peer Group =================== -- BGP: neighbor WORD peer-group This command defines a new peer group. -- BGP: neighbor PEER peer-group WORD This command bind specific peer to peer group WORD.  File: quagga.info, Node: BGP Address Family, Next: Autonomous System, Prev: BGP Peer Group, Up: BGP 11.7 BGP Address Family ======================= Multiprotocol BGP enables BGP to carry routing information for multiple Network Layer protocols. BGP supports multiple Address Family Identifier (AFI), namely IPv4 and IPv6. Support is also provided for multiple sets of per-AFI information via Subsequent Address Family Identifiers (SAFI). In addition to unicast information, VPN information 'RFC4364' and 'RFC4659', and Encapsulation information 'RFC5512' is supported. -- Command: show ip bgp vpnv4 all -- Command: show ipv6 bgp vpn all Print active IPV4 or IPV6 routes advertised via the VPN SAFI. -- Command: show ip bgp encap all -- Command: show ipv6 bgp encap all Print active IPV4 or IPV6 routes advertised via the Encapsulation SAFI. -- Command: show bgp ipv4 encap summary -- Command: show bgp ipv4 vpn summary -- Command: show bgp ipv6 encap summary -- Command: show bgp ipv6 vpn summary Print a summary of neighbor connections for the specified AFI/SAFI combination.  File: quagga.info, Node: Autonomous System, Next: BGP Communities Attribute, Prev: BGP Address Family, Up: BGP 11.8 Autonomous System ====================== The AS (Autonomous System) number is one of the essential element of BGP. BGP is a distance vector routing protocol, and the AS-Path framework provides distance vector metric and loop detection to BGP. 'RFC1930, Guidelines for creation, selection, and registration of an Autonomous System (AS)' provides some background on the concepts of an AS. The AS number is a two octet value, ranging in value from 1 to 65535. The 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::  File: quagga.info, Node: AS Path Regular Expression, Next: Display BGP Routes by AS Path, Up: Autonomous System 11.8.1 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 'POSIX 1003.2' regular expressions. Following description is just a subset of 'POSIX' regular expression. User can use full 'POSIX' regular expression. Adding to that special character '_' is added for AS path regular expression. '.' Matches any single character. '*' Matches 0 or more occurrences of pattern. '+' Matches 1 or more occurrences of pattern. '?' Match 0 or 1 occurrences of pattern. '^' Matches the beginning of the line. '$' Matches the end of the line. '_' Character '_' has special meanings in AS path regular expression. It matches to space and comma , and AS set delimiter { and } and AS confederation delimiter '(' and ')'. And it also matches to the beginning of the line and the end of the line. So '_' can be used for AS value boundaries match. 'show ip bgp regexp _7675_' matches to all of BGP routes which as AS number include 7675.  File: quagga.info, Node: Display BGP Routes by AS Path, Next: AS Path Access List, Prev: AS Path Regular Expression, Up: Autonomous System 11.8.2 Display BGP Routes by AS Path ------------------------------------ To show BGP routes which has specific AS path information 'show ip bgp' command can be used. -- Command: show ip bgp regexp LINE This commands display BGP routes that matches AS path regular expression LINE.  File: quagga.info, Node: AS Path Access List, Next: Using AS Path in Route Map, Prev: Display BGP Routes by AS Path, Up: Autonomous System 11.8.3 AS Path Access List -------------------------- AS path access list is user defined AS path. -- Command: ip as-path access-list WORD {permit|deny} LINE This command defines a new AS path access list. -- Command: no ip as-path access-list WORD -- Command: no ip as-path access-list WORD {permit|deny} LINE  File: quagga.info, Node: Using AS Path in Route Map, Next: Private AS Numbers, Prev: AS Path Access List, Up: Autonomous System 11.8.4 Using AS Path in Route Map --------------------------------- -- Route Map: match as-path WORD -- Route Map: set as-path prepend AS-PATH Prepend the given string of AS numbers to the AS_PATH. -- Route Map: set as-path prepend last-as NUM Prepend the existing last AS number (the leftmost ASN) to the AS_PATH.  File: quagga.info, Node: Private AS Numbers, Prev: Using AS Path in Route Map, Up: Autonomous System 11.8.5 Private AS Numbers -------------------------  File: quagga.info, Node: BGP Communities Attribute, Next: BGP Extended Communities Attribute, Prev: Autonomous System, Up: BGP 11.9 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 'RFC1997, BGP Communities Attribute' and 'RFC1998, 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. 'AS:VAL' This format represents 4 octet communities value. 'AS' is high order 2 octet in digit format. 'VAL' is low order 2 octet in digit format. This format is useful to define AS oriented policy value. For example, '7675:80' can be used when AS 7675 wants to pass local policy value 80 to neighboring peer. 'internet' 'internet' represents well-known communities value 0. 'no-export' 'no-export' represents well-known communities value 'NO_EXPORT' (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. 'no-advertise' 'no-advertise' represents well-known communities value 'NO_ADVERTISE' (0xFFFFFF02). All routes carry this value must not be advertise to other BGP peers. 'local-AS' 'local-AS' represents well-known communities value 'NO_EXPORT_SUBCONFED' (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. 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::  File: quagga.info, Node: BGP Community Lists, Next: Numbered BGP Community Lists, Up: BGP Communities Attribute 11.9.1 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. -- Command: ip community-list standard NAME {permit|deny} COMMUNITY This command defines a new standard community list. COMMUNITY is communities value. The 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 COMMUNITY is empty it matches to any routes. -- Command: ip community-list expanded NAME {permit|deny} LINE This command defines a new expanded community list. LINE is a string expression of communities attribute. LINE can include regular expression to match communities attribute in BGP updates. -- Command: no ip community-list NAME -- Command: no ip community-list standard NAME -- Command: no ip community-list expanded NAME These commands delete community lists specified by NAME. All of community lists shares a single name space. So community lists can be removed simpley specifying community lists name. -- Command: show ip community-list -- Command: show ip community-list NAME This command display current community list information. When NAME is specified the specified community list's information is shown. # 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  File: quagga.info, Node: Numbered BGP Community Lists, Next: BGP Community in Route Map, Prev: BGP Community Lists, Up: BGP Communities Attribute 11.9.2 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. -- Command: ip community-list <1-99> {permit|deny} 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 COMMUNITY is empty it matches to any routes. -- Command: ip community-list <100-199> {permit|deny} 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. -- Command: ip community-list NAME {permit|deny} COMMUNITY When community list type is not specifed, the community list type is automatically detected. If 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.  File: quagga.info, Node: BGP Community in Route Map, Next: Display BGP Routes by Community, Prev: Numbered BGP Community Lists, Up: BGP Communities Attribute 11.9.3 BGP Community in Route Map --------------------------------- In Route Map (*note 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. -- Route Map: match community WORD -- Route Map: match community WORD exact-match This command perform match to BGP updates using community list WORD. When the one of BGP communities value match to the one of communities value in community list, it is match. When 'exact-match' keyword is spcified, match happen only when BGP updates have completely same communities value specified in the community list. -- Route Map: set community none -- Route Map: set community COMMUNITY -- Route Map: set community COMMUNITY additive This command manipulate communities value in BGP updates. When 'none' is specified as communities value, it removes entire communities attribute from BGP updates. When COMMUNITY is not '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 COMMUNITY value. When 'additive' keyword is specified, COMMUNITY is appended to the existing communities value. -- Route Map: set comm-list WORD delete This command remove communities value from BGP communities attribute. The WORD is community list name. When BGP route's communities value matches to the community list WORD, the communities value is removed. When all of communities value is removed eventually, the BGP update's communities attribute is completely removed.  File: quagga.info, Node: Display BGP Routes by Community, Next: Using BGP Communities Attribute, Prev: BGP Community in Route Map, Up: BGP Communities Attribute 11.9.4 Display BGP Routes by Community -------------------------------------- To show BGP routes which has specific BGP communities attribute, 'show ip bgp' command can be used. The COMMUNITY value and community list can be used for 'show ip bgp' command. -- Command: show ip bgp community -- Command: show ip bgp community COMMUNITY -- Command: show ip bgp community COMMUNITY exact-match 'show ip bgp community' displays BGP routes which has communities attribute. When COMMUNITY is specified, BGP routes that matches COMMUNITY value is displayed. For this command, 'internet' keyword can't be used for COMMUNITY value. When 'exact-match' is specified, it display only routes that have an exact match. -- Command: show ip bgp community-list WORD -- Command: show ip bgp community-list WORD exact-match This commands display BGP routes that matches community list WORD. When 'exact-match' is specified, display only routes that have an exact match.  File: quagga.info, Node: Using BGP Communities Attribute, Prev: Display BGP Routes by Community, Up: BGP Communities Attribute 11.9.5 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. 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 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. 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 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 and 0:90. Network operator can put special internal communities value at BGP border router, then limit the BGP routes announcement into the internal network. 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 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. 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 Communities value keyword 'internet' has special meanings in standard community lists. In below example '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 'INTERNET' is same as above example's 'FILTER'. ip community-list standard INTERNET deny 1:1 ip community-list standard INTERNET permit internet 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 'permit' community-list is used. 'deny' community-list is ignored. 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  File: quagga.info, Node: BGP Extended Communities Attribute, Next: Displaying BGP routes, Prev: BGP Communities Attribute, Up: BGP 11.10 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. 'AS:VAL' This is a format to define AS based Extended Community value. 'AS' part is 2 octets Global Administrator subfield in Extended Community value. 'VAL' part is 4 octets Local Administrator subfield. '7675:100' represents AS 7675 policy value 100. 'IP-Address:VAL' This is a format to define IP address based Extended Community value. 'IP-Address' part is 4 octets Global Administrator subfield. 'VAL' part is 2 octets Local Administrator subfield. '10.0.0.1:100' represents * Menu: * BGP Extended Community Lists:: * BGP Extended Communities in Route Map::  File: quagga.info, Node: BGP Extended Community Lists, Next: BGP Extended Communities in Route Map, Up: BGP Extended Communities Attribute 11.10.1 BGP Extended Community Lists ------------------------------------ Expanded Community Lists is a user defined BGP Expanded Community Lists. -- Command: ip extcommunity-list standard NAME {permit|deny} EXTCOMMUNITY This command defines a new standard extcommunity-list. EXTCOMMUNITY is extended communities value. The 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 EXTCOMMUNITY is empty it matches to any routes. -- Command: ip extcommunity-list expanded NAME {permit|deny} LINE This command defines a new expanded extcommunity-list. LINE is a string expression of extended communities attribute. LINE can include regular expression to match extended communities attribute in BGP updates. -- Command: no ip extcommunity-list NAME -- Command: no ip extcommunity-list standard NAME -- Command: no ip extcommunity-list expanded NAME These commands delete extended community lists specified by NAME. All of extended community lists shares a single name space. So extended community lists can be removed simpley specifying the name. -- Command: show ip extcommunity-list -- Command: show ip extcommunity-list NAME This command display current extcommunity-list information. When NAME is specified the community list's information is shown. # show ip extcommunity-list  File: quagga.info, Node: BGP Extended Communities in Route Map, Prev: BGP Extended Community Lists, Up: BGP Extended Communities Attribute 11.10.2 BGP Extended Communities in Route Map --------------------------------------------- -- Route Map: match extcommunity WORD -- Route Map: set extcommunity rt EXTCOMMUNITY This command set Route Target value. -- Route Map: set extcommunity soo EXTCOMMUNITY This command set Site of Origin value.  File: quagga.info, Node: Displaying BGP routes, Next: Capability Negotiation, Prev: BGP Extended Communities Attribute, Up: BGP 11.11 Displaying BGP Routes =========================== * Menu: * Show IP BGP:: * More Show IP BGP::  File: quagga.info, Node: Show IP BGP, Next: More Show IP BGP, Up: Displaying BGP routes 11.11.1 Show IP BGP ------------------- -- Command: show ip bgp -- Command: show ip bgp A.B.C.D -- Command: show ip bgp X:X::X:X This command displays BGP routes. When no route is specified it display all of IPv4 BGP routes. 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  File: quagga.info, Node: More Show IP BGP, Prev: Show IP BGP, Up: Displaying BGP routes 11.11.2 More Show IP BGP ------------------------ -- Command: show ip bgp regexp LINE This command display BGP routes using AS path regular expression (*note Display BGP Routes by AS Path::). -- Command: show ip bgp community COMMUNITY -- Command: show ip bgp community COMMUNITY exact-match This command display BGP routes using COMMUNITY (*note Display BGP Routes by Community::). -- Command: show ip bgp community-list WORD -- Command: show ip bgp community-list WORD exact-match This command display BGP routes using community list (*note Display BGP Routes by Community::). -- Command: show ip bgp summary -- Command: show ip bgp neighbor [PEER] -- Command: clear ip bgp PEER Clear peers which have addresses of X.X.X.X -- Command: clear ip bgp PEER soft in Clear peer using soft reconfiguration. -- Command: show ip bgp dampened-paths Display paths suppressed due to dampening -- Command: show ip bgp flap-statistics Display flap statistics of routes -- Command: show debug -- Command: debug event -- Command: debug update -- Command: debug keepalive -- Command: no debug event -- Command: no debug update -- Command: no debug keepalive  File: quagga.info, Node: Capability Negotiation, Next: Route Reflector, Prev: Displaying BGP routes, Up: BGP 11.12 Capability Negotiation ============================ When adding IPv6 routing information exchange feature to BGP. There were some proposals. IETF (Internet Engineering Task Force) IDR (Inter Domain Routing) WG (Working group) adopted 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. 'bgpd' supports Multiprotocol Extension for BGP. So if remote peer supports the protocol, 'bgpd' can exchange IPv6 and/or multicast routing information. Traditional BGP did not have the feature to detect remote peer's capabilities, e.g. whether it can handle prefix types other than IPv4 unicast routes. This was a big problem using Multiprotocol Extension for BGP to operational network. 'RFC2842, Capabilities Advertisement with BGP-4' adopted a feature called Capability Negotiation. 'bgpd' use this Capability Negotiation to detect the remote peer's capabilities. If the peer is only configured as IPv4 unicast neighbor, 'bgpd' does not send these Capability Negotiation packets (at least not unless other optional BGP features require capability negotation). By default, Quagga 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, Quagga sends Unsupported Capability error and then resets the connection. If you want to completely match capabilities with remote peer. Please use 'strict-capability-match' command. -- BGP: neighbor PEER strict-capability-match -- BGP: no neighbor PEER strict-capability-match Strictly compares remote capabilities and local capabilities. If capabilities are different, send Unsupported Capability error then reset connection. 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 'dont-capability-negotiate' command to disable the feature. -- BGP: neighbor PEER dont-capability-negotiate -- BGP: no neighbor 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. 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 'override-capability', 'bgpd' ignores received capabilities then override negotiated capabilities with configured values. -- BGP: neighbor PEER override-capability -- BGP: no neighbor PEER override-capability Override the result of Capability Negotiation with local configuration. Ignore remote peer's capability value.  File: quagga.info, Node: Route Reflector, Next: Route Server, Prev: Capability Negotiation, Up: BGP 11.13 Route Reflector ===================== -- BGP: bgp cluster-id A.B.C.D -- BGP: neighbor PEER route-reflector-client -- BGP: no neighbor PEER route-reflector-client  File: quagga.info, Node: Route Server, Next: How to set up a 6-Bone connection, Prev: Route Reflector, Up: BGP 11.14 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 '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 'view's. '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::  File: quagga.info, Node: Multiple instance, Next: BGP instance and view, Up: Route Server 11.14.1 Multiple instance ------------------------- To enable multiple view function of 'bgpd', you must turn on multiple instance feature beforehand. -- Command: bgp multiple-instance Enable BGP multiple instance feature. After this feature is enabled, you can make multiple BGP instances or multiple BGP views. -- Command: no bgp multiple-instance Disable BGP multiple instance feature. You can not disable this feature when BGP multiple instances or views exist. When you want to make configuration more Cisco like one, -- Command: bgp config-type cisco Cisco compatible BGP configuration output. When bgp config-type cisco is specified, "no synchronization" is displayed. "no auto-summary" is displayed. "network" and "aggregate-address" argument is displayed as "A.B.C.D M.M.M.M" Quagga: network 10.0.0.0/8 Cisco: network 10.0.0.0 Quagga: 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 ! -- Command: bgp config-type zebra Quagga style BGP configuration. This is default.  File: quagga.info, Node: BGP instance and view, Next: Routing policy, Prev: Multiple instance, Up: Route Server 11.14.2 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. -- Command: router bgp AS-NUMBER Make a new BGP instance. You can use arbitrary word for the NAME. 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 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. -- Command: router bgp AS-NUMBER view NAME Make a new BGP view. You can use arbitrary word for the NAME. This view's route selection result does not go to the kernel routing table. With this command, you can setup Route Server like below. 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  File: quagga.info, Node: Routing policy, Next: Viewing the view, Prev: BGP instance and view, Up: Route Server 11.14.3 Routing policy ---------------------- You can set different routing policy for a peer. For example, you can set different filter for a peer. 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 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.  File: quagga.info, Node: Viewing the view, Prev: Routing policy, Up: Route Server 11.14.4 Viewing the view ------------------------ To display routing table of BGP view, you must specify view name. -- Command: show ip bgp view NAME Display routing table of BGP view NAME.  File: quagga.info, Node: How to set up a 6-Bone connection, Next: Dump BGP packets and table, Prev: Route Server, Up: BGP 11.15 How to set up a 6-Bone connection ======================================= 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 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 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 !  File: quagga.info, Node: Dump BGP packets and table, Next: BGP Configuration Examples, Prev: How to set up a 6-Bone connection, Up: BGP 11.16 Dump BGP packets and table ================================ -- Command: dump bgp all PATH [INTERVAL] -- Command: dump bgp all-et PATH [INTERVAL] -- Command: no dump bgp all [PATH] [INTERVAL] Dump all BGP packet and events to PATH file. If INTERVAL is set, a new file will be created for echo INTERVAL of seconds. The path PATH can be set with date and time formatting (strftime). The type ‘all-et’ enables support for Extended Timestamp Header (*note Packet Binary Dump Format::). (*note Packet Binary Dump Format::) -- Command: dump bgp updates PATH [INTERVAL] -- Command: dump bgp updates-et PATH [INTERVAL] -- Command: no dump bgp updates [PATH] [INTERVAL] Dump only BGP updates messages to PATH file. If INTERVAL is set, a new file will be created for echo INTERVAL of seconds. The path PATH can be set with date and time formatting (strftime). The type ‘updates-et’ enables support for Extended Timestamp Header (*note Packet Binary Dump Format::). -- Command: dump bgp routes-mrt PATH -- Command: dump bgp routes-mrt PATH INTERVAL -- Command: no dump bgp route-mrt [PATH] [INTERVAL] Dump whole BGP routing table to PATH. This is heavy process. The path PATH can be set with date and time formatting (strftime). If INTERVAL is set, a new file will be created for echo INTERVAL of seconds. Note: the interval variable can also be set using hours and minutes: 04h20m00.  File: quagga.info, Node: BGP Configuration Examples, Prev: Dump BGP packets and table, Up: BGP 11.17 BGP Configuration Examples ================================ Example of a session to an upstream, advertising only one prefix to it. router bgp 64512 bgp router-id 10.236.87.1 network 10.236.87.0/24 neighbor upstream peer-group neighbor upstream remote-as 64515 neighbor upstream capability dynamic neighbor upstream prefix-list pl-allowed-adv out neighbor 10.1.1.1 peer-group upstream neighbor 10.1.1.1 description ACME ISP ! ip prefix-list pl-allowed-adv seq 5 permit 82.195.133.0/25 ip prefix-list pl-allowed-adv seq 10 deny any A more complex example. With upstream, peer and customer sessions. Advertising global prefixes and NO_EXPORT prefixes and providing actions for customer routes based on community values. Extensive use of route-maps and the 'call' feature to support selective advertising of prefixes. This example is intended as guidance only, it has NOT been tested and almost certainly containts silly mistakes, if not serious flaws. router bgp 64512 bgp router-id 10.236.87.1 network 10.123.456.0/24 network 10.123.456.128/25 route-map rm-no-export neighbor upstream capability dynamic neighbor upstream route-map rm-upstream-out out neighbor cust capability dynamic neighbor cust route-map rm-cust-in in neighbor cust route-map rm-cust-out out neighbor cust send-community both neighbor peer capability dynamic neighbor peer route-map rm-peer-in in neighbor peer route-map rm-peer-out out neighbor peer send-community both neighbor 10.1.1.1 remote-as 64515 neighbor 10.1.1.1 peer-group upstream neighbor 10.2.1.1 remote-as 64516 neighbor 10.2.1.1 peer-group upstream neighbor 10.3.1.1 remote-as 64517 neighbor 10.3.1.1 peer-group cust-default neighbor 10.3.1.1 description customer1 neighbor 10.3.1.1 prefix-list pl-cust1-network in neighbor 10.4.1.1 remote-as 64518 neighbor 10.4.1.1 peer-group cust neighbor 10.4.1.1 prefix-list pl-cust2-network in neighbor 10.4.1.1 description customer2 neighbor 10.5.1.1 remote-as 64519 neighbor 10.5.1.1 peer-group peer neighbor 10.5.1.1 prefix-list pl-peer1-network in neighbor 10.5.1.1 description peer AS 1 neighbor 10.6.1.1 remote-as 64520 neighbor 10.6.1.1 peer-group peer neighbor 10.6.1.1 prefix-list pl-peer2-network in neighbor 10.6.1.1 description peer AS 2 ! ip prefix-list pl-default permit 0.0.0.0/0 ! ip prefix-list pl-upstream-peers permit 10.1.1.1/32 ip prefix-list pl-upstream-peers permit 10.2.1.1/32 ! ip prefix-list pl-cust1-network permit 10.3.1.0/24 ip prefix-list pl-cust1-network permit 10.3.2.0/24 ! ip prefix-list pl-cust2-network permit 10.4.1.0/24 ! ip prefix-list pl-peer1-network permit 10.5.1.0/24 ip prefix-list pl-peer1-network permit 10.5.2.0/24 ip prefix-list pl-peer1-network permit 192.168.0.0/24 ! ip prefix-list pl-peer2-network permit 10.6.1.0/24 ip prefix-list pl-peer2-network permit 10.6.2.0/24 ip prefix-list pl-peer2-network permit 192.168.1.0/24 ip prefix-list pl-peer2-network permit 192.168.2.0/24 ip prefix-list pl-peer2-network permit 172.16.1/24 ! ip as-path access-list asp-own-as permit ^$ ip as-path access-list asp-own-as permit _64512_ ! ! ################################################################# ! Match communities we provide actions for, on routes receives from ! customers. Communities values of :X, with X, have actions: ! ! 100 - blackhole the prefix ! 200 - set no_export ! 300 - advertise only to other customers ! 400 - advertise only to upstreams ! 500 - set no_export when advertising to upstreams ! 2X00 - set local_preference to X00 ! ! blackhole the prefix of the route ip community-list standard cm-blackhole permit 64512:100 ! ! set no-export community before advertising ip community-list standard cm-set-no-export permit 64512:200 ! ! advertise only to other customers ip community-list standard cm-cust-only permit 64512:300 ! ! advertise only to upstreams ip community-list standard cm-upstream-only permit 64512:400 ! ! advertise to upstreams with no-export ip community-list standard cm-upstream-noexport permit 64512:500 ! ! set local-pref to least significant 3 digits of the community ip community-list standard cm-prefmod-100 permit 64512:2100 ip community-list standard cm-prefmod-200 permit 64512:2200 ip community-list standard cm-prefmod-300 permit 64512:2300 ip community-list standard cm-prefmod-400 permit 64512:2400 ip community-list expanded cme-prefmod-range permit 64512:2... ! ! Informational communities ! ! 3000 - learned from upstream ! 3100 - learned from customer ! 3200 - learned from peer ! ip community-list standard cm-learnt-upstream permit 64512:3000 ip community-list standard cm-learnt-cust permit 64512:3100 ip community-list standard cm-learnt-peer permit 64512:3200 ! ! ################################################################### ! Utility route-maps ! ! These utility route-maps generally should not used to permit/deny ! routes, i.e. they do not have meaning as filters, and hence probably ! should be used with 'on-match next'. These all finish with an empty ! permit entry so as not interfere with processing in the caller. ! route-map rm-no-export permit 10 set community additive no-export route-map rm-no-export permit 20 ! route-map rm-blackhole permit 10 description blackhole, up-pref and ensure it cant escape this AS set ip next-hop 127.0.0.1 set local-preference 10 set community additive no-export route-map rm-blackhole permit 20 ! ! Set local-pref as requested route-map rm-prefmod permit 10 match community cm-prefmod-100 set local-preference 100 route-map rm-prefmod permit 20 match community cm-prefmod-200 set local-preference 200 route-map rm-prefmod permit 30 match community cm-prefmod-300 set local-preference 300 route-map rm-prefmod permit 40 match community cm-prefmod-400 set local-preference 400 route-map rm-prefmod permit 50 ! ! Community actions to take on receipt of route. route-map rm-community-in permit 10 description check for blackholing, no point continuing if it matches. match community cm-blackhole call rm-blackhole route-map rm-community-in permit 20 match community cm-set-no-export call rm-no-export on-match next route-map rm-community-in permit 30 match community cme-prefmod-range call rm-prefmod route-map rm-community-in permit 40 ! ! ##################################################################### ! Community actions to take when advertising a route. ! These are filtering route-maps, ! ! Deny customer routes to upstream with cust-only set. route-map rm-community-filt-to-upstream deny 10 match community cm-learnt-cust match community cm-cust-only route-map rm-community-filt-to-upstream permit 20 ! ! Deny customer routes to other customers with upstream-only set. route-map rm-community-filt-to-cust deny 10 match community cm-learnt-cust match community cm-upstream-only route-map rm-community-filt-to-cust permit 20 ! ! ################################################################### ! The top-level route-maps applied to sessions. Further entries could ! be added obviously.. ! ! Customers route-map rm-cust-in permit 10 call rm-community-in on-match next route-map rm-cust-in permit 20 set community additive 64512:3100 route-map rm-cust-in permit 30 ! route-map rm-cust-out permit 10 call rm-community-filt-to-cust on-match next route-map rm-cust-out permit 20 ! ! Upstream transit ASes route-map rm-upstream-out permit 10 description filter customer prefixes which are marked cust-only call rm-community-filt-to-upstream on-match next route-map rm-upstream-out permit 20 description only customer routes are provided to upstreams/peers match community cm-learnt-cust ! ! Peer ASes ! outbound policy is same as for upstream route-map rm-peer-out permit 10 call rm-upstream-out ! route-map rm-peer-in permit 10 set community additive 64512:3200  File: quagga.info, Node: Configuring Quagga as a Route Server, Next: VTY shell, Prev: BGP, Up: Top 12 Configuring Quagga as a Route Server *************************************** The purpose of a Route Server is to centralize the peerings between BGP speakers. For example if we have an exchange point scenario with four BGP speakers, each of which maintaining a BGP peering with the other three we can convert it into a centralized scenario where each of the four establishes a single BGP peering against the Route Server. We will first describe briefly the Route Server model implemented by Quagga. We will explain the commands that have been added for configuring that model. And finally we will show a full example of Quagga configured as Route Server. * Menu: * Description of the Route Server model:: * Commands for configuring a Route Server:: * Example of Route Server Configuration::  File: quagga.info, Node: Description of the Route Server model, Next: Commands for configuring a Route Server, Up: Configuring Quagga as a Route Server 12.1 Description of the Route Server model ========================================== First we are going to describe the normal processing that BGP announcements suffer inside a standard BGP speaker, as shown in *note Figure 12.1: fig:normal-processing, it consists of three steps: * When an announcement is received from some peer, the 'In' filters configured for that peer are applied to the announcement. These filters can reject the announcement, accept it unmodified, or accept it with some of its attributes modified. * The announcements that pass the 'In' filters go into the Best Path Selection process, where they are compared to other announcements referred to the same destination that have been received from different peers (in case such other announcements exist). For each different destination, the announcement which is selected as the best is inserted into the BGP speaker's Loc-RIB. * The routes which are inserted in the Loc-RIB are considered for announcement to all the peers (except the one from which the route came). This is done by passing the routes in the Loc-RIB through the 'Out' filters corresponding to each peer. These filters can reject the route, accept it unmodified, or accept it with some of its attributes modified. Those routes which are accepted by the 'Out' filters of a peer are announced to that peer. [image src="fig-normal-processing.png" alt="Normal announcement processing" text=" _______________________________ / _________ _________ \\ From Peer A --->|(A)-|Best | | |-[A]|--->To Peer A From Peer B --->|(B)-|Path |-->|Local-RIB|-[B]|--->To Peer B From Peer C --->|(C)-|Selection| | |-[C]|--->To Peer C From Peer D --->|(D)-|_________| |_________|-[D]|--->To Peer D \\_______________________________/ Key: (X) - 'In' Filter applied to Peer X's announcements [X] - 'Out' Filter applied to announcements to Peer X"] Figure 12.1: Announcement processing inside a "normal" BGP speaker Of course we want that the routing tables obtained in each of the routers are the same when using the route server than when not. But as a consequence of having a single BGP peering (against the route server), the BGP speakers can no longer distinguish from/to which peer each announce comes/goes. This means that the routers connected to the route server are not able to apply by themselves the same input/output filters as in the full mesh scenario, so they have to delegate those functions to the route server. Even more, the "best path" selection must be also performed inside the route server on behalf of its clients. The reason is that if, after applying the filters of the announcer and the (potential) receiver, the route server decides to send to some client two or more different announcements referred to the same destination, the client will only retain the last one, considering it as an implicit withdrawal of the previous announcements for the same destination. This is the expected behavior of a BGP speaker as defined in 'RFC1771', and even though there are some proposals of mechanisms that permit multiple paths for the same destination to be sent through a single BGP peering, none are currently supported by most existing BGP implementations. As a consequence a route server must maintain additional information and perform additional tasks for a RS-client that those necessary for common BGP peerings. Essentially a route server must: * Maintain a separated Routing Information Base (Loc-RIB) for each peer configured as RS-client, containing the routes selected as a result of the "Best Path Selection" process that is performed on behalf of that RS-client. * Whenever it receives an announcement from a RS-client, it must consider it for the Loc-RIBs of the other RS-clients. * This means that for each of them the route server must pass the announcement through the appropriate 'Out' filter of the announcer. * Then through the appropriate 'In' filter of the potential receiver. * Only if the announcement is accepted by both filters it will be passed to the "Best Path Selection" process. * Finally, it might go into the Loc-RIB of the receiver. When we talk about the "appropriate" filter, both the announcer and the receiver of the route must be taken into account. Suppose that the route server receives an announcement from client A, and the route server is considering it for the Loc-RIB of client B. The filters that should be applied are the same that would be used in the full mesh scenario, i.e., first the 'Out' filter of router A for announcements going to router B, and then the 'In' filter of router B for announcements coming from router A. We call "Export Policy" of a RS-client to the set of 'Out' filters that the client would use if there was no route server. The same applies for the "Import Policy" of a RS-client and the set of 'In' filters of the client if there was no route server. It is also common to demand from a route server that it does not modify some BGP attributes (next-hop, as-path and MED) that are usually modified by standard BGP speakers before announcing a route. The announcement processing model implemented by Quagga is shown in *note Figure 12.2: fig:rs-processing. The figure shows a mixture of RS-clients (B, C and D) with normal BGP peers (A). There are some details that worth additional comments: * Announcements coming from a normal BGP peer are also considered for the Loc-RIBs of all the RS-clients. But logically they do not pass through any export policy. * Those peers that are configured as RS-clients do not receive any announce from the 'Main' Loc-RIB. * Apart from import and export policies, 'In' and 'Out' filters can also be set for RS-clients. 'In' filters might be useful when the route server has also normal BGP peers. On the other hand, 'Out' filters for RS-clients are probably unnecessary, but we decided not to remove them as they do not hurt anybody (they can always be left empty). [image src="fig-rs-processing.png" alt="Route Server Processing Model" text="From Peer A | From RS-Client B | | From RS-Client C | | | From RS-Client D | | | | | | | | Main / Normal RIB | | | | ________________________________ | | | | / _________ _________ \\ | | | +--->|(D)-|Best | | Main | | | | +--|--->|(C)-|Path |-->|Local-RIB|->[A]|--->To Peer A | +--|--|--->|(B)-|Selection| | | | +--|--|--|--->|(A)-|_________| |_________| | | | | | \\________________________________/ | | | | | | | | ________________________________ | | | | / _________ _________ \\ | | | +--->*D*->|{B}-|Best | |RS-Client| | | | +--|--->*C*->|{B}-|Path |-->|Local-RIB|->[B]|--->To RS-Client B | | | | | |Selection| | for B | | +--|--|--|-------->|{B}-|_________| |_________| | | | | | \\________________________________/ | | | | | | | | ________________________________ | | | | / _________ _________ \\ | | | +--->*D*->|{C}-|Best | |RS-Client| | | | | | | |Path |-->|Local-RIB|->[C]|--->To RS-Client C | +--|--|--->*B*->|{C}-|Selection| | for C | | +--|--|--|-------->|{C}-|_________| |_________| | | | | \\________________________________/ | | | | | | ________________________________ | | | / _________ _________ \\ | | | | |Best | |RS-Client| | | | +------>*C*->|{D}-|Path |-->|Local-RIB|->[D]|--->To RS-Client D | +--------->*B*->|{D}-|Selection| | for D | | +----------------->|{D}-|_________| |_________| | \\________________________________/ Key: (X) - 'In' Filter applied to Peer X's announcements before considering announcement for the normal main Local-RIB [X] - 'Out' Filter applied to announcements to Peer X *X* - 'Export' Filter of RS-Client X, to apply X's policies before its routes may be considered for other RS-Clients RIBs. {X} - 'Import' Filter of RS-Client X, to apply X's policies on routes before allowing them into X's RIB."] Figure 12.2: Announcement processing model implemented by the Route Server  File: quagga.info, Node: Commands for configuring a Route Server, Next: Example of Route Server Configuration, Prev: Description of the Route Server model, Up: Configuring Quagga as a Route Server 12.2 Commands for configuring a Route Server ============================================ Now we will describe the commands that have been added to quagga in order to support the route server features. -- Route-Server: neighbor PEER-GROUP route-server-client -- Route-Server: neighbor A.B.C.D route-server-client -- Route-Server: neighbor X:X::X:X route-server-client This command configures the peer given by PEER, A.B.C.D or X:X::X:X as an RS-client. Actually this command is not new, it already existed in standard Quagga. It enables the transparent mode for the specified peer. This means that some BGP attributes (as-path, next-hop and MED) of the routes announced to that peer are not modified. With the route server patch, this command, apart from setting the transparent mode, creates a new Loc-RIB dedicated to the specified peer (those named 'Loc-RIB for X' in *note Figure 12.2: fig:rs-processing.). Starting from that moment, every announcement received by the route server will be also considered for the new Loc-RIB. -- Route-Server: neigbor {A.B.C.D|X.X::X.X|peer-group} route-map WORD {import|export} This set of commands can be used to specify the route-map that represents the Import or Export policy of a peer which is configured as a RS-client (with the previous command). -- Route-Server: match peer {A.B.C.D|X:X::X:X} This is a new _match_ statement for use in route-maps, enabling them to describe import/export policies. As we said before, an import/export policy represents a set of input/output filters of the RS-client. This statement makes possible that a single route-map represents the full set of filters that a BGP speaker would use for its different peers in a non-RS scenario. The _match peer_ statement has different semantics whether it is used inside an import or an export route-map. In the first case the statement matches if the address of the peer who sends the announce is the same that the address specified by {A.B.C.D|X:X::X:X}. For export route-maps it matches when {A.B.C.D|X:X::X:X} is the address of the RS-Client into whose Loc-RIB the announce is going to be inserted (how the same export policy is applied before different Loc-RIBs is shown in *note Figure 12.2: fig:rs-processing.). -- Route-map Command: call WORD This command (also used inside a route-map) jumps into a different route-map, whose name is specified by WORD. When the called route-map finishes, depending on its result the original route-map continues or not. Apart from being useful for making import/export route-maps easier to write, this command can also be used inside any normal (in or out) route-map.  File: quagga.info, Node: Example of Route Server Configuration, Prev: Commands for configuring a Route Server, Up: Configuring Quagga as a Route Server 12.3 Example of Route Server Configuration ========================================== Finally we are going to show how to configure a Quagga daemon to act as a Route Server. For this purpose we are going to present a scenario without route server, and then we will show how to use the configurations of the BGP routers to generate the configuration of the route server. All the configuration files shown in this section have been taken from scenarios which were tested using the VNUML tool VNUML (http://www.dit.upm.es/vnuml). * Menu: * Configuration of the BGP routers without Route Server:: * Configuration of the BGP routers with Route Server:: * Configuration of the Route Server itself:: * Further considerations about Import and Export route-maps::  File: quagga.info, Node: Configuration of the BGP routers without Route Server, Next: Configuration of the BGP routers with Route Server, Up: Example of Route Server Configuration 12.3.1 Configuration of the BGP routers without Route Server ------------------------------------------------------------ We will suppose that our initial scenario is an exchange point with three BGP capable routers, named RA, RB and RC. Each of the BGP speakers generates some routes (with the NETWORK command), and establishes BGP peerings against the other two routers. These peerings have In and Out route-maps configured, named like "PEER-X-IN" or "PEER-X-OUT". For example the configuration file for router RA could be the following: #Configuration for router 'RA' ! hostname RA password **** ! router bgp 65001 no bgp default ipv4-unicast neighbor 2001:0DB8::B remote-as 65002 neighbor 2001:0DB8::C remote-as 65003 ! address-family ipv6 network 2001:0DB8:AAAA:1::/64 network 2001:0DB8:AAAA:2::/64 network 2001:0DB8:0000:1::/64 network 2001:0DB8:0000:2::/64 neighbor 2001:0DB8::B activate neighbor 2001:0DB8::B soft-reconfiguration inbound neighbor 2001:0DB8::B route-map PEER-B-IN in neighbor 2001:0DB8::B route-map PEER-B-OUT out neighbor 2001:0DB8::C activate neighbor 2001:0DB8::C soft-reconfiguration inbound neighbor 2001:0DB8::C route-map PEER-C-IN in neighbor 2001:0DB8::C route-map PEER-C-OUT out exit-address-family ! ipv6 prefix-list COMMON-PREFIXES seq 5 permit 2001:0DB8:0000::/48 ge 64 le 64 ipv6 prefix-list COMMON-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-A-PREFIXES seq 5 permit 2001:0DB8:AAAA::/48 ge 64 le 64 ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-B-PREFIXES seq 5 permit 2001:0DB8:BBBB::/48 ge 64 le 64 ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-C-PREFIXES seq 5 permit 2001:0DB8:CCCC::/48 ge 64 le 64 ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any ! route-map PEER-B-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 100 route-map PEER-B-IN permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! route-map PEER-C-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 200 route-map PEER-C-IN permit 20 match ipv6 address prefix-list PEER-C-PREFIXES set community 65001:22222 ! route-map PEER-B-OUT permit 10 match ipv6 address prefix-list PEER-A-PREFIXES ! route-map PEER-C-OUT permit 10 match ipv6 address prefix-list PEER-A-PREFIXES ! line vty !  File: quagga.info, Node: Configuration of the BGP routers with Route Server, Next: Configuration of the Route Server itself, Prev: Configuration of the BGP routers without Route Server, Up: Example of Route Server Configuration 12.3.2 Configuration of the BGP routers with Route Server --------------------------------------------------------- To convert the initial scenario into one with route server, first we must modify the configuration of routers RA, RB and RC. Now they must not peer between them, but only with the route server. For example, RA's configuration would turn into: # Configuration for router 'RA' ! hostname RA password **** ! router bgp 65001 no bgp default ipv4-unicast neighbor 2001:0DB8::FFFF remote-as 65000 ! address-family ipv6 network 2001:0DB8:AAAA:1::/64 network 2001:0DB8:AAAA:2::/64 network 2001:0DB8:0000:1::/64 network 2001:0DB8:0000:2::/64 neighbor 2001:0DB8::FFFF activate neighbor 2001:0DB8::FFFF soft-reconfiguration inbound exit-address-family ! line vty ! Which is logically much simpler than its initial configuration, as it now maintains only one BGP peering and all the filters (route-maps) have disappeared.  File: quagga.info, Node: Configuration of the Route Server itself, Next: Further considerations about Import and Export route-maps, Prev: Configuration of the BGP routers with Route Server, Up: Example of Route Server Configuration 12.3.3 Configuration of the Route Server itself ----------------------------------------------- As we said when we described the functions of a route server (*note Description of the Route Server model::), it is in charge of all the route filtering. To achieve that, the In and Out filters from the RA, RB and RC configurations must be converted into Import and Export policies in the route server. This is a fragment of the route server configuration (we only show the policies for client RA): # Configuration for Route Server ('RS') ! hostname RS password ix ! bgp multiple-instance ! router bgp 65000 view RS no bgp default ipv4-unicast neighbor 2001:0DB8::A remote-as 65001 neighbor 2001:0DB8::B remote-as 65002 neighbor 2001:0DB8::C remote-as 65003 ! address-family ipv6 neighbor 2001:0DB8::A activate neighbor 2001:0DB8::A route-server-client neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import neighbor 2001:0DB8::A route-map RSCLIENT-A-EXPORT export neighbor 2001:0DB8::A soft-reconfiguration inbound neighbor 2001:0DB8::B activate neighbor 2001:0DB8::B route-server-client neighbor 2001:0DB8::B route-map RSCLIENT-B-IMPORT import neighbor 2001:0DB8::B route-map RSCLIENT-B-EXPORT export neighbor 2001:0DB8::B soft-reconfiguration inbound neighbor 2001:0DB8::C activate neighbor 2001:0DB8::C route-server-client neighbor 2001:0DB8::C route-map RSCLIENT-C-IMPORT import neighbor 2001:0DB8::C route-map RSCLIENT-C-EXPORT export neighbor 2001:0DB8::C soft-reconfiguration inbound exit-address-family ! ipv6 prefix-list COMMON-PREFIXES seq 5 permit 2001:0DB8:0000::/48 ge 64 le 64 ipv6 prefix-list COMMON-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-A-PREFIXES seq 5 permit 2001:0DB8:AAAA::/48 ge 64 le 64 ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-B-PREFIXES seq 5 permit 2001:0DB8:BBBB::/48 ge 64 le 64 ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-C-PREFIXES seq 5 permit 2001:0DB8:CCCC::/48 ge 64 le 64 ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any ! route-map RSCLIENT-A-IMPORT permit 10 match peer 2001:0DB8::B call A-IMPORT-FROM-B route-map RSCLIENT-A-IMPORT permit 20 match peer 2001:0DB8::C call A-IMPORT-FROM-C ! route-map A-IMPORT-FROM-B permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 100 route-map A-IMPORT-FROM-B permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! route-map A-IMPORT-FROM-C permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 200 route-map A-IMPORT-FROM-C permit 20 match ipv6 address prefix-list PEER-C-PREFIXES set community 65001:22222 ! route-map RSCLIENT-A-EXPORT permit 10 match peer 2001:0DB8::B match ipv6 address prefix-list PEER-A-PREFIXES route-map RSCLIENT-A-EXPORT permit 20 match peer 2001:0DB8::C match ipv6 address prefix-list PEER-A-PREFIXES ! ... ... ... If you compare the initial configuration of RA with the route server configuration above, you can see how easy it is to generate the Import and Export policies for RA from the In and Out route-maps of RA's original configuration. When there was no route server, RA maintained two peerings, one with RB and another with RC. Each of this peerings had an In route-map configured. To build the Import route-map for client RA in the route server, simply add route-map entries following this scheme: route-map permit 10 match peer call route-map permit 20 match peer call This is exactly the process that has been followed to generate the route-map RSCLIENT-A-IMPORT. The route-maps that are called inside it (A-IMPORT-FROM-B and A-IMPORT-FROM-C) are exactly the same than the In route-maps from the original configuration of RA (PEER-B-IN and PEER-C-IN), only the name is different. The same could have been done to create the Export policy for RA (route-map RSCLIENT-A-EXPORT), but in this case the original Out route-maps where so simple that we decided not to use the CALL WORD commands, and we integrated all in a single route-map (RSCLIENT-A-EXPORT). The Import and Export policies for RB and RC are not shown, but the process would be identical.  File: quagga.info, Node: Further considerations about Import and Export route-maps, Prev: Configuration of the Route Server itself, Up: Example of Route Server Configuration 12.3.4 Further considerations about Import and Export route-maps ---------------------------------------------------------------- The current version of the route server patch only allows to specify a route-map for import and export policies, while in a standard BGP speaker apart from route-maps there are other tools for performing input and output filtering (access-lists, community-lists, ...). But this does not represent any limitation, as all kinds of filters can be included in import/export route-maps. For example suppose that in the non-route-server scenario peer RA had the following filters configured for input from peer B: neighbor 2001:0DB8::B prefix-list LIST-1 in neighbor 2001:0DB8::B filter-list LIST-2 in neighbor 2001:0DB8::B route-map PEER-B-IN in ... ... route-map PEER-B-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set local-preference 100 route-map PEER-B-IN permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 It is posible to write a single route-map which is equivalent to the three filters (the community-list, the prefix-list and the route-map). That route-map can then be used inside the Import policy in the route server. Lets see how to do it: neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import ... ! ... route-map RSCLIENT-A-IMPORT permit 10 match peer 2001:0DB8::B call A-IMPORT-FROM-B ... ... ! route-map A-IMPORT-FROM-B permit 1 match ipv6 address prefix-list LIST-1 match as-path LIST-2 on-match goto 10 route-map A-IMPORT-FROM-B deny 2 route-map A-IMPORT-FROM-B permit 10 match ipv6 address prefix-list COMMON-PREFIXES set local-preference 100 route-map A-IMPORT-FROM-B permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! ... ... The route-map A-IMPORT-FROM-B is equivalent to the three filters (LIST-1, LIST-2 and PEER-B-IN). The first entry of route-map A-IMPORT-FROM-B (sequence number 1) matches if and only if both the prefix-list LIST-1 and the filter-list LIST-2 match. If that happens, due to the "on-match goto 10" statement the next route-map entry to be processed will be number 10, and as of that point route-map A-IMPORT-FROM-B is identical to PEER-B-IN. If the first entry does not match, 'on-match goto 10" will be ignored and the next processed entry will be number 2, which will deny the route. Thus, the result is the same that with the three original filters, i.e., if either LIST-1 or LIST-2 rejects the route, it does not reach the route-map PEER-B-IN. In case both LIST-1 and LIST-2 accept the route, it passes to PEER-B-IN, which can reject, accept or modify the route.  File: quagga.info, Node: VTY shell, Next: Filtering, Prev: Configuring Quagga as a Route Server, Up: Top 13 VTY shell ************ 'vtysh' is integrated shell of Quagga 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 /etc/quagga 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 two commands. * Menu: * VTY shell username:: * VTY shell integrated configuration::  File: quagga.info, Node: VTY shell username, Next: VTY shell integrated configuration, Up: VTY shell 13.1 VTY shell username ======================= -- Command: username USERNAME nopassword 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. vtysh requires read/write permission to the various daemons vty sockets, this can be accomplished through use of unix groups and the -enable-vty-group configure option.  File: quagga.info, Node: VTY shell integrated configuration, Prev: VTY shell username, Up: VTY shell 13.2 VTY shell integrated configuration ======================================= -- Command: service integrated-vtysh-config Write out integrated Quagga.conf file when 'write file' is issued. This command controls the behaviour of vtysh when it is told to write out the configuration. Per default, vtysh will instruct each daemon to write out their own config files when 'write file' is issued. However, if 'service integrated-vtysh-config' is set, when 'write file' is issued, vtysh will instruct the daemons will write out a Quagga.conf with all daemons' commands integrated into it. Vtysh per default behaves as if 'write-conf daemon' is set. Note that both may be set at same time if one wishes to have both Quagga.conf and daemon specific files written out. Further, note that the daemons are hard-coded to first look for the integrated Quagga.conf file before looking for their own file. We recommend you do not mix the use of the two types of files. Further, it is better not to use the integrated Quagga.conf file, as any syntax error in it can lead to /all/ of your daemons being unable to start up. Per daemon files are more robust as impact of errors in configuration are limited to the daemon in whose file the error is made.  File: quagga.info, Node: Filtering, Next: Route Map, Prev: VTY shell, Up: Top 14 Filtering ************ Quagga 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::  File: quagga.info, Node: IP Access List, Next: IP Prefix List, Up: Filtering 14.1 IP Access List =================== -- Command: access-list NAME permit IPV4-NETWORK -- Command: access-list NAME deny IPV4-NETWORK Basic filtering is done by 'access-list' as shown in the following example. access-list filter deny 10.0.0.0/9 access-list filter permit 10.0.0.0/8  File: quagga.info, Node: IP Prefix List, Prev: IP Access List, Up: Filtering 14.2 IP Prefix List =================== 'ip prefix-list' provides the most powerful prefix based filtering mechanism. In addition to 'access-list' functionality, '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 'ip prefix-list' is defined, and no match is found, default deny is applied. -- Command: ip prefix-list NAME (permit|deny) PREFIX [le LEN] [ge LEN] -- Command: ip prefix-list NAME seq NUMBER (permit|deny) PREFIX [le LEN] [ge LEN] You can create 'ip prefix-list' using above commands. seq seq 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. le '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. ge '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. 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, the prefix length must match exactly the length specified in the prefix list. -- Command: no ip prefix-list NAME * Menu: * ip prefix-list description:: * ip prefix-list sequential number control:: * Showing ip prefix-list:: * Clear counter of ip prefix-list::  File: quagga.info, Node: ip prefix-list description, Next: ip prefix-list sequential number control, Up: IP Prefix List 14.2.1 ip prefix-list description --------------------------------- -- Command: ip prefix-list NAME description DESC Descriptions may be added to prefix lists. This command adds a description to the prefix list. -- Command: no ip prefix-list NAME description [DESC] Deletes the description from a prefix list. It is possible to use the command without the full description.  File: quagga.info, Node: ip prefix-list sequential number control, Next: Showing ip prefix-list, Prev: ip prefix-list description, Up: IP Prefix List 14.2.2 ip prefix-list sequential number control ----------------------------------------------- -- Command: ip prefix-list sequence-number With this command, the IP prefix list sequential number is displayed. This is the default behavior. -- Command: no ip prefix-list sequence-number With this command, the IP prefix list sequential number is not displayed.  File: quagga.info, Node: Showing ip prefix-list, Next: Clear counter of ip prefix-list, Prev: ip prefix-list sequential number control, Up: IP Prefix List 14.2.3 Showing ip prefix-list ----------------------------- -- Command: show ip prefix-list Display all IP prefix lists. -- Command: show ip prefix-list NAME Show IP prefix list can be used with a prefix list name. -- Command: show ip prefix-list NAME seq NUM Show IP prefix list can be used with a prefix list name and sequential number. -- Command: show ip prefix-list NAME 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. -- Command: show ip prefix-list NAME A.B.C.D/M longer -- Command: show ip prefix-list NAME A.B.C.D/M first-match -- Command: show ip prefix-list summary -- Command: show ip prefix-list summary NAME -- Command: show ip prefix-list detail -- Command: show ip prefix-list detail NAME  File: quagga.info, Node: Clear counter of ip prefix-list, Prev: Showing ip prefix-list, Up: IP Prefix List 14.2.4 Clear counter of ip prefix-list -------------------------------------- -- 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. -- Command: clear ip prefix-list NAME -- Command: clear ip prefix-list NAME A.B.C.D/M  File: quagga.info, Node: Route Map, Next: IPv6 Support, Prev: Filtering, Up: Top 15 Route Map ************ Route maps provide a means to both filter and/or apply actions to route, hence allowing policy to be applied to routes. * Menu: * Route Map Command:: * Route Map Match Command:: * Route Map Set Command:: * Route Map Call Command:: * Route Map Exit Action Command:: * Route Map Examples:: Route-maps are an ordered list of route-map entries. Each entry may specify up to four distincts sets of clauses: 'Matching Policy' This specifies the policy implied if the 'Matching Conditions' are met or not met, and which actions of the route-map are to be taken, if any. The two possibilities are: - 'permit': If the entry matches, then carry out the 'Set Actions'. Then finish processing the route-map, permitting the route, unless an 'Exit Action' indicates otherwise. - 'deny': If the entry matches, then finish processing the route-map and deny the route (return 'deny'). The 'Matching Policy' is specified as part of the command which defines the ordered entry in the route-map. See below. 'Matching Conditions' A route-map entry may, optionally, specify one or more conditions which must be matched if the entry is to be considered further, as governed by the Match Policy. If a route-map entry does not explicitely specify any matching conditions, then it always matches. 'Set Actions' A route-map entry may, optionally, specify one or more 'Set Actions' to set or modify attributes of the route. 'Call Action' Call to another route-map, after any 'Set Actions' have been carried out. If the route-map called returns 'deny' then processing of the route-map finishes and the route is denied, regardless of the 'Matching Policy' or the 'Exit Policy'. If the called route-map returns 'permit', then 'Matching Policy' and 'Exit Policy' govern further behaviour, as normal. 'Exit Policy' An entry may, optionally, specify an alternative 'Exit Policy' to take if the entry matched, rather than the normal policy of exiting the route-map and permitting the route. The two possibilities are: - 'next': Continue on with processing of the route-map entries. - 'goto N': Jump ahead to the first route-map entry whose order in the route-map is >= N. Jumping to a previous entry is not permitted. The default action of a route-map, if no entries match, is to deny. I.e. a route-map essentially has as its last entry an empty 'deny' entry, which matches all routes. To change this behaviour, one must specify an empty 'permit' entry as the last entry in the route-map. To summarise the above: Match No Match ----------------------------- _Permit_ action cont _Deny_ deny cont 'action' - Apply _set_ statements - If _call_ is present, call given route-map. If that returns a 'deny', finish processing and return 'deny'. - If 'Exit Policy' is _next_, goto next route-map entry - If 'Exit Policy' is _goto_, goto first entry whose order in the list is >= the given order. - Finish processing the route-map and permit the route. 'deny' - The route is denied by the route-map (return 'deny'). 'cont' - goto next route-map entry  File: quagga.info, Node: Route Map Command, Next: Route Map Match Command, Up: Route Map 15.1 Route Map Command ====================== -- Command: route-map ROUTE-MAP-NAME (permit|deny) ORDER Configure the ORDER'th entry in ROUTE-MAP-NAME with 'Match Policy' of either _permit_ or _deny_.  File: quagga.info, Node: Route Map Match Command, Next: Route Map Set Command, Prev: Route Map Command, Up: Route Map 15.2 Route Map Match Command ============================ -- Route-map Command: match ip address ACCESS_LIST Matches the specified ACCESS_LIST -- Route-map Command: match ip next-hop IPV4_ADDR Matches the specified IPV4_ADDR. -- Route-map Command: match as-path AS_PATH Matches the specified AS_PATH. -- Route-map Command: match metric METRIC Matches the specified METRIC. -- Route-map Command: match local-preference METRIC Matches the specified LOCAL-PREFERENCE. -- Route-map Command: match community COMMUNITY_LIST Matches the specified COMMUNITY_LIST  File: quagga.info, Node: Route Map Set Command, Next: Route Map Call Command, Prev: Route Map Match Command, Up: Route Map 15.3 Route Map Set Command ========================== -- Route-map Command: set ip next-hop IPV4_ADDRESS Set the BGP nexthop address. -- Route-map Command: set local-preference LOCAL_PREF Set the BGP local preference. -- Route-map Command: set weight WEIGHT Set the route's weight. -- Route-map Command: set metric METRIC Set the BGP attribute MED. -- Route-map Command: set as-path prepend AS_PATH Set the BGP AS path to prepend. -- Route-map Command: set community COMMUNITY Set the BGP community attribute. -- Route-map Command: set ipv6 next-hop global IPV6_ADDRESS Set the BGP-4+ global IPv6 nexthop address. -- Route-map Command: set ipv6 next-hop local IPV6_ADDRESS Set the BGP-4+ link local IPv6 nexthop address.  File: quagga.info, Node: Route Map Call Command, Next: Route Map Exit Action Command, Prev: Route Map Set Command, Up: Route Map 15.4 Route Map Call Command =========================== -- Route-map Command: call NAME Call route-map NAME. If it returns deny, deny the route and finish processing the route-map.  File: quagga.info, Node: Route Map Exit Action Command, Next: Route Map Examples, Prev: Route Map Call Command, Up: Route Map 15.5 Route Map Exit Action Command ================================== -- Route-map Command: on-match next -- Route-map Command: continue Proceed on to the next entry in the route-map. -- Route-map Command: on-match goto N -- Route-map Command: continue N Proceed processing the route-map at the first entry whose order is >= N  File: quagga.info, Node: Route Map Examples, Prev: Route Map Exit Action Command, Up: Route Map 15.6 Route Map Examples ======================= A simple example of a route-map: route-map test permit 10 match ip address 10 set local-preference 200 This means that if a route matches ip access-list number 10 it's local-preference value is set to 200. See *note BGP Configuration Examples:: for examples of more sophisticated useage of route-maps, including of the 'call' action.  File: quagga.info, Node: IPv6 Support, Next: Kernel Interface, Prev: Route Map, Up: Top 16 IPv6 Support *************** Quagga fully supports IPv6 routing. As described so far, Quagga supports RIPng, OSPFv3, and BGP-4+. You can give IPv6 addresses to an interface and configure static IPv6 routing information. Quagga IPv6 also provides automatic address configuration via a feature called '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::  File: quagga.info, Node: Router Advertisement, Up: IPv6 Support 16.1 Router Advertisement ========================= -- Interface Command: no ipv6 nd suppress-ra Send router advertisment messages. -- Interface Command: ipv6 nd suppress-ra Don't send router advertisment messages. -- Interface Command: ipv6 nd prefix IPV6PREFIX [VALID-LIFETIME] [PREFERRED-LIFETIME] [off-link] [no-autoconfig] [router-address] Configuring the IPv6 prefix to include in router advertisements. Several prefix specific optional parameters and flags may follow: * VALID-LIFETIME - the length of time in seconds during what the prefix is valid for the purpose of on-link determination. Value INFINITE represents infinity (i.e. a value of all one bits ('0xffffffff')). Range: '<0-4294967295>' Default: '2592000' * PREFERRED-LIFETIME - the length of time in seconds during what addresses generated from the prefix remain preferred. Value INFINITE represents infinity. Range: '<0-4294967295>' Default: '604800' * OFF-LINK - indicates that advertisement makes no statement about on-link or off-link properties of the prefix. Default: not set, i.e. this prefix can be used for on-link determination. * NO-AUTOCONFIG - indicates to hosts on the local link that the specified prefix cannot be used for IPv6 autoconfiguration. Default: not set, i.e. prefix can be used for autoconfiguration. * ROUTER-ADDRESS - indicates to hosts on the local link that the specified prefix contains a complete IP address by setting R flag. Default: not set, i.e. hosts do not assume a complete IP address is placed. -- Interface Command: ipv6 nd ra-interval <1-1800> -- Interface Command: no ipv6 nd ra-interval [<1-1800>] The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in seconds. Default: '600' -- Interface Command: ipv6 nd ra-interval msec <70-1800000> -- Interface Command: no ipv6 nd ra-interval [msec <70-1800000>] The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in milliseconds. Default: '600000' -- Interface Command: ipv6 nd ra-lifetime <0-9000> -- Interface Command: no ipv6 nd ra-lifetime [<0-9000>] The value to be placed in the Router Lifetime field of router advertisements sent from the interface, in seconds. Indicates the usefulness of the router as a default router on this interface. Setting the value to zero indicates that the router should not be considered a default router on this interface. Must be either zero or between value specified with IPV6 ND RA-INTERVAL (or default) and 9000 seconds. Default: '1800' -- Interface Command: ipv6 nd reachable-time <1-3600000> -- Interface Command: no ipv6 nd reachable-time [<1-3600000>] The value to be placed in the Reachable Time field in the Router Advertisement messages sent by the router, in milliseconds. The configured time enables the router to detect unavailable neighbors. The value zero means unspecified (by this router). Default: '0' -- Interface Command: ipv6 nd managed-config-flag -- Interface Command: no ipv6 nd managed-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use managed (stateful) protocol for addresses autoconfiguration in addition to any addresses autoconfigured using stateless address autoconfiguration. Default: not set -- Interface Command: ipv6 nd other-config-flag -- Interface Command: no ipv6 nd other-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use administered (stateful) protocol to obtain autoconfiguration information other than addresses. Default: not set -- Interface Command: ipv6 nd home-agent-config-flag -- Interface Command: no ipv6 nd home-agent-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that the router acts as a Home Agent and includes a Home Agent Option. Default: not set -- Interface Command: ipv6 nd home-agent-preference <0-65535> -- Interface Command: no ipv6 nd home-agent-preference [<0-65535>] The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent preference. The default value of 0 stands for the lowest preference possible. Default: 0 -- Interface Command: ipv6 nd home-agent-lifetime <0-65520> -- Interface Command: no ipv6 nd home-agent-lifetime [<0-65520>] The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent Lifetime. The default value of 0 means to place the current Router Lifetime value. Default: 0 -- Interface Command: ipv6 nd adv-interval-option -- Interface Command: no ipv6 nd adv-interval-option Include an Advertisement Interval option which indicates to hosts the maximum time, in milliseconds, between successive unsolicited Router Advertisements. Default: not set -- Interface Command: ipv6 nd router-preference (high|medium|low) -- Interface Command: no ipv6 nd router-preference [(high|medium|low)] Set default router preference in IPv6 router advertisements per RFC4191. Default: medium -- Interface Command: ipv6 nd mtu <1-65535> -- Interface Command: no ipv6 nd mtu [<1-65535>] Include an MTU (type 5) option in each RA packet to assist the attached hosts in proper interface configuration. The announced value is not verified to be consistent with router interface MTU. Default: don't advertise any MTU option interface eth0 no ipv6 nd suppress-ra ipv6 nd prefix 2001:0DB8:5009::/64 For more information see 'RFC2462 (IPv6 Stateless Address Autoconfiguration)' , 'RFC4861 (Neighbor Discovery for IP Version 6 (IPv6))' , 'RFC6275 (Mobility Support in IPv6)' and 'RFC4191 (Default Router Preferences and More-Specific Routes)'.  File: quagga.info, Node: Kernel Interface, Next: SNMP Support, Prev: IPv6 Support, Up: Top 17 Kernel Interface ******************* There are several different methods for reading kernel routing table information, updating kernel routing tables, and for looking up interfaces. 'ioctl' The 'ioctl' method is a very traditional way for reading or writing kernel information. 'ioctl' can be used for looking up interfaces and for modifying interface addresses, flags, mtu settings and other types of information. Also, '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. 'sysctl' '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 'ioctl'. 'proc filesystem' 'proc filesystem' provides an easy way of getting kernel information. 'routing socket' 'netlink' On recent Linux kernels (2.0.x and 2.2.x), there is a kernel/user communication support called 'netlink'. It makes asynchronous communication between kernel and Quagga 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 Quagga. You can use netlink as a dynamic routing update channel between Quagga and the kernel.  File: quagga.info, Node: SNMP Support, Next: Zebra Protocol, Prev: Kernel Interface, Up: Top 18 SNMP Support *************** SNMP (Simple Network Managing Protocol) is a widely implemented feature for collecting network information from router and/or host. Quagga itself does not support SNMP agent (server daemon) functionality but is able to connect to a SNMP agent using the SMUX protocol ('RFC1227') or the AgentX protocol ('RFC2741') and make the routing protocol MIBs available through it. * Menu: * Getting and installing an SNMP agent:: * AgentX configuration:: * SMUX configuration:: * MIB and command reference:: * Handling SNMP Traps::  File: quagga.info, Node: Getting and installing an SNMP agent, Next: AgentX configuration, Up: SNMP Support 18.1 Getting and installing an SNMP agent ========================================= There are several SNMP agent which support SMUX or AgentX. We recommend to use the latest version of 'net-snmp' which was formerly known as 'ucd-snmp'. It is free and open software and available at and as binary package for most Linux distributions. 'net-snmp' has to be compiled with '--with-mib-modules=agentx' to be able to accept connections from Quagga using AgentX protocol or with '--with-mib-modules=smux' to use SMUX protocol. Nowadays, SMUX is a legacy protocol. The AgentX protocol should be preferred for any new deployment. Both protocols have the same coverage.  File: quagga.info, Node: AgentX configuration, Next: SMUX configuration, Prev: Getting and installing an SNMP agent, Up: SNMP Support 18.2 AgentX configuration ========================= To enable AgentX protocol support, Quagga must have been build with the '--enable-snmp' or '--enable-snmp=agentx' option. Both the master SNMP agent (snmpd) and each of the Quagga daemons must be configured. In '/etc/snmp/snmpd.conf', 'master agentx' directive should be added. In each of the Quagga daemons, 'agentx' command will enable AgentX support. /etc/snmp/snmpd.conf: # # example access restrictions setup # com2sec readonly default public group MyROGroup v1 readonly view all included .1 80 access MyROGroup "" any noauth exact all none none # # enable master agent for AgentX subagents # master agentx /etc/quagga/ospfd.conf: ! ... the rest of ospfd.conf has been omitted for clarity ... ! agentx ! Upon successful connection, you should get something like this in the log of each Quagga daemons: 2012/05/25 11:39:08 ZEBRA: snmp[info]: NET-SNMP version 5.4.3 AgentX subagent connected Then, you can use the following command to check everything works as expected: # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 [...] The AgentX protocol can be transported over a Unix socket or using TCP or UDP. It usually defaults to a Unix socket and depends on how NetSNMP was built. If need to configure Quagga to use another transport, you can configure it through '/etc/snmp/quagga.conf': /etc/snmp/quagga.conf: [snmpd] # Use a remote master agent agentXSocket tcp:192.168.15.12:705  File: quagga.info, Node: SMUX configuration, Next: MIB and command reference, Prev: AgentX configuration, Up: SNMP Support 18.3 SMUX configuration ======================= To enable SMUX protocol support, Quagga must have been build with the '--enable-snmp=smux' option. A separate connection has then to be established between the SNMP agent (snmpd) and each of the Quagga daemons. This connections each use different OID numbers and passwords. Be aware that this OID number is not the one that is used in queries by clients, it is solely used for the intercommunication of the daemons. In the following example the ospfd daemon will be connected to the snmpd daemon using the password "quagga_ospfd". For testing it is recommending to take exactly the below snmpd.conf as wrong access restrictions can be hard to debug. /etc/snmp/snmpd.conf: # # example access restrictions setup # com2sec readonly default public group MyROGroup v1 readonly view all included .1 80 access MyROGroup "" any noauth exact all none none # # the following line is relevant for Quagga # smuxpeer .1.3.6.1.4.1.3317.1.2.5 quagga_ospfd /etc/quagga/ospf: ! ... the rest of ospfd.conf has been omitted for clarity ... ! smux peer .1.3.6.1.4.1.3317.1.2.5 quagga_ospfd ! After restarting snmpd and quagga, a successful connection can be verified in the syslog and by querying the SNMP daemon: snmpd[12300]: [smux_accept] accepted fd 12 from 127.0.0.1:36255 snmpd[12300]: accepted smux peer: \ oid GNOME-PRODUCT-ZEBRA-MIB::ospfd, quagga-0.96.5 # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 Be warned that the current version (5.1.1) of the Net-SNMP daemon writes a line for every SNMP connect to the syslog which can lead to enormous log file sizes. If that is a problem you should consider to patch snmpd and comment out the troublesome 'snmp_log()' line in the function 'netsnmp_agent_check_packet()' in 'agent/snmp_agent.c'. quagga-1.2.4/doc/quagga.info-2000066400000000000000000003462461325323223500160300ustar00rootroot00000000000000This is quagga.info, produced by makeinfo version 6.3 from quagga.texi. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. 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. INFO-DIR-SECTION Routing Software: START-INFO-DIR-ENTRY * Quagga: (quagga). The Quagga Software Routing Suite END-INFO-DIR-ENTRY This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. This is Edition 1.2.4, last updated 19 February 2018 of 'The Quagga Manual', for Quagga Version 1.2.4. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. 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.  File: quagga.info, Node: MIB and command reference, Next: Handling SNMP Traps, Prev: SMUX configuration, Up: SNMP Support 18.4 MIB and command reference ============================== The following OID numbers are used for the interprocess communication of snmpd and the Quagga daemons with SMUX only. (OIDs below .iso.org.dod.internet.private.enterprises) zebra .1.3.6.1.4.1.3317.1.2.1 .gnome.gnomeProducts.zebra.zserv bgpd .1.3.6.1.4.1.3317.1.2.2 .gnome.gnomeProducts.zebra.bgpd ripd .1.3.6.1.4.1.3317.1.2.3 .gnome.gnomeProducts.zebra.ripd ospfd .1.3.6.1.4.1.3317.1.2.5 .gnome.gnomeProducts.zebra.ospfd ospf6d .1.3.6.1.4.1.3317.1.2.6 .gnome.gnomeProducts.zebra.ospf6d Sadly, SNMP has not been implemented in all daemons yet. The following OID numbers are used for querying the SNMP daemon by a client: zebra .1.3.6.1.2.1.4.24 .iso.org.dot.internet.mgmt.mib-2.ip.ipForward ospfd .1.3.6.1.2.1.14 .iso.org.dot.internet.mgmt.mib-2.ospf bgpd .1.3.6.1.2.1.15 .iso.org.dot.internet.mgmt.mib-2.bgp ripd .1.3.6.1.2.1.23 .iso.org.dot.internet.mgmt.mib-2.rip2 ospf6d .1.3.6.1.3.102 .iso.org.dod.internet.experimental.ospfv3 The following syntax is understood by the Quagga daemons for configuring SNMP using SMUX: -- Command: smux peer OID -- Command: no smux peer OID -- Command: smux peer OID PASSWORD -- Command: no smux peer OID PASSWORD Here is the syntax for using AgentX: -- Command: agentx -- Command: no agentx  File: quagga.info, Node: Handling SNMP Traps, Prev: MIB and command reference, Up: SNMP Support 18.5 Handling SNMP Traps ======================== To handle snmp traps make sure your snmp setup of quagga works correctly as described in the quagga documentation in *Note SNMP Support::. The BGP4 mib will send traps on peer up/down events. These should be visible in your snmp logs with a message similar to: 'snmpd[13733]: Got trap from peer on fd 14' To react on these traps they should be handled by a trapsink. Configure your trapsink by adding the following lines to '/etc/snmpd/snmpd.conf': # send traps to the snmptrapd on localhost trapsink localhost This will send all traps to an snmptrapd running on localhost. You can of course also use a dedicated management station to catch traps. Configure the snmptrapd daemon by adding the following line to '/etc/snmpd/snmptrapd.conf': traphandle .1.3.6.1.4.1.3317.1.2.2 /etc/snmp/snmptrap_handle.sh This will use the bash script '/etc/snmp/snmptrap_handle.sh' to handle the BGP4 traps. To add traps for other protocol daemons, lookup their appropriate OID from their mib. (For additional information about which traps are supported by your mib, lookup the mib on ). Make sure snmptrapd is started. The snmptrap_handle.sh script I personally use for handling BGP4 traps is below. You can of course do all sorts of things when handling traps, like sound a siren, have your display flash, etc., be creative ;). #!/bin/bash # routers name ROUTER=`hostname -s` #email address use to sent out notification EMAILADDR="john@doe.com" #email address used (allongside above) where warnings should be sent EMAILADDR_WARN="sms-john@doe.com" # type of notification TYPE="Notice" # local snmp community for getting AS belonging to peer COMMUNITY="" # if a peer address is in $WARN_PEERS a warning should be sent WARN_PEERS="192.0.2.1" # get stdin INPUT=`cat -` # get some vars from stdin uptime=`echo $INPUT | cut -d' ' -f5` peer=`echo $INPUT | cut -d' ' -f8 | \ sed -e 's/SNMPv2-SMI::mib-2.15.3.1.14.//g'` peerstate=`echo $INPUT | cut -d' ' -f13` errorcode=`echo $INPUT | cut -d' ' -f9 | sed -e 's/\"//g'` suberrorcode=`echo $INPUT | cut -d' ' -f10 | sed -e 's/\"//g'` remoteas=`snmpget -v2c -c $COMMUNITY \ localhost SNMPv2-SMI::mib-2.15.3.1.9.$peer \ | cut -d' ' -f4` WHOISINFO=`whois -h whois.ripe.net " -r AS$remoteas" | \ egrep '(as-name|descr)'` asname=`echo "$WHOISINFO" | grep "^as-name:" | \ sed -e 's/^as-name://g' -e 's/ //g' -e 's/^ //g' | uniq` asdescr=`echo "$WHOISINFO" | grep "^descr:" | \ sed -e 's/^descr://g' -e 's/ //g' -e 's/^ //g' | uniq` # if peer address is in $WARN_PEER, the email should also # be sent to $EMAILADDR_WARN for ip in $WARN_PEERS; do if [ "x$ip" == "x$peer" ]; then EMAILADDR="$EMAILADDR,$EMAILADDR_WARN" TYPE="WARNING" break fi done # convert peer state case "$peerstate" in 1) peerstate="Idle" ;; 2) peerstate="Connect" ;; 3) peerstate="Active" ;; 4) peerstate="Opensent" ;; 5) peerstate="Openconfirm" ;; 6) peerstate="Established" ;; *) peerstate="Unknown" ;; esac # get textual messages for errors case "$errorcode" in 00) error="No error" suberror="" ;; 01) error="Message Header Error" case "$suberrorcode" in 01) suberror="Connection Not Synchronized" ;; 02) suberror="Bad Message Length" ;; 03) suberror="Bad Message Type" ;; *) suberror="Unknown" ;; esac ;; 02) error="OPEN Message Error" case "$suberrorcode" in 01) suberror="Unsupported Version Number" ;; 02) suberror="Bad Peer AS" ;; 03) suberror="Bad BGP Identifier" ;; 04) suberror="Unsupported Optional Parameter" ;; 05) suberror="Authentication Failure" ;; 06) suberror="Unacceptable Hold Time" ;; *) suberror="Unknown" ;; esac ;; 03) error="UPDATE Message Error" case "$suberrorcode" in 01) suberror="Malformed Attribute List" ;; 02) suberror="Unrecognized Well-known Attribute" ;; 03) suberror="Missing Well-known Attribute" ;; 04) suberror="Attribute Flags Error" ;; 05) suberror="Attribute Length Error" ;; 06) suberror="Invalid ORIGIN Attribute" ;; 07) suberror="AS Routing Loop" ;; 08) suberror="Invalid NEXT_HOP Attribute" ;; 09) suberror="Optional Attribute Error" ;; 10) suberror="Invalid Network Field" ;; 11) suberror="Malformed AS_PATH" ;; *) suberror="Unknown" ;; esac ;; 04) error="Hold Timer Expired" suberror="" ;; 05) error="Finite State Machine Error" suberror="" ;; 06) error="Cease" case "$suberrorcode" in 01) suberror="Maximum Number of Prefixes Reached" ;; 02) suberror="Administratively Shutdown" ;; 03) suberror="Peer Unconfigured" ;; 04) suberror="Administratively Reset" ;; 05) suberror="Connection Rejected" ;; 06) suberror="Other Configuration Change" ;; 07) suberror="Connection collision resolution" ;; 08) suberror="Out of Resource" ;; 09) suberror="MAX" ;; *) suberror="Unknown" ;; esac ;; *) error="Unknown" suberror="" ;; esac # create textual message from errorcodes if [ "x$suberror" == "x" ]; then NOTIFY="$errorcode ($error)" else NOTIFY="$errorcode/$suberrorcode ($error/$suberror)" fi # form a decent subject SUBJECT="$TYPE: $ROUTER [bgp] $peer is $peerstate: $NOTIFY" # create the email body MAIL=`cat << EOF BGP notification on router $ROUTER. Peer: $peer AS: $remoteas New state: $peerstate Notification: $NOTIFY Info: $asname $asdescr Snmpd uptime: $uptime EOF` # mail the notification echo "$MAIL" | mail -s "$SUBJECT" $EMAILADDR  File: quagga.info, Node: Zebra Protocol, Next: Packet Binary Dump Format, Prev: SNMP Support, Up: Top Appendix A Zebra Protocol ************************* A.1 Overview of the Zebra Protocol ================================== Zebra Protocol is used by protocol daemons to communicate with the zebra daemon. Each protocol daemon may request and send information to and from the zebra daemon such as interface states, routing state, nexthop-validation, and so on. Protocol daemons may also install routes with zebra. The zebra daemon manages which route is installed into the forwarding table with the kernel. Zebra Protocol is a streaming protocol, with a common header. The protocol is versioned to allow for incompatible changes. Version 0 is implicitely versioned. Version 1 onwards has an explicit version field. Version 0 can be distinguished from all other versions by examining the 3rd byte of the header, which contains a marker value of 255 for all versions bar version 0. The marker byte corresponds to the command field in version 0, and the marker value is a reserved command in version 0. Version 0 is used by all versions of GNU Zebra as of this writing, and versions of Quagga up to and including Quagga 0.98. The version 1 header was introduced with Quagga 0.99.3. The version 3 header was introduced with Quagga 1.0.20160309. A.2 Zebra Protocol Definition ============================= A.2.1 Zebra Protocol Header (version 0) --------------------------------------- 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) | +-------------------------------+---------------+ A.2.2 Zebra Protocol Common Header (version 1 and 2) ---------------------------------------------------- 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) | Marker (1) | Version (1) | +-------------------------------+---------------+-------------+ | Command (2) | +-------------------------------+ A.2.3 Zebra Protocol Common Header (version 3) ---------------------------------------------- 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) | Marker (1) | Version (1) | +-------------------------------+---------------+-------------+ | VRF ID (2) | Command (2) | +-------------------------------+-----------------------------+ A.2.4 Zebra Protocol Header Field Definitions --------------------------------------------- 'Length' Total packet length including this header. The minimum length is 3 bytes for version 0 messages, 6 bytes for version 1 and 2 messages, and 8 bytes for version 3. 'Marker' Static marker with a value of 255 always. This is to allow version 0 Zserv headers (which do not include version explicitely) to be distinguished from versioned headers. Not present in version 0 messages. 'Version' Version number of the Zserv message. Clients should not continue processing messages past the version field for versions they do not recognise. Not present in version 0 messages. 'VRF ID' Virtual Routing/Forwarding context ID, to which the message applies. Only present from version 3 onwards. 'Command' The Zebra Protocol command. A.2.5 Zebra Protocol Commands ----------------------------- Command Value ----------------------------------------------------- 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  File: quagga.info, Node: Packet Binary Dump Format, Next: Command Index, Prev: Zebra Protocol, Up: Top Appendix B Packet Binary Dump Format ************************************ Quagga can dump routing protocol packet into file with a binary format (*note 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. 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP_ET, the common header format will contain an additional microsecond field (RFC6396 2011). 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Microsecond | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_STATE_CHANGE, and Address Family == IP (version 4) 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Where State is the value defined in RFC1771. If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_STATE_CHANGE, and Address Family == IP version 6 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_MESSAGE, and Address Family == IP (version 4) 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 | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 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 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 | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_ENTRY, and Address Family == IP (version 4) 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] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_ENTRY, and Address Family == IP version 6 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] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 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, 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] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The file specified in "File Name" contains all routing entries, which are in the format of "subtype == BGP4MP_ENTRY". Constants: /* type value */ #define MSG_PROTOCOL_BGP4MP 16 #define MSG_PROTOCOL_BGP4MP_ET 17 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 #define BGP4MP_ENTRY 2 #define BGP4MP_SNAPSHOT 3  File: quagga.info, Node: Command Index, Next: VTY Key Index, Prev: Packet Binary Dump Format, Up: Top Command Index ************* [index] * Menu: * access-class ACCESS-LIST: Basic Config Commands. (line 146) * access-list NAME deny IPV4-NETWORK: IP Access List. (line 7) * access-list NAME permit IPV4-NETWORK: IP Access List. (line 6) * admin-grp BANDWIDTH: Link Parameters Commands. (line 25) * agentx: MIB and command reference. (line 32) * aggregate-address A.B.C.D/M: Route Aggregation. (line 6) * aggregate-address A.B.C.D/M as-set: Route Aggregation. (line 9) * aggregate-address A.B.C.D/M summary-only: Route Aggregation. (line 13) * area <0-4294967295> authentication: OSPF area. (line 125) * area <0-4294967295> authentication message-digest: OSPF area. (line 132) * area <0-4294967295> export-list NAME: OSPF area. (line 84) * area <0-4294967295> filter-list prefix NAME in: OSPF area. (line 115) * area <0-4294967295> filter-list prefix NAME out: OSPF area. (line 116) * area <0-4294967295> import-list NAME: OSPF area. (line 107) * area <0-4294967295> range A.B.C.D/M: OSPF area. (line 7) * area <0-4294967295> shortcut: OSPF area. (line 54) * area <0-4294967295> stub: OSPF area. (line 61) * area <0-4294967295> stub no-summary: OSPF area. (line 73) * area <0-4294967295> virtual-link A.B.C.D: OSPF area. (line 49) * area A.B.C.D authentication: OSPF area. (line 124) * area A.B.C.D authentication message-digest: OSPF area. (line 131) * area A.B.C.D default-cost <0-16777215>: OSPF area. (line 79) * area A.B.C.D export-list NAME: OSPF area. (line 83) * area A.B.C.D filter-list prefix NAME in: OSPF area. (line 113) * area A.B.C.D filter-list prefix NAME out: OSPF area. (line 114) * area A.B.C.D import-list NAME: OSPF area. (line 106) * area A.B.C.D range A.B.C.D/M: OSPF area. (line 6) * area A.B.C.D range IPV4_PREFIX not-advertise: OSPF area. (line 27) * area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX: OSPF area. (line 33) * area A.B.C.D shortcut: OSPF area. (line 53) * area A.B.C.D stub: OSPF area. (line 60) * area A.B.C.D stub no-summary: OSPF area. (line 72) * area A.B.C.D virtual-link A.B.C.D: OSPF area. (line 48) * area-password [clear | md5] : ISIS router. (line 25) * auto-cost reference-bandwidth <1-4294967>: OSPF router. (line 161) * auto-cost reference-bandwidth COST: OSPF6 router. (line 49) * ava-bw BANDWIDTH: Link Parameters Commands. (line 40) * bandwidth <1-10000000>: Standard Commands. (line 30) * banner motd default: Basic Config Commands. (line 128) * bgp always-compare-med: BGP MED. (line 226) * bgp bestpath as-path confed: BGP decision process. (line 67) * bgp bestpath as-path multipath-relax: BGP decision process. (line 72) * bgp bestpath compare-routerid: BGP decision process. (line 78) * bgp cluster-id A.B.C.D: Route Reflector. (line 6) * bgp config-type cisco: Multiple instance. (line 19) * bgp config-type zebra: Multiple instance. (line 52) * bgp dampening <1-45> <1-20000> <1-20000> <1-255>: BGP route flap dampening. (line 6) * bgp deterministic-med: BGP MED. (line 207) * bgp multiple-instance: Multiple instance. (line 9) * bgp route-reflector allow-outbound-policy: Peer filtering. (line 17) * bgp router-id A.B.C.D: BGP router. (line 21) * call NAME: Route Map Call Command. (line 6) * call WORD: Commands for configuring a Route Server. (line 51) * capability opaque: Opaque LSA. (line 7) * clear ip bgp PEER: More Show IP BGP. (line 24) * clear ip bgp PEER soft in: More Show IP BGP. (line 27) * clear ip prefix-list: Clear counter of ip prefix-list. (line 6) * clear ip prefix-list NAME: Clear counter of ip prefix-list. (line 10) * clear ip prefix-list NAME A.B.C.D/M: Clear counter of ip prefix-list. (line 12) * clear zebra fpm stats: zebra Terminal Mode Commands. (line 40) * configure terminal: Terminal Mode Commands. (line 12) * continue: Route Map Exit Action Command. (line 7) * continue N: Route Map Exit Action Command. (line 11) * debug event: More Show IP BGP. (line 38) * debug isis adj-packets: Debugging ISIS. (line 6) * debug isis checksum-errors: Debugging ISIS. (line 10) * debug isis events: Debugging ISIS. (line 14) * debug isis local-updates: Debugging ISIS. (line 18) * debug isis packet-dump: Debugging ISIS. (line 22) * debug isis protocol-errors: Debugging ISIS. (line 26) * debug isis route-events: Debugging ISIS. (line 30) * debug isis snp-packets: Debugging ISIS. (line 34) * debug isis spf-events: Debugging ISIS. (line 38) * debug isis spf-statistics: Debugging ISIS. (line 39) * debug isis spf-triggers: Debugging ISIS. (line 40) * debug isis update-packets: Debugging ISIS. (line 47) * debug keepalive: More Show IP BGP. (line 42) * debug ospf event: Debugging OSPF. (line 26) * debug ospf ism: Debugging OSPF. (line 14) * debug ospf ism (status|events|timers): Debugging OSPF. (line 15) * debug ospf lsa: Debugging OSPF. (line 34) * debug ospf lsa (generate|flooding|refresh): Debugging OSPF. (line 35) * debug ospf nsm: Debugging OSPF. (line 20) * debug ospf nsm (status|events|timers): Debugging OSPF. (line 21) * debug ospf nssa: Debugging OSPF. (line 30) * debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]: Debugging OSPF. (line 6) * debug ospf te: Debugging OSPF. (line 40) * debug ospf zebra: Debugging OSPF. (line 44) * debug ospf zebra (interface|redistribute): Debugging OSPF. (line 45) * debug rip events: RIP Debug Commands. (line 8) * debug rip packet: RIP Debug Commands. (line 14) * debug rip zebra: RIP Debug Commands. (line 21) * debug ripng events: ripngd Terminal Mode Commands. (line 10) * debug ripng packet: ripngd Terminal Mode Commands. (line 12) * debug ripng zebra: ripngd Terminal Mode Commands. (line 14) * debug update: More Show IP BGP. (line 40) * default-information originate: How to Announce RIP route. (line 50) * default-information originate <1>: Redistribute routes to OSPF. (line 36) * default-information originate always: Redistribute routes to OSPF. (line 42) * default-information originate always metric <0-16777214>: Redistribute routes to OSPF. (line 43) * default-information originate always metric <0-16777214> metric-type (1|2): Redistribute routes to OSPF. (line 45) * default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 47) * default-information originate metric <0-16777214>: Redistribute routes to OSPF. (line 37) * default-information originate metric <0-16777214> metric-type (1|2): Redistribute routes to OSPF. (line 38) * default-information originate metric <0-16777214> metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 40) * default-metric <0-16777214>: Redistribute routes to OSPF. (line 64) * default-metric <1-16>: RIP Metric Manipulation. (line 10) * delay <0-16777215> [min <0-16777215> | max <0-16777215>]: Link Parameters Commands. (line 36) * delay-variation <0-16777215>: Link Parameters Commands. (line 37) * description DESCRIPTION ...: Standard Commands. (line 23) * distance <1-255>: RIP distance. (line 8) * distance <1-255> <1>: Redistribute routes to OSPF. (line 67) * distance <1-255> A.B.C.D/M: RIP distance. (line 12) * distance <1-255> A.B.C.D/M <1>: BGP distance. (line 14) * distance <1-255> A.B.C.D/M ACCESS-LIST: RIP distance. (line 17) * distance <1-255> A.B.C.D/M WORD: BGP distance. (line 15) * distance bgp <1-255> <1-255> <1-255>: BGP distance. (line 6) * distance ospf (intra-area|inter-area|external) <1-255>: Redistribute routes to OSPF. (line 70) * distribute-list ACCESS_LIST (in|out) IFNAME: ripngd Filtering Commands. (line 6) * distribute-list ACCESS_LIST DIRECT IFNAME: Filtering RIP Routes. (line 8) * distribute-list NAME out (kernel|connected|static|rip|ospf: Redistribute routes to OSPF. (line 56) * distribute-list prefix PREFIX_LIST (in|out) IFNAME: Filtering RIP Routes. (line 31) * domain-password [clear | md5] : ISIS router. (line 26) * dump bgp all PATH [INTERVAL]: Dump BGP packets and table. (line 6) * dump bgp all-et PATH [INTERVAL]: Dump BGP packets and table. (line 7) * dump bgp routes-mrt PATH: Dump BGP packets and table. (line 24) * dump bgp routes-mrt PATH INTERVAL: Dump BGP packets and table. (line 25) * dump bgp updates PATH [INTERVAL]: Dump BGP packets and table. (line 15) * dump bgp updates-et PATH [INTERVAL]: Dump BGP packets and table. (line 16) * enable: Link Parameters Commands. (line 18) * enable password PASSWORD: Basic Config Commands. (line 13) * exec-timeout MINUTE: Basic Config Commands. (line 134) * exec-timeout MINUTE SECOND: Basic Config Commands. (line 135) * flush_timer TIME: ripngd Configuration. (line 11) * hostname dynamic: ISIS router. (line 21) * hostname HOSTNAME: Basic Config Commands. (line 6) * interface IFNAME: Standard Commands. (line 6) * interface IFNAME area AREA: OSPF6 router. (line 11) * ip address ADDRESS/PREFIX: Standard Commands. (line 12) * ip address ADDRESS/PREFIX secondary: Standard Commands. (line 18) * ip as-path access-list WORD {permit|deny} LINE: AS Path Access List. (line 8) * ip community-list <1-99> {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 13) * ip community-list <100-199> {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 19) * ip community-list expanded NAME {permit|deny} LINE: BGP Community Lists. (line 29) * ip community-list NAME {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 24) * ip community-list standard NAME {permit|deny} COMMUNITY: BGP Community Lists. (line 19) * ip extcommunity-list expanded NAME {permit|deny} LINE: BGP Extended Community Lists. (line 20) * ip extcommunity-list standard NAME {permit|deny} EXTCOMMUNITY: BGP Extended Community Lists. (line 8) * ip mroute PREFIX NEXTHOP [DISTANCE]: Multicast RIB Commands. (line 70) * ip multicast rpf-lookup-mode MODE: Multicast RIB Commands. (line 18) * ip ospf area AREA [ADDR]: OSPF interface. (line 6) * ip ospf authentication message-digest: OSPF interface. (line 28) * ip ospf authentication-key AUTH_KEY: OSPF interface. (line 18) * ip ospf cost <1-65535>: OSPF interface. (line 56) * ip ospf dead-interval <1-65535>: OSPF interface. (line 61) * ip ospf dead-interval minimal hello-multiplier <2-20>: OSPF interface. (line 62) * ip ospf hello-interval <1-65535>: OSPF interface. (line 80) * ip ospf message-digest-key KEYID md5 KEY: OSPF interface. (line 44) * ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point): OSPF interface. (line 90) * ip ospf priority <0-255>: OSPF interface. (line 95) * ip ospf retransmit-interval <1-65535>: OSPF interface. (line 102) * ip ospf transmit-delay: OSPF interface. (line 108) * ip prefix-list NAME (permit|deny) PREFIX [le LEN] [ge LEN]: IP Prefix List. (line 15) * ip prefix-list NAME description DESC: ip prefix-list description. (line 6) * ip prefix-list NAME seq NUMBER (permit|deny) PREFIX [le LEN] [ge LEN]: IP Prefix List. (line 16) * ip prefix-list sequence-number: ip prefix-list sequential number control. (line 6) * ip protocol PROTOCOL route-map ROUTEMAP: zebra Route Filtering. (line 11) * ip rip authentication key-chain KEY-CHAIN: RIP Authentication. (line 42) * ip rip authentication mode md5: RIP Authentication. (line 28) * ip rip authentication mode text: RIP Authentication. (line 32) * ip rip authentication string STRING: RIP Authentication. (line 36) * ip rip receive version VERSION: RIP Version Control. (line 43) * ip rip send version VERSION: RIP Version Control. (line 32) * ip route NETWORK GATEWAY: Static Route Commands. (line 9) * ip route NETWORK GATEWAY DISTANCE: Static Route Commands. (line 35) * ip route NETWORK NETMASK GATEWAY: Static Route Commands. (line 24) * ip router isis WORD: ISIS interface. (line 6) * ip split-horizon: RIP Configuration. (line 69) * ipv6 address ADDRESS/PREFIX: Standard Commands. (line 13) * ipv6 nd adv-interval-option: Router Advertisement. (line 126) * ipv6 nd home-agent-config-flag: Router Advertisement. (line 101) * ipv6 nd home-agent-lifetime <0-65520>: Router Advertisement. (line 117) * ipv6 nd home-agent-preference <0-65535>: Router Advertisement. (line 109) * ipv6 nd managed-config-flag: Router Advertisement. (line 84) * ipv6 nd mtu <1-65535>: Router Advertisement. (line 141) * ipv6 nd other-config-flag: Router Advertisement. (line 93) * ipv6 nd prefix IPV6PREFIX [VALID-LIFETIME] [PREFERRED-LIFETIME] [off-link] [no-autoconfig] [router-address]: Router Advertisement. (line 12) * ipv6 nd ra-interval <1-1800>: Router Advertisement. (line 49) * ipv6 nd ra-interval msec <70-1800000>: Router Advertisement. (line 56) * ipv6 nd ra-lifetime <0-9000>: Router Advertisement. (line 63) * ipv6 nd reachable-time <1-3600000>: Router Advertisement. (line 75) * ipv6 nd router-preference (high|medium|low): Router Advertisement. (line 134) * ipv6 nd suppress-ra: Router Advertisement. (line 9) * ipv6 ospf6 cost COST: OSPF6 interface. (line 6) * ipv6 ospf6 dead-interval DEADINTERVAL: OSPF6 interface. (line 13) * ipv6 ospf6 hello-interval HELLOINTERVAL: OSPF6 interface. (line 10) * ipv6 ospf6 network (broadcast|point-to-point): OSPF6 interface. (line 25) * ipv6 ospf6 priority PRIORITY: OSPF6 interface. (line 19) * ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL: OSPF6 interface. (line 16) * ipv6 ospf6 transmit-delay TRANSMITDELAY: OSPF6 interface. (line 22) * ipv6 route NETWORK GATEWAY: Static Route Commands. (line 76) * ipv6 route NETWORK GATEWAY DISTANCE: Static Route Commands. (line 77) * is-type [level-1 | level-1-2 | level-2-only]: ISIS region. (line 6) * isis circuit-type [level-1 | level-1-2 | level-2]: ISIS interface. (line 12) * isis csnp-interval <1-600>: ISIS interface. (line 18) * isis csnp-interval <1-600> [level-1 | level-2]: ISIS interface. (line 19) * isis hello padding: ISIS interface. (line 25) * isis hello-interval <1-600>: ISIS interface. (line 28) * isis hello-interval <1-600> [level-1 | level-2]: ISIS interface. (line 29) * isis hello-multiplier <2-100>: ISIS interface. (line 35) * isis hello-multiplier <2-100> [level-1 | level-2]: ISIS interface. (line 36) * isis metric [<0-255> | <0-16777215>]: ISIS interface. (line 42) * isis metric [<0-255> | <0-16777215>] [level-1 | level-2]: ISIS interface. (line 43) * isis network point-to-point: ISIS interface. (line 51) * isis passive: ISIS interface. (line 55) * isis password [clear | md5] : ISIS interface. (line 59) * isis priority <0-127>: ISIS interface. (line 64) * isis priority <0-127> [level-1 | level-2]: ISIS interface. (line 65) * isis psnp-interval <1-120>: ISIS interface. (line 71) * isis psnp-interval <1-120> [level-1 | level-2]: ISIS interface. (line 72) * line vty: Basic Config Commands. (line 125) * link-detect: Standard Commands. (line 36) * link-params: Link Parameters Commands. (line 6) * list: Terminal Mode Commands. (line 23) * log commands: Basic Config Commands. (line 109) * log facility FACILITY: Basic Config Commands. (line 79) * log file FILENAME: Basic Config Commands. (line 39) * log file FILENAME LEVEL: Basic Config Commands. (line 40) * log monitor: Basic Config Commands. (line 66) * log monitor LEVEL: Basic Config Commands. (line 67) * log record-priority: Basic Config Commands. (line 85) * log stdout: Basic Config Commands. (line 27) * log stdout LEVEL: Basic Config Commands. (line 28) * log syslog: Basic Config Commands. (line 57) * log syslog LEVEL: Basic Config Commands. (line 58) * log timestamp precision <0-6>: Basic Config Commands. (line 95) * log trap LEVEL: Basic Config Commands. (line 16) * log-adjacency-changes: ISIS router. (line 32) * log-adjacency-changes [detail]: OSPF router. (line 71) * logmsg LEVEL MESSAGE: Terminal Mode Commands. (line 33) * lsp-gen-interval <1-120>: ISIS Timer. (line 6) * lsp-gen-interval [level-1 | level-2] <1-120>: ISIS Timer. (line 7) * lsp-refresh-interval <1-65235>: ISIS Timer. (line 13) * lsp-refresh-interval <1-65235> <1>: ISIS Timer. (line 20) * lsp-refresh-interval [level-1 | level-2] <1-65235>: ISIS Timer. (line 14) * lsp-refresh-interval [level-1 | level-2] <1-65235> <1>: ISIS Timer. (line 21) * match as-path AS_PATH: Route Map Match Command. (line 12) * match as-path WORD: Using AS Path in Route Map. (line 6) * match community COMMUNITY_LIST: Route Map Match Command. (line 21) * match community WORD: BGP Community in Route Map. (line 12) * match community WORD exact-match: BGP Community in Route Map. (line 13) * match extcommunity WORD: BGP Extended Communities in Route Map. (line 6) * match interface WORD: RIP route-map. (line 25) * match ip address ACCESS_LIST: Route Map Match Command. (line 6) * match ip address prefix-list WORD: RIP route-map. (line 38) * match ip address WORD: RIP route-map. (line 37) * match ip next-hop IPV4_ADDR: Route Map Match Command. (line 9) * match ip next-hop prefix-list WORD: RIP route-map. (line 42) * match ip next-hop WORD: RIP route-map. (line 41) * match local-preference METRIC: Route Map Match Command. (line 18) * match metric <0-4294967295>: RIP route-map. (line 47) * match metric METRIC: Route Map Match Command. (line 15) * match peer {A.B.C.D|X:X::X:X}: Commands for configuring a Route Server. (line 33) * max-bw BANDWIDTH: Link Parameters Commands. (line 22) * max-lsp-lifetime <360-65535>: ISIS Timer. (line 27) * max-lsp-lifetime [level-1 | level-2] <360-65535>: ISIS Timer. (line 28) * max-metric router-lsa administrative: OSPF router. (line 129) * max-metric router-lsa [on-startup|on-shutdown] <5-86400>: OSPF router. (line 127) * max-rsv-bw BANDWIDTH: Link Parameters Commands. (line 23) * metric <0-4294967295>: Link Parameters Commands. (line 21) * metric-style [narrow | transition | wide]: ISIS router. (line 36) * mpls-te inter-as area |as: OSPF Traffic Engineering. (line 16) * mpls-te on: OSPF Traffic Engineering. (line 6) * mpls-te on <1>: ISIS Traffic Engineering. (line 6) * mpls-te router-address : OSPF Traffic Engineering. (line 10) * mpls-te router-address <1>: ISIS Traffic Engineering. (line 10) * multicast: Standard Commands. (line 26) * neigbor {A.B.C.D|X.X::X.X|peer-group} route-map WORD {import|export}: Commands for configuring a Route Server. (line 27) * neighbor as <0-65535>: Link Parameters Commands. (line 54) * neighbor A.B.C.D: RIP Configuration. (line 33) * neighbor A.B.C.D route-server-client: Commands for configuring a Route Server. (line 10) * neighbor PEER default-originate: BGP Peer commands. (line 60) * neighbor PEER description ...: BGP Peer commands. (line 19) * neighbor PEER distribute-list NAME [in|out]: Peer filtering. (line 6) * neighbor PEER dont-capability-negotiate: Capability Negotiation. (line 50) * neighbor PEER ebgp-multihop: BGP Peer commands. (line 16) * neighbor PEER filter-list NAME [in|out]: Peer filtering. (line 12) * neighbor PEER interface IFNAME: BGP Peer commands. (line 32) * neighbor PEER local-as AS-NUMBER: BGP Peer commands. (line 80) * neighbor PEER local-as AS-NUMBER no-prepend: BGP Peer commands. (line 81) * neighbor PEER local-as AS-NUMBER no-prepend replace-as: BGP Peer commands. (line 82) * neighbor PEER maximum-prefix NUMBER: BGP Peer commands. (line 77) * neighbor PEER next-hop-self [all]: BGP Peer commands. (line 42) * neighbor PEER override-capability: Capability Negotiation. (line 66) * neighbor PEER peer-group WORD: BGP Peer Group. (line 9) * neighbor PEER port PORT: BGP Peer commands. (line 66) * neighbor PEER port PORT <1>: BGP Peer commands. (line 67) * neighbor PEER prefix-list NAME [in|out]: Peer filtering. (line 10) * neighbor PEER remote-as ASN: Defining Peer. (line 6) * neighbor PEER route-map NAME [in|out]: Peer filtering. (line 14) * neighbor PEER route-reflector-client: Route Reflector. (line 8) * neighbor PEER send-community: BGP Peer commands. (line 69) * neighbor PEER send-community <1>: BGP Peer commands. (line 70) * neighbor PEER shutdown: BGP Peer commands. (line 9) * neighbor PEER strict-capability-match: Capability Negotiation. (line 39) * neighbor PEER ttl-security hops NUMBER: BGP Peer commands. (line 101) * neighbor PEER update-source : BGP Peer commands. (line 49) * neighbor PEER version VERSION: BGP Peer commands. (line 23) * neighbor PEER weight WEIGHT: BGP Peer commands. (line 72) * neighbor PEER-GROUP route-server-client: Commands for configuring a Route Server. (line 9) * neighbor WORD peer-group: BGP Peer Group. (line 6) * neighbor X:X::X:X route-server-client: Commands for configuring a Route Server. (line 11) * net XX.XXXX. ... .XXX.XX: ISIS router. (line 17) * network A.B.C.D/M: BGP route. (line 6) * network A.B.C.D/M area <0-4294967295>: OSPF router. (line 173) * network A.B.C.D/M area A.B.C.D: OSPF router. (line 172) * network IFNAME: RIP Configuration. (line 26) * network IFNAME <1>: ripngd Configuration. (line 17) * network NETWORK: RIP Configuration. (line 14) * network NETWORK <1>: ripngd Configuration. (line 14) * no agentx: MIB and command reference. (line 33) * no aggregate-address A.B.C.D/M: Route Aggregation. (line 17) * no area <0-4294967295> authentication: OSPF area. (line 127) * no area <0-4294967295> export-list NAME: OSPF area. (line 86) * no area <0-4294967295> filter-list prefix NAME in: OSPF area. (line 119) * no area <0-4294967295> filter-list prefix NAME out: OSPF area. (line 120) * no area <0-4294967295> import-list NAME: OSPF area. (line 109) * no area <0-4294967295> range A.B.C.D/M: OSPF area. (line 9) * no area <0-4294967295> shortcut: OSPF area. (line 56) * no area <0-4294967295> stub: OSPF area. (line 63) * no area <0-4294967295> stub no-summary: OSPF area. (line 75) * no area <0-4294967295> virtual-link A.B.C.D: OSPF area. (line 51) * no area A.B.C.D authentication: OSPF area. (line 126) * no area A.B.C.D default-cost <0-16777215>: OSPF area. (line 80) * no area A.B.C.D export-list NAME: OSPF area. (line 85) * no area A.B.C.D filter-list prefix NAME in: OSPF area. (line 117) * no area A.B.C.D filter-list prefix NAME out: OSPF area. (line 118) * no area A.B.C.D import-list NAME: OSPF area. (line 108) * no area A.B.C.D range A.B.C.D/M: OSPF area. (line 8) * no area A.B.C.D range IPV4_PREFIX not-advertise: OSPF area. (line 28) * no area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX: OSPF area. (line 34) * no area A.B.C.D shortcut: OSPF area. (line 55) * no area A.B.C.D stub: OSPF area. (line 62) * no area A.B.C.D stub no-summary: OSPF area. (line 74) * no area A.B.C.D virtual-link A.B.C.D: OSPF area. (line 50) * no area-password: ISIS router. (line 27) * no auto-cost reference-bandwidth: OSPF router. (line 162) * no auto-cost reference-bandwidth <1>: OSPF6 router. (line 50) * no bandwidth <1-10000000>: Standard Commands. (line 31) * no banner motd: Basic Config Commands. (line 131) * no bgp multiple-instance: Multiple instance. (line 13) * no capability opaque: Opaque LSA. (line 9) * no debug event: More Show IP BGP. (line 44) * no debug isis adj-packets: Debugging ISIS. (line 7) * no debug isis checksum-errors: Debugging ISIS. (line 11) * no debug isis events: Debugging ISIS. (line 15) * no debug isis local-updates: Debugging ISIS. (line 19) * no debug isis packet-dump: Debugging ISIS. (line 23) * no debug isis protocol-errors: Debugging ISIS. (line 27) * no debug isis route-events: Debugging ISIS. (line 31) * no debug isis snp-packets: Debugging ISIS. (line 35) * no debug isis spf-events: Debugging ISIS. (line 41) * no debug isis spf-statistics: Debugging ISIS. (line 42) * no debug isis spf-triggers: Debugging ISIS. (line 43) * no debug isis update-packets: Debugging ISIS. (line 48) * no debug keepalive: More Show IP BGP. (line 48) * no debug ospf event: Debugging OSPF. (line 27) * no debug ospf ism: Debugging OSPF. (line 16) * no debug ospf ism (status|events|timers): Debugging OSPF. (line 17) * no debug ospf lsa: Debugging OSPF. (line 36) * no debug ospf lsa (generate|flooding|refresh): Debugging OSPF. (line 37) * no debug ospf nsm: Debugging OSPF. (line 22) * no debug ospf nsm (status|events|timers): Debugging OSPF. (line 23) * no debug ospf nssa: Debugging OSPF. (line 31) * no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]: Debugging OSPF. (line 9) * no debug ospf te: Debugging OSPF. (line 41) * no debug ospf zebra: Debugging OSPF. (line 46) * no debug ospf zebra (interface|redistribute): Debugging OSPF. (line 47) * no debug update: More Show IP BGP. (line 46) * no default-information originate: Redistribute routes to OSPF. (line 49) * no default-metric: Redistribute routes to OSPF. (line 65) * no default-metric <1-16>: RIP Metric Manipulation. (line 11) * no distance <1-255>: RIP distance. (line 9) * no distance <1-255> <1>: Redistribute routes to OSPF. (line 68) * no distance <1-255> A.B.C.D/M: RIP distance. (line 13) * no distance <1-255> A.B.C.D/M ACCESS-LIST: RIP distance. (line 18) * no distance ospf: Redistribute routes to OSPF. (line 71) * no distribute-list NAME out (kernel|connected|static|rip|ospf: Redistribute routes to OSPF. (line 58) * no domain-password: ISIS router. (line 28) * no dump bgp all [PATH] [INTERVAL]: Dump BGP packets and table. (line 8) * no dump bgp route-mrt [PATH] [INTERVAL]: Dump BGP packets and table. (line 26) * no dump bgp updates [PATH] [INTERVAL]: Dump BGP packets and table. (line 17) * no exec-timeout: Basic Config Commands. (line 142) * no hostname dynamic: ISIS router. (line 22) * no ip address ADDRESS/PREFIX: Standard Commands. (line 14) * no ip address ADDRESS/PREFIX secondary: Standard Commands. (line 19) * no ip as-path access-list WORD: AS Path Access List. (line 11) * no ip as-path access-list WORD {permit|deny} LINE: AS Path Access List. (line 12) * no ip community-list expanded NAME: BGP Community Lists. (line 36) * no ip community-list NAME: BGP Community Lists. (line 34) * no ip community-list standard NAME: BGP Community Lists. (line 35) * no ip extcommunity-list expanded NAME: BGP Extended Community Lists. (line 28) * no ip extcommunity-list NAME: BGP Extended Community Lists. (line 26) * no ip extcommunity-list standard NAME: BGP Extended Community Lists. (line 27) * no ip mroute PREFIX NEXTHOP [DISTANCE]: Multicast RIB Commands. (line 71) * no ip multicast rpf-lookup-mode [MODE]: Multicast RIB Commands. (line 19) * no ip ospf area [ADDR]: OSPF interface. (line 7) * no ip ospf authentication-key: OSPF interface. (line 19) * no ip ospf cost: OSPF interface. (line 57) * no ip ospf dead-interval: OSPF interface. (line 64) * no ip ospf hello-interval: OSPF interface. (line 81) * no ip ospf message-digest-key: OSPF interface. (line 45) * no ip ospf network: OSPF interface. (line 92) * no ip ospf priority: OSPF interface. (line 96) * no ip ospf retransmit interval: OSPF interface. (line 103) * no ip ospf transmit-delay: OSPF interface. (line 109) * no ip prefix-list NAME: IP Prefix List. (line 64) * no ip prefix-list NAME description [DESC]: ip prefix-list description. (line 10) * no ip prefix-list sequence-number: ip prefix-list sequential number control. (line 10) * no ip rip authentication key-chain KEY-CHAIN: RIP Authentication. (line 43) * no ip rip authentication mode md5: RIP Authentication. (line 29) * no ip rip authentication mode text: RIP Authentication. (line 33) * no ip rip authentication string STRING: RIP Authentication. (line 37) * no ip router isis WORD: ISIS interface. (line 7) * no ip split-horizon: RIP Configuration. (line 70) * no ipv6 address ADDRESS/PREFIX: Standard Commands. (line 15) * no ipv6 nd adv-interval-option: Router Advertisement. (line 127) * no ipv6 nd home-agent-config-flag: Router Advertisement. (line 102) * no ipv6 nd home-agent-lifetime [<0-65520>]: Router Advertisement. (line 118) * no ipv6 nd home-agent-preference [<0-65535>]: Router Advertisement. (line 110) * no ipv6 nd managed-config-flag: Router Advertisement. (line 85) * no ipv6 nd mtu [<1-65535>]: Router Advertisement. (line 142) * no ipv6 nd other-config-flag: Router Advertisement. (line 94) * no ipv6 nd ra-interval [<1-1800>]: Router Advertisement. (line 50) * no ipv6 nd ra-interval [msec <70-1800000>]: Router Advertisement. (line 57) * no ipv6 nd ra-lifetime [<0-9000>]: Router Advertisement. (line 64) * no ipv6 nd reachable-time [<1-3600000>]: Router Advertisement. (line 76) * no ipv6 nd router-preference [(high|medium|low)]: Router Advertisement. (line 135) * no ipv6 nd suppress-ra: Router Advertisement. (line 6) * no is-type: ISIS region. (line 7) * no isis circuit-type: ISIS interface. (line 13) * no isis csnp-interval: ISIS interface. (line 20) * no isis csnp-interval [level-1 | level-2]: ISIS interface. (line 21) * no isis hello-interval: ISIS interface. (line 30) * no isis hello-interval [level-1 | level-2]: ISIS interface. (line 31) * no isis hello-multiplier: ISIS interface. (line 37) * no isis hello-multiplier [level-1 | level-2]: ISIS interface. (line 38) * no isis metric: ISIS interface. (line 45) * no isis metric [level-1 | level-2]: ISIS interface. (line 46) * no isis network point-to-point: ISIS interface. (line 52) * no isis passive: ISIS interface. (line 56) * no isis password: ISIS interface. (line 60) * no isis priority: ISIS interface. (line 66) * no isis priority [level-1 | level-2]: ISIS interface. (line 67) * no isis psnp-interval: ISIS interface. (line 73) * no isis psnp-interval [level-1 | level-2]: ISIS interface. (line 74) * no link-detect: Standard Commands. (line 37) * no link-param: Link Parameters Commands. (line 7) * no log facility: Basic Config Commands. (line 80) * no log file: Basic Config Commands. (line 41) * no log monitor: Basic Config Commands. (line 68) * no log record-priority: Basic Config Commands. (line 86) * no log stdout: Basic Config Commands. (line 29) * no log syslog: Basic Config Commands. (line 59) * no log timestamp precision: Basic Config Commands. (line 96) * no log trap: Basic Config Commands. (line 17) * no log-adjacency-changes: ISIS router. (line 33) * no log-adjacency-changes [detail]: OSPF router. (line 72) * no lsp-gen-interval: ISIS Timer. (line 8) * no lsp-gen-interval [level-1 | level-2]: ISIS Timer. (line 9) * no lsp-refresh-interval: ISIS Timer. (line 15) * no lsp-refresh-interval <1>: ISIS Timer. (line 22) * no lsp-refresh-interval [level-1 | level-2]: ISIS Timer. (line 16) * no lsp-refresh-interval [level-1 | level-2] <1>: ISIS Timer. (line 23) * no max-lsp-lifetime: ISIS Timer. (line 29) * no max-lsp-lifetime [level-1 | level-2]: ISIS Timer. (line 30) * no max-metric router-lsa [on-startup|on-shutdown|administrative]: OSPF router. (line 130) * no metric-style: ISIS router. (line 37) * no mpls-te: OSPF Traffic Engineering. (line 7) * no mpls-te <1>: OSPF Traffic Engineering. (line 11) * no mpls-te <2>: ISIS Traffic Engineering. (line 7) * no mpls-te inter-as: OSPF Traffic Engineering. (line 17) * no mpls-te router-address: ISIS Traffic Engineering. (line 11) * no multicast: Standard Commands. (line 27) * no neighbor: Link Parameters Commands. (line 55) * no neighbor A.B.C.D: RIP Configuration. (line 34) * no neighbor PEER default-originate: BGP Peer commands. (line 61) * no neighbor PEER description ...: BGP Peer commands. (line 20) * no neighbor PEER dont-capability-negotiate: Capability Negotiation. (line 51) * no neighbor PEER ebgp-multihop: BGP Peer commands. (line 17) * no neighbor PEER interface IFNAME: BGP Peer commands. (line 33) * no neighbor PEER local-as: BGP Peer commands. (line 83) * no neighbor PEER maximum-prefix NUMBER: BGP Peer commands. (line 78) * no neighbor PEER next-hop-self [all]: BGP Peer commands. (line 43) * no neighbor PEER override-capability: Capability Negotiation. (line 67) * no neighbor PEER route-reflector-client: Route Reflector. (line 9) * no neighbor PEER shutdown: BGP Peer commands. (line 10) * no neighbor PEER strict-capability-match: Capability Negotiation. (line 40) * no neighbor PEER ttl-security hops NUMBER: BGP Peer commands. (line 102) * no neighbor PEER update-source: BGP Peer commands. (line 50) * no neighbor PEER weight WEIGHT: BGP Peer commands. (line 73) * no net XX.XXXX. ... .XXX.XX: ISIS router. (line 18) * no network A.B.C.D/M: BGP route. (line 15) * no network A.B.C.D/M area <0-4294967295>: OSPF router. (line 175) * no network A.B.C.D/M area A.B.C.D: OSPF router. (line 174) * no network IFNAME: RIP Configuration. (line 27) * no network NETWORK: RIP Configuration. (line 15) * no ospf abr-type TYPE: OSPF router. (line 26) * no ospf opaque-lsa: Opaque LSA. (line 8) * no ospf rfc1583compatibility: OSPF router. (line 61) * no ospf router-id: OSPF router. (line 16) * no passive-interface IFNAME: RIP Configuration. (line 57) * no passive-interface INTERFACE: OSPF router. (line 78) * no pce address: Router Information. (line 12) * no pce domain as <0-65535>: Router Information. (line 14) * no pce flag: Router Information. (line 18) * no pce neighbor as <0-65535>: Router Information. (line 16) * no pce scope: Router Information. (line 20) * no redistribute (kernel|connected|static|rip|bgp): Redistribute routes to OSPF. (line 21) * no redistribute bgp: How to Announce RIP route. (line 43) * no redistribute connected: How to Announce RIP route. (line 25) * no redistribute kernel: How to Announce RIP route. (line 9) * no redistribute ospf: How to Announce RIP route. (line 35) * no redistribute static: How to Announce RIP route. (line 17) * no route A.B.C.D/M: How to Announce RIP route. (line 53) * no router bgp ASN: BGP router. (line 18) * no router isis WORD: ISIS router. (line 10) * no router ospf: OSPF router. (line 10) * no router rip: RIP Configuration. (line 11) * no router-info: Router Information. (line 7) * no set-overload-bit: ISIS router. (line 44) * no shutdown: Standard Commands. (line 9) * no smux peer OID: MIB and command reference. (line 26) * no smux peer OID PASSWORD: MIB and command reference. (line 29) * no spf-interval: ISIS Timer. (line 36) * no spf-interval [level-1 | level-2]: ISIS Timer. (line 37) * no timers basic: RIP Timers. (line 30) * no timers throttle spf: OSPF router. (line 90) * no timers throttle spf <1>: OSPF6 router. (line 17) * no version: RIP Version Control. (line 29) * offset-list ACCESS-LIST (in|out): RIP Metric Manipulation. (line 19) * offset-list ACCESS-LIST (in|out) IFNAME: RIP Metric Manipulation. (line 20) * on-match goto N: Route Map Exit Action Command. (line 10) * on-match next: Route Map Exit Action Command. (line 6) * ospf abr-type TYPE: OSPF router. (line 25) * ospf opaque-lsa: Opaque LSA. (line 6) * ospf rfc1583compatibility: OSPF router. (line 60) * ospf router-id A.B.C.D: OSPF router. (line 15) * packet-loss PERCENTAGE: Link Parameters Commands. (line 38) * passive-interface (IFNAME|default): RIP Configuration. (line 56) * passive-interface INTERFACE: OSPF router. (line 77) * password PASSWORD: Basic Config Commands. (line 9) * pce address : Router Information. (line 11) * pce domain as <0-65535>: Router Information. (line 13) * pce flag BITPATTERN: Router Information. (line 17) * pce neighbor as <0-65535>: Router Information. (line 15) * pce scope BITPATTERN: Router Information. (line 19) * redistribute (kernel|connected|static|rip|bgp): Redistribute routes to OSPF. (line 6) * redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>: Redistribute routes to OSPF. (line 13) * redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD: Redistribute routes to OSPF. (line 15) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2): Redistribute routes to OSPF. (line 9) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>: Redistribute routes to OSPF. (line 17) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD: Redistribute routes to OSPF. (line 19) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 11) * redistribute (kernel|connected|static|rip|bgp) ROUTE-MAP: Redistribute routes to OSPF. (line 7) * redistribute bgp: How to Announce RIP route. (line 40) * redistribute bgp metric <0-16>: How to Announce RIP route. (line 41) * redistribute bgp route-map ROUTE-MAP: How to Announce RIP route. (line 42) * redistribute connected: How to Announce RIP route. (line 22) * redistribute connected <1>: Redistribute routes to OSPF6. (line 7) * redistribute connected <2>: Redistribute to BGP. (line 12) * redistribute connected metric <0-16>: How to Announce RIP route. (line 23) * redistribute connected route-map ROUTE-MAP: How to Announce RIP route. (line 24) * redistribute kernel: How to Announce RIP route. (line 6) * redistribute kernel <1>: Redistribute to BGP. (line 6) * redistribute kernel metric <0-16>: How to Announce RIP route. (line 7) * redistribute kernel route-map ROUTE-MAP: How to Announce RIP route. (line 8) * redistribute ospf: How to Announce RIP route. (line 32) * redistribute ospf <1>: Redistribute to BGP. (line 18) * redistribute ospf metric <0-16>: How to Announce RIP route. (line 33) * redistribute ospf route-map ROUTE-MAP: How to Announce RIP route. (line 34) * redistribute rip: Redistribute to BGP. (line 15) * redistribute ripng: Redistribute routes to OSPF6. (line 8) * redistribute static: How to Announce RIP route. (line 14) * redistribute static <1>: Redistribute routes to OSPF6. (line 6) * redistribute static <2>: Redistribute to BGP. (line 9) * redistribute static metric <0-16>: How to Announce RIP route. (line 15) * redistribute static route-map ROUTE-MAP: How to Announce RIP route. (line 16) * res-bw BANDWIDTH: Link Parameters Commands. (line 39) * route A.B.C.D/M: How to Announce RIP route. (line 52) * route NETWORK: ripngd Configuration. (line 20) * route-map ROUTE-MAP-NAME (permit|deny) ORDER: Route Map Command. (line 6) * router bgp AS-NUMBER: BGP instance and view. (line 10) * router bgp AS-NUMBER view NAME: BGP instance and view. (line 27) * router bgp ASN: BGP router. (line 12) * router isis WORD: ISIS router. (line 9) * router ospf: OSPF router. (line 9) * router ospf6: OSPF6 router. (line 6) * router rip: RIP Configuration. (line 6) * router ripng: ripngd Configuration. (line 8) * router zebra: ripngd Configuration. (line 23) * router-id A.B.C.D: OSPF6 router. (line 8) * router-info [as | area ]: Router Information. (line 6) * service advanced-vty: Basic Config Commands. (line 118) * service integrated-vtysh-config: VTY shell integrated configuration. (line 6) * service password-encryption: Basic Config Commands. (line 115) * service terminal-length <0-512>: Basic Config Commands. (line 121) * set as-path prepend AS-PATH: Using AS Path in Route Map. (line 8) * set as-path prepend AS_PATH: Route Map Set Command. (line 18) * set as-path prepend last-as NUM: Using AS Path in Route Map. (line 11) * set comm-list WORD delete: BGP Community in Route Map. (line 33) * set community COMMUNITY: BGP Community in Route Map. (line 22) * set community COMMUNITY <1>: Route Map Set Command. (line 21) * set community COMMUNITY additive: BGP Community in Route Map. (line 23) * set community none: BGP Community in Route Map. (line 21) * set extcommunity rt EXTCOMMUNITY: BGP Extended Communities in Route Map. (line 8) * set extcommunity soo EXTCOMMUNITY: BGP Extended Communities in Route Map. (line 11) * set ip next-hop A.B.C.D: RIP route-map. (line 52) * set ip next-hop IPV4_ADDRESS: Route Map Set Command. (line 6) * set ipv6 next-hop global IPV6_ADDRESS: Route Map Set Command. (line 24) * set ipv6 next-hop local IPV6_ADDRESS: Route Map Set Command. (line 27) * set local-preference LOCAL_PREF: Route Map Set Command. (line 9) * set metric <0-4294967295>: RIP route-map. (line 57) * set metric METRIC: Route Map Set Command. (line 15) * set src ADDRESS: zebra Route Filtering. (line 16) * set weight WEIGHT: Route Map Set Command. (line 12) * set-overload-bit: ISIS router. (line 43) * show bgp ipv4 encap summary: BGP Address Family. (line 23) * show bgp ipv4 vpn summary: BGP Address Family. (line 24) * show bgp ipv6 encap summary: BGP Address Family. (line 25) * show bgp ipv6 vpn summary: BGP Address Family. (line 26) * show debug: More Show IP BGP. (line 36) * show debugging isis: Debugging ISIS. (line 51) * show debugging ospf: Debugging OSPF. (line 50) * show debugging rip: RIP Debug Commands. (line 28) * show debugging ripng: ripngd Terminal Mode Commands. (line 8) * show interface: zebra Terminal Mode Commands. (line 20) * show ip bgp: Show IP BGP. (line 6) * show ip bgp A.B.C.D: Show IP BGP. (line 7) * show ip bgp community: Display BGP Routes by Community. (line 10) * show ip bgp community COMMUNITY: Display BGP Routes by Community. (line 11) * show ip bgp community COMMUNITY <1>: More Show IP BGP. (line 10) * show ip bgp community COMMUNITY exact-match: Display BGP Routes by Community. (line 12) * show ip bgp community COMMUNITY exact-match <1>: More Show IP BGP. (line 11) * show ip bgp community-list WORD: Display BGP Routes by Community. (line 19) * show ip bgp community-list WORD <1>: More Show IP BGP. (line 15) * show ip bgp community-list WORD exact-match: Display BGP Routes by Community. (line 20) * show ip bgp community-list WORD exact-match <1>: More Show IP BGP. (line 16) * show ip bgp dampened-paths: More Show IP BGP. (line 30) * show ip bgp encap all: BGP Address Family. (line 18) * show ip bgp flap-statistics: More Show IP BGP. (line 33) * show ip bgp neighbor [PEER]: More Show IP BGP. (line 22) * show ip bgp regexp LINE: Display BGP Routes by AS Path. (line 9) * show ip bgp regexp LINE <1>: More Show IP BGP. (line 6) * show ip bgp summary: More Show IP BGP. (line 20) * show ip bgp view NAME: Viewing the view. (line 8) * show ip bgp vpnv4 all: BGP Address Family. (line 14) * show ip bgp X:X::X:X: Show IP BGP. (line 8) * show ip community-list: BGP Community Lists. (line 41) * show ip community-list NAME: BGP Community Lists. (line 42) * show ip extcommunity-list: BGP Extended Community Lists. (line 34) * show ip extcommunity-list NAME: BGP Extended Community Lists. (line 35) * show ip ospf: Showing OSPF information. (line 6) * show ip ospf database: Showing OSPF information. (line 19) * show ip ospf database (opaque-link|opaque-area|opaque-external): Opaque LSA. (line 15) * show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER: Opaque LSA. (line 22) * show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID: Opaque LSA. (line 17) * show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER: Opaque LSA. (line 19) * show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate: Opaque LSA. (line 25) * show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate: Opaque LSA. (line 28) * show ip ospf database ... adv-router ADV-ROUTER: Showing OSPF information. (line 28) * show ip ospf database ... LINK-STATE-ID: Showing OSPF information. (line 25) * show ip ospf database ... LINK-STATE-ID adv-router ADV-ROUTER: Showing OSPF information. (line 26) * show ip ospf database ... LINK-STATE-ID self-originate: Showing OSPF information. (line 29) * show ip ospf database ... self-originate: Showing OSPF information. (line 30) * show ip ospf database asbr-router: Showing OSPF information. (line 23) * show ip ospf database asbr-summary: Showing OSPF information. (line 20) * show ip ospf database external: Showing OSPF information. (line 21) * show ip ospf database max-age: Showing OSPF information. (line 32) * show ip ospf database network: Showing OSPF information. (line 22) * show ip ospf database self-originate: Showing OSPF information. (line 34) * show ip ospf database summary: Showing OSPF information. (line 24) * show ip ospf interface [INTERFACE]: Showing OSPF information. (line 10) * show ip ospf mpls-te interface: OSPF Traffic Engineering. (line 24) * show ip ospf mpls-te interface INTERFACE: OSPF Traffic Engineering. (line 25) * show ip ospf mpls-te router: OSPF Traffic Engineering. (line 29) * show ip ospf neighbor: Showing OSPF information. (line 14) * show ip ospf neighbor detail: Showing OSPF information. (line 16) * show ip ospf neighbor INTERFACE: Showing OSPF information. (line 15) * show ip ospf neighbor INTERFACE detail: Showing OSPF information. (line 17) * show ip ospf route: Showing OSPF information. (line 36) * show ip ospf router-info: Router Information. (line 30) * show ip ospf router-info pce: Router Information. (line 32) * show ip prefix-list: Showing ip prefix-list. (line 6) * show ip prefix-list detail: Showing ip prefix-list. (line 29) * show ip prefix-list detail NAME: Showing ip prefix-list. (line 30) * show ip prefix-list NAME: Showing ip prefix-list. (line 9) * show ip prefix-list NAME A.B.C.D/M: Showing ip prefix-list. (line 16) * show ip prefix-list NAME A.B.C.D/M first-match: Showing ip prefix-list. (line 24) * show ip prefix-list NAME A.B.C.D/M longer: Showing ip prefix-list. (line 22) * show ip prefix-list NAME seq NUM: Showing ip prefix-list. (line 12) * show ip prefix-list summary: Showing ip prefix-list. (line 26) * show ip prefix-list summary NAME: Showing ip prefix-list. (line 27) * show ip prefix-list [NAME]: zebra Terminal Mode Commands. (line 22) * show ip protocol: zebra Terminal Mode Commands. (line 26) * show ip rip: Show RIP Information. (line 8) * show ip rip status: Show RIP Information. (line 16) * show ip ripng: ripngd Terminal Mode Commands. (line 6) * show ip route: zebra Terminal Mode Commands. (line 6) * show ip route isis: Showing ISIS information. (line 36) * show ip rpf: Multicast RIB Commands. (line 64) * show ip rpf ADDR: Multicast RIB Commands. (line 50) * show ipforward: zebra Terminal Mode Commands. (line 28) * show ipv6 bgp encap all: BGP Address Family. (line 19) * show ipv6 bgp vpn all: BGP Address Family. (line 15) * show ipv6 ospf6 database: Showing OSPF6 information. (line 10) * show ipv6 ospf6 interface: Showing OSPF6 information. (line 14) * show ipv6 ospf6 neighbor: Showing OSPF6 information. (line 17) * show ipv6 ospf6 request-list A.B.C.D: Showing OSPF6 information. (line 20) * show ipv6 ospf6 [INSTANCE_ID]: Showing OSPF6 information. (line 6) * show ipv6 route: zebra Terminal Mode Commands. (line 18) * show ipv6 route ospf6: Showing OSPF6 information. (line 23) * show ipv6forward: zebra Terminal Mode Commands. (line 33) * show isis database: Showing ISIS information. (line 24) * show isis database [detail]: Showing ISIS information. (line 26) * show isis database detail : Showing ISIS information. (line 27) * show isis database [detail]: Showing ISIS information. (line 25) * show isis hostname: Showing ISIS information. (line 9) * show isis interface: Showing ISIS information. (line 12) * show isis interface : Showing ISIS information. (line 14) * show isis interface detail: Showing ISIS information. (line 13) * show isis mpls-te interface: ISIS Traffic Engineering. (line 14) * show isis mpls-te interface INTERFACE: ISIS Traffic Engineering. (line 15) * show isis mpls-te router: ISIS Traffic Engineering. (line 19) * show isis neighbor: Showing ISIS information. (line 18) * show isis neighbor : Showing ISIS information. (line 19) * show isis neighbor detail: Showing ISIS information. (line 20) * show isis summary: Showing ISIS information. (line 6) * show isis topology: Showing ISIS information. (line 31) * show isis topology [level-1|level-2]: Showing ISIS information. (line 32) * show logging: Terminal Mode Commands. (line 29) * show route-map [NAME]: zebra Terminal Mode Commands. (line 24) * show version: Terminal Mode Commands. (line 26) * show zebra fpm stats: zebra Terminal Mode Commands. (line 36) * shutdown: Standard Commands. (line 8) * smux peer OID: MIB and command reference. (line 25) * smux peer OID PASSWORD: MIB and command reference. (line 28) * spf-interval <1-120>: ISIS Timer. (line 34) * spf-interval [level-1 | level-2] <1-120>: ISIS Timer. (line 35) * table TABLENO: Static Route Commands. (line 80) * terminal length <0-512>: Terminal Mode Commands. (line 16) * timers basic UPDATE TIMEOUT GARBAGE: RIP Timers. (line 6) * timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME: OSPF router. (line 88) * timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME <1>: OSPF6 router. (line 15) * unrsv-bw <0-7> BANDWIDTH: Link Parameters Commands. (line 24) * use-bw BANDWIDTH: Link Parameters Commands. (line 41) * username USERNAME nopassword: VTY shell username. (line 6) * version VERSION: RIP Version Control. (line 19) * who: Terminal Mode Commands. (line 20) * write file: Terminal Mode Commands. (line 9) * write terminal: Terminal Mode Commands. (line 6)  File: quagga.info, Node: VTY Key Index, Next: Index, Prev: Command Index, Up: Top VTY Key Index ************* [index] * Menu: * : CLI Advanced Commands. (line 27) * C-a: CLI Movement Commands. (line 24) * C-b: CLI Movement Commands. (line 15) * C-c: CLI Advanced Commands. (line 10) * C-d: CLI Editing Commands. (line 14) * C-e: CLI Movement Commands. (line 27) * C-f: CLI Movement Commands. (line 11) * C-h: CLI Editing Commands. (line 11) * C-k: CLI Editing Commands. (line 23) * C-n: CLI Advanced Commands. (line 17) * C-p: CLI Advanced Commands. (line 21) * C-t: CLI Editing Commands. (line 29) * C-u: CLI Editing Commands. (line 26) * C-v: CLI Editing Commands. (line 32) * C-w: CLI Editing Commands. (line 20) * C-z: CLI Advanced Commands. (line 13) * : CLI Editing Commands. (line 11) * : CLI Advanced Commands. (line 17) * : CLI Movement Commands. (line 15) * M-b: CLI Movement Commands. (line 21) * M-d: CLI Editing Commands. (line 17) * M-f: CLI Movement Commands. (line 18) * : CLI Movement Commands. (line 11) * : CLI Advanced Commands. (line 24) * : CLI Advanced Commands. (line 21)  File: quagga.info, Node: Index, Prev: VTY Key Index, Up: Top Index ***** [index] * Menu: * About Quagga: About Quagga. (line 6) * Bug hunting: Bug Reports. (line 6) * Bug Reports: Bug Reports. (line 6) * Build options: The Configure script and its options. (line 6) * Building on Linux boxes: Linux notes. (line 6) * Building the system: Installation. (line 6) * Compatibility with other systems: Supported Platforms. (line 6) * Configuration files for running the software: Config Commands. (line 6) * Configuration options: The Configure script and its options. (line 6) * Configuring Quagga: Linux notes. (line 6) * Contact information: Mailing List. (line 6) * Distance-vector routing protocol: OSPF Fundamentals. (line 6) * Distribution configuration: The Configure script and its options. (line 6) * Errors in the software: Bug Reports. (line 6) * Files for running configurations: Config Commands. (line 6) * Found a bug?: Bug Reports. (line 6) * Getting the herd running: Config Commands. (line 6) * How to get in touch with Quagga: Mailing List. (line 6) * How to install Quagga: Installation. (line 6) * Installation: Installation. (line 6) * Installing Quagga: Installation. (line 6) * ISIS: OSPF6 Configuration Examples. (line 15) * Link State Advertisement: OSPF Fundamentals. (line 12) * Link State Announcement: OSPF Fundamentals. (line 12) * Link State DataBase: OSPF Fundamentals. (line 12) * Link-state routing protocol: OSPF Fundamentals. (line 6) * Link-state routing protocol advantages: OSPF Fundamentals. (line 22) * Link-state routing protocol disadvantages: OSPF Fundamentals. (line 32) * Linux configurations: Linux notes. (line 6) * LSA flooding: OSPF Fundamentals. (line 12) * Mailing lists: Mailing List. (line 6) * Mailing Quagga: Mailing List. (line 6) * Making Quagga: Installation. (line 6) * Modifying the herd's behavior: Config Commands. (line 6) * NHRP: ISIS Configuration Examples. (line 79) * Operating systems that support Quagga: Supported Platforms. (line 6) * Options for configuring: The Configure script and its options. (line 6) * Options to ./configure: The Configure script and its options. (line 6) * OSPF Areas overview: OSPF Fundamentals. (line 103) * OSPF Fundamentals: OSPFv2. (line 27) * OSPF Hello Protocol: OSPF Fundamentals. (line 55) * OSPF Hello Protocol overview: OSPF Fundamentals. (line 53) * OSPF LSA overview: OSPF Fundamentals. (line 73) * OSPFv2: ripngd Filtering Commands. (line 13) * Overview: Overview. (line 6) * Quagga Least-Privileges: Least-Privilege support. (line 6) * Quagga on other systems: Supported Platforms. (line 6) * Quagga Privileges: Least-Privilege support. (line 6) * Reporting bugs: Bug Reports. (line 6) * Reporting software errors: Bug Reports. (line 6) * Software architecture: System Architecture. (line 6) * Software internals: System Architecture. (line 6) * Supported platforms: Supported Platforms. (line 6) * System architecture: System Architecture. (line 6) quagga-1.2.4/doc/quagga.texi000066400000000000000000000062251325323223500156750ustar00rootroot00000000000000\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename quagga.info @c Set variables - sourced from defines.texi @include defines.texi @settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @iftex @afourpaper @end iftex @c %**end of header @c automake will automatically generate version.texi @c and set EDITION, VERSION, UPDATED and UPDATED-MONTH @include version.texi @copying @value{COPYRIGHT_STR} @quotation 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 quotation @end copying @c Info entry @dircategory Routing Software: @direntry * @value{PACKAGE_NAME}: (quagga). The Quagga Software Routing Suite @end direntry @c @smallbook @ifinfo This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. This is Edition @value{EDITION}, last updated @value{UPDATED} of @cite{The Quagga Manual}, for @uref{http://www.quagga.net/,,@value{PACKAGE_NAME}} Version @value{VERSION}. @insertcopying @end ifinfo @titlepage @title @uref{http://www.quagga.net,,Quagga} @subtitle A routing software package for TCP/IP networks @subtitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @value{VERSION} @subtitle @value{UPDATED-MONTH} @author @value{AUTHORS} @page @vskip 0pt plus 1filll @insertcopying @end titlepage @page @ifnottex @node Top @top Quagga @uref{http://www.quagga.net,,Quagga} is an advanced routing software package that provides a suite of TCP/IP based routing protocols. This is the Manual for Quagga @value{VERSION}. @uref{http://www.quagga.net,,Quagga} is a fork of @uref{http://www.zebra.org,,GNU Zebra}. @insertcopying @end ifnottex @menu * Overview:: * Installation:: * Basic commands:: * Zebra:: * RIP:: * RIPng:: * OSPFv2:: * OSPFv3:: * ISIS:: * NHRP:: * BGP:: * Configuring Quagga as a Route Server:: * VTY shell:: * Filtering:: * Route Map:: * IPv6 Support:: * Kernel Interface:: * SNMP Support:: * Zebra Protocol:: * Packet Binary Dump Format:: * Command Index:: * VTY Key Index:: * Index:: @end menu @contents @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 isisd.texi @include nhrpd.texi @include bgpd.texi @include routeserver.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 @unnumbered Command Index @printindex fn @node VTY Key Index @unnumbered VTY Key Index @printindex ky @node Index @unnumbered Index @printindex cp @bye quagga-1.2.4/doc/ripd.8000066400000000000000000000052441325323223500145640ustar00rootroot00000000000000.TH RIPD 8 "25 November 2004" "Quagga RIP daemon" "Version 0.97.3" .SH NAME ripd \- a RIP routing engine for use with Quagga routing software. .SH SYNOPSIS .B ripd [ .B \-dhrv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B ripd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B ripd command: .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\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\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 identifier 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\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the ripd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\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 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 to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\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. \fBripd\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B ripd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-1.2.4/doc/ripd.texi000066400000000000000000000546341325323223500153750ustar00rootroot00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @node RIP @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:: * RIP Version Control:: * 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 @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 520 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 @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. Quagga @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 @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 router rip} {} Disable RIP. @end deffn @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}|default)} {} @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. The interface may be specified as @var{default} to make ripd default to passive on all interfaces. The default is to be passive on all interfaces. @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 RIP Version Control @section RIP Version Control RIP can be configured to send either Version 1 or Version 2 packets. The default is to send RIPv2 while accepting both RIPv1 and RIPv2 (and replying with packets of the appropriate version for REQUESTS / triggered updates). The version to receive and send can be specified globally, and further overriden on a per-interface basis if needs be for send and receive seperately (see below). It is important to note that RIPv1 can not be authenticated. Further, if RIPv1 is enabled then RIP will reply to REQUEST packets, sending the state of its RIP routing table to any remote routers that ask on demand. For a more detailed discussion on the security implications of RIPv1 see @ref{RIP Authentication}. @deffn {RIP Command} {version @var{version}} {} Set RIP version to accept for reads and send. @var{version} can be either `1'' or `2''. Disabling RIPv1 by specifying version 2 is STRONGLY encouraged, @xref{RIP Authentication}. This may become the default in a future release. Default: Send Version 2, and accept either version. @end deffn @deffn {RIP Command} {no version} {} Reset the global version setting back to the default. @end deffn @deffn {Interface command} {ip rip send version @var{version}} {} @var{version} can be `1', `2' or `1 2'. This interface command overrides the global rip version setting, and selects which version of RIP to send packets with, for this interface specifically. Choice of RIP Version 1, RIP Version 2, or both versions. In the latter case, where `1 2' is specified, packets will be both broadcast and multicast. Default: Send packets according to the global version (version 2) @end deffn @deffn {Interface command} {ip rip receive version @var{version}} {} @var{version} can be `1', `2' or `1 2'. This interface command overrides the global rip version setting, and selects which versions of RIP packets will be accepted on this interface. Choice of RIP Version 1, RIP Version 2, or both. Default: Accept packets according to the global setting (both 1 and 2). @end deffn @node How to Announce RIP route @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 Quagga. 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 Quagga and redistributing it in RIP using @code{redistribute static}. @end deffn @node Filtering RIP Routes @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 @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 @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 @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 Quagga'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 @var{word}} {} @deffnx {Route Map} {match ip next-hop prefix-list @var{word}} {} Match if route next-hop (meaning next-hop listed in the rip route-table as displayed by "show ip rip") is permitted by access-list. @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 @section RIP Authentication RIPv2 allows packets to be authenticated via either an insecure plain text password, included with the packet, or via a more secure MD5 based @acronym{HMAC, keyed-Hashing for Message AuthentiCation}, RIPv1 can not be authenticated at all, thus when authentication is configured @code{ripd} will discard routing updates received via RIPv1 packets. However, unless RIPv1 reception is disabled entirely, @xref{RIP Version Control}, RIPv1 REQUEST packets which are received, which query the router for routing information, will still be honoured by @code{ripd}, and @code{ripd} WILL reply to such packets. This allows @code{ripd} to honour such REQUESTs (which sometimes is used by old equipment and very simple devices to bootstrap their default route), while still providing security for route updates which are received. In short: Enabling authentication prevents routes being updated by unauthenticated remote routers, but still can allow routes (I.e. the entire RIP routing table) to be queried remotely, potentially by anyone on the internet, via RIPv1. To prevent such unauthenticated querying of routes disable RIPv1, @xref{RIP Version Control}. @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 @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 @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 rip status} {} 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 rip status} 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 @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. quagga-1.2.4/doc/ripngd.8000066400000000000000000000053231325323223500151070ustar00rootroot00000000000000.TH RIPNGD 8 "25 November 2004" "Quagga RIPNG daemon" "Version 0.97.3" .SH NAME ripngd \- a RIPNG routing engine for use with Quagga routing software. .SH SYNOPSIS .B ripngd [ .B \-dhlrv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B ripngd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B ripngd command: .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\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\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 identifier 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\-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\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the ripngd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\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 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 to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\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" .BR bgpd (8), .BR ripd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B ripngd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-1.2.4/doc/ripngd.texi000066400000000000000000000041601325323223500157070ustar00rootroot00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @node RIPng @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 @section Invoking ripngd There are no @code{ripngd} specific invocation options. Common options can be specified (@pxref{Common Invocation Options}). @node ripngd Configuration @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 @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 @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 quagga-1.2.4/doc/routemap.texi000066400000000000000000000150531325323223500162630ustar00rootroot00000000000000@node Route Map @chapter Route Map Route maps provide a means to both filter and/or apply actions to route, hence allowing policy to be applied to routes. @menu * Route Map Command:: * Route Map Match Command:: * Route Map Set Command:: * Route Map Call Command:: * Route Map Exit Action Command:: * Route Map Examples:: @end menu Route-maps are an ordered list of route-map entries. Each entry may specify up to four distincts sets of clauses: @table @samp @item Matching Policy This specifies the policy implied if the @samp{Matching Conditions} are met or not met, and which actions of the route-map are to be taken, if any. The two possibilities are: @itemize @minus @item @samp{permit}: If the entry matches, then carry out the @samp{Set Actions}. Then finish processing the route-map, permitting the route, unless an @samp{Exit Action} indicates otherwise. @item @samp{deny}: If the entry matches, then finish processing the route-map and deny the route (return @samp{deny}). @end itemize The @samp{Matching Policy} is specified as part of the command which defines the ordered entry in the route-map. See below. @item Matching Conditions A route-map entry may, optionally, specify one or more conditions which must be matched if the entry is to be considered further, as governed by the Match Policy. If a route-map entry does not explicitely specify any matching conditions, then it always matches. @item Set Actions A route-map entry may, optionally, specify one or more @samp{Set Actions} to set or modify attributes of the route. @item Call Action Call to another route-map, after any @samp{Set Actions} have been carried out. If the route-map called returns @samp{deny} then processing of the route-map finishes and the route is denied, regardless of the @samp{Matching Policy} or the @samp{Exit Policy}. If the called route-map returns @samp{permit}, then @samp{Matching Policy} and @samp{Exit Policy} govern further behaviour, as normal. @item Exit Policy An entry may, optionally, specify an alternative @samp{Exit Policy} to take if the entry matched, rather than the normal policy of exiting the route-map and permitting the route. The two possibilities are: @itemize @minus @item @samp{next}: Continue on with processing of the route-map entries. @item @samp{goto N}: Jump ahead to the first route-map entry whose order in the route-map is >= N. Jumping to a previous entry is not permitted. @end itemize @end table The default action of a route-map, if no entries match, is to deny. I.e. a route-map essentially has as its last entry an empty @samp{deny} entry, which matches all routes. To change this behaviour, one must specify an empty @samp{permit} entry as the last entry in the route-map. To summarise the above: @multitable {permit} {action} {No Match} @headitem @tab Match @tab No Match @item @emph{Permit} @tab action @tab cont @item @emph{Deny} @tab deny @tab cont @end multitable @table @samp @item action @itemize @minus @item Apply @emph{set} statements @item If @emph{call} is present, call given route-map. If that returns a @samp{deny}, finish processing and return @samp{deny}. @item If @samp{Exit Policy} is @emph{next}, goto next route-map entry @item If @samp{Exit Policy} is @emph{goto}, goto first entry whose order in the list is >= the given order. @item Finish processing the route-map and permit the route. @end itemize @item deny @itemize @minus @item The route is denied by the route-map (return @samp{deny}). @end itemize @item cont @itemize @minus @item goto next route-map entry @end itemize @end table @node Route Map Command @section Route Map Command @deffn {Command} {route-map @var{route-map-name} (permit|deny) @var{order}} {} Configure the @var{order}'th entry in @var{route-map-name} with @samp{Match Policy} of either @emph{permit} or @emph{deny}. @end deffn @node Route Map Match Command @section 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 as-path @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 local-preference @var{metric}} {} Matches the specified @var{local-preference}. @end deffn @deffn {Route-map Command} {match community @var{community_list}} {} Matches the specified @var{community_list} @end deffn @node Route Map Set Command @section 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}} {} @anchor{routemap set 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 @node Route Map Call Command @section Route Map Call Command @deffn {Route-map Command} {call @var{name}} {} Call route-map @var{name}. If it returns deny, deny the route and finish processing the route-map. @end deffn @node Route Map Exit Action Command @section Route Map Exit Action Command @deffn {Route-map Command} {on-match next} {} @deffnx {Route-map Command} {continue} {} Proceed on to the next entry in the route-map. @end deffn @deffn {Route-map Command} {on-match goto @var{N}} {} @deffnx {Route-map Command} {continue @var{N}} {} Proceed processing the route-map at the first entry whose order is >= N @end deffn @node Route Map Examples @section Route Map Examples A simple example of 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. See @ref{BGP Configuration Examples} for examples of more sophisticated useage of route-maps, including of the @samp{call} action. quagga-1.2.4/doc/routeserver.texi000066400000000000000000000512151325323223500170140ustar00rootroot00000000000000@c -*-texinfo-*- @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @c @c This file is a modified version of Jose Luis Rubio's TeX sources @c of his RS-Manual document @node Configuring Quagga as a Route Server @chapter Configuring Quagga as a Route Server The purpose of a Route Server is to centralize the peerings between BGP speakers. For example if we have an exchange point scenario with four BGP speakers, each of which maintaining a BGP peering with the other three we can convert it into a centralized scenario where each of the four establishes a single BGP peering against the Route Server. We will first describe briefly the Route Server model implemented by Quagga. We will explain the commands that have been added for configuring that model. And finally we will show a full example of Quagga configured as Route Server. @menu * Description of the Route Server model:: * Commands for configuring a Route Server:: * Example of Route Server Configuration:: @end menu @node Description of the Route Server model @section Description of the Route Server model First we are going to describe the normal processing that BGP announcements suffer inside a standard BGP speaker, as shown in @ref{fig:normal-processing}, it consists of three steps: @itemize @bullet @item When an announcement is received from some peer, the `In' filters configured for that peer are applied to the announcement. These filters can reject the announcement, accept it unmodified, or accept it with some of its attributes modified. @item The announcements that pass the `In' filters go into the Best Path Selection process, where they are compared to other announcements referred to the same destination that have been received from different peers (in case such other announcements exist). For each different destination, the announcement which is selected as the best is inserted into the BGP speaker's Loc-RIB. @item The routes which are inserted in the Loc-RIB are considered for announcement to all the peers (except the one from which the route came). This is done by passing the routes in the Loc-RIB through the `Out' filters corresponding to each peer. These filters can reject the route, accept it unmodified, or accept it with some of its attributes modified. Those routes which are accepted by the `Out' filters of a peer are announced to that peer. @end itemize @float Figure,fig:normal-processing @center @image{fig-normal-processing,400pt,,Normal announcement processing} @caption{Announcement processing inside a ``normal'' BGP speaker} @end float Of course we want that the routing tables obtained in each of the routers are the same when using the route server than when not. But as a consequence of having a single BGP peering (against the route server), the BGP speakers can no longer distinguish from/to which peer each announce comes/goes. @anchor{filter-delegation}This means that the routers connected to the route server are not able to apply by themselves the same input/output filters as in the full mesh scenario, so they have to delegate those functions to the route server. Even more, the ``best path'' selection must be also performed inside the route server on behalf of its clients. The reason is that if, after applying the filters of the announcer and the (potential) receiver, the route server decides to send to some client two or more different announcements referred to the same destination, the client will only retain the last one, considering it as an implicit withdrawal of the previous announcements for the same destination. This is the expected behavior of a BGP speaker as defined in @cite{RFC1771}, and even though there are some proposals of mechanisms that permit multiple paths for the same destination to be sent through a single BGP peering, none are currently supported by most existing BGP implementations. As a consequence a route server must maintain additional information and perform additional tasks for a RS-client that those necessary for common BGP peerings. Essentially a route server must: @anchor{Route Server tasks} @itemize @bullet @item Maintain a separated Routing Information Base (Loc-RIB) for each peer configured as RS-client, containing the routes selected as a result of the ``Best Path Selection'' process that is performed on behalf of that RS-client. @item Whenever it receives an announcement from a RS-client, it must consider it for the Loc-RIBs of the other RS-clients. @anchor{Route-server path filter process} @itemize @bullet @item This means that for each of them the route server must pass the announcement through the appropriate `Out' filter of the announcer. @item Then through the appropriate `In' filter of the potential receiver. @item Only if the announcement is accepted by both filters it will be passed to the ``Best Path Selection'' process. @item Finally, it might go into the Loc-RIB of the receiver. @end itemize @end itemize When we talk about the ``appropriate'' filter, both the announcer and the receiver of the route must be taken into account. Suppose that the route server receives an announcement from client A, and the route server is considering it for the Loc-RIB of client B. The filters that should be applied are the same that would be used in the full mesh scenario, i.e., first the `Out' filter of router A for announcements going to router B, and then the `In' filter of router B for announcements coming from router A. We call ``Export Policy'' of a RS-client to the set of `Out' filters that the client would use if there was no route server. The same applies for the ``Import Policy'' of a RS-client and the set of `In' filters of the client if there was no route server. It is also common to demand from a route server that it does not modify some BGP attributes (next-hop, as-path and MED) that are usually modified by standard BGP speakers before announcing a route. The announcement processing model implemented by Quagga is shown in @ref{fig:rs-processing}. The figure shows a mixture of RS-clients (B, C and D) with normal BGP peers (A). There are some details that worth additional comments: @itemize @bullet @item Announcements coming from a normal BGP peer are also considered for the Loc-RIBs of all the RS-clients. But logically they do not pass through any export policy. @item Those peers that are configured as RS-clients do not receive any announce from the `Main' Loc-RIB. @item Apart from import and export policies, `In' and `Out' filters can also be set for RS-clients. `In' filters might be useful when the route server has also normal BGP peers. On the other hand, `Out' filters for RS-clients are probably unnecessary, but we decided not to remove them as they do not hurt anybody (they can always be left empty). @end itemize @float Figure,fig:rs-processing @center @image{fig-rs-processing,430pt,,Route Server Processing Model} @caption{Announcement processing model implemented by the Route Server} @end float @node Commands for configuring a Route Server @section Commands for configuring a Route Server Now we will describe the commands that have been added to quagga in order to support the route server features. @deffn {Route-Server} {neighbor @var{peer-group} route-server-client} {} @deffnx {Route-Server} {neighbor @var{A.B.C.D} route-server-client} {} @deffnx {Route-Server} {neighbor @var{X:X::X:X} route-server-client} {} This command configures the peer given by @var{peer}, @var{A.B.C.D} or @var{X:X::X:X} as an RS-client. Actually this command is not new, it already existed in standard Quagga. It enables the transparent mode for the specified peer. This means that some BGP attributes (as-path, next-hop and MED) of the routes announced to that peer are not modified. With the route server patch, this command, apart from setting the transparent mode, creates a new Loc-RIB dedicated to the specified peer (those named `Loc-RIB for X' in @ref{fig:rs-processing}.). Starting from that moment, every announcement received by the route server will be also considered for the new Loc-RIB. @end deffn @deffn {Route-Server} {neigbor @{A.B.C.D|X.X::X.X|peer-group@} route-map WORD @{import|export@}} {} This set of commands can be used to specify the route-map that represents the Import or Export policy of a peer which is configured as a RS-client (with the previous command). @end deffn @deffn {Route-Server} {match peer @{A.B.C.D|X:X::X:X@}} {} This is a new @emph{match} statement for use in route-maps, enabling them to describe import/export policies. As we said before, an import/export policy represents a set of input/output filters of the RS-client. This statement makes possible that a single route-map represents the full set of filters that a BGP speaker would use for its different peers in a non-RS scenario. The @emph{match peer} statement has different semantics whether it is used inside an import or an export route-map. In the first case the statement matches if the address of the peer who sends the announce is the same that the address specified by @{A.B.C.D|X:X::X:X@}. For export route-maps it matches when @{A.B.C.D|X:X::X:X@} is the address of the RS-Client into whose Loc-RIB the announce is going to be inserted (how the same export policy is applied before different Loc-RIBs is shown in @ref{fig:rs-processing}.). @end deffn @deffn {Route-map Command} {call @var{WORD}} {} This command (also used inside a route-map) jumps into a different route-map, whose name is specified by @var{WORD}. When the called route-map finishes, depending on its result the original route-map continues or not. Apart from being useful for making import/export route-maps easier to write, this command can also be used inside any normal (in or out) route-map. @end deffn @node Example of Route Server Configuration @section Example of Route Server Configuration Finally we are going to show how to configure a Quagga daemon to act as a Route Server. For this purpose we are going to present a scenario without route server, and then we will show how to use the configurations of the BGP routers to generate the configuration of the route server. All the configuration files shown in this section have been taken from scenarios which were tested using the VNUML tool @uref{http://www.dit.upm.es/vnuml,VNUML}. @menu * Configuration of the BGP routers without Route Server:: * Configuration of the BGP routers with Route Server:: * Configuration of the Route Server itself:: * Further considerations about Import and Export route-maps:: @end menu @node Configuration of the BGP routers without Route Server @subsection Configuration of the BGP routers without Route Server We will suppose that our initial scenario is an exchange point with three BGP capable routers, named RA, RB and RC. Each of the BGP speakers generates some routes (with the @var{network} command), and establishes BGP peerings against the other two routers. These peerings have In and Out route-maps configured, named like ``PEER-X-IN'' or ``PEER-X-OUT''. For example the configuration file for router RA could be the following: @exampleindent 0 @example #Configuration for router 'RA' ! hostname RA password **** ! router bgp 65001 no bgp default ipv4-unicast neighbor 2001:0DB8::B remote-as 65002 neighbor 2001:0DB8::C remote-as 65003 ! address-family ipv6 network 2001:0DB8:AAAA:1::/64 network 2001:0DB8:AAAA:2::/64 network 2001:0DB8:0000:1::/64 network 2001:0DB8:0000:2::/64 neighbor 2001:0DB8::B activate neighbor 2001:0DB8::B soft-reconfiguration inbound neighbor 2001:0DB8::B route-map PEER-B-IN in neighbor 2001:0DB8::B route-map PEER-B-OUT out neighbor 2001:0DB8::C activate neighbor 2001:0DB8::C soft-reconfiguration inbound neighbor 2001:0DB8::C route-map PEER-C-IN in neighbor 2001:0DB8::C route-map PEER-C-OUT out exit-address-family ! ipv6 prefix-list COMMON-PREFIXES seq 5 permit 2001:0DB8:0000::/48 ge 64 le 64 ipv6 prefix-list COMMON-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-A-PREFIXES seq 5 permit 2001:0DB8:AAAA::/48 ge 64 le 64 ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-B-PREFIXES seq 5 permit 2001:0DB8:BBBB::/48 ge 64 le 64 ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-C-PREFIXES seq 5 permit 2001:0DB8:CCCC::/48 ge 64 le 64 ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any ! route-map PEER-B-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 100 route-map PEER-B-IN permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! route-map PEER-C-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 200 route-map PEER-C-IN permit 20 match ipv6 address prefix-list PEER-C-PREFIXES set community 65001:22222 ! route-map PEER-B-OUT permit 10 match ipv6 address prefix-list PEER-A-PREFIXES ! route-map PEER-C-OUT permit 10 match ipv6 address prefix-list PEER-A-PREFIXES ! line vty ! @end example @node Configuration of the BGP routers with Route Server @subsection Configuration of the BGP routers with Route Server To convert the initial scenario into one with route server, first we must modify the configuration of routers RA, RB and RC. Now they must not peer between them, but only with the route server. For example, RA's configuration would turn into: @example # Configuration for router 'RA' ! hostname RA password **** ! router bgp 65001 no bgp default ipv4-unicast neighbor 2001:0DB8::FFFF remote-as 65000 ! address-family ipv6 network 2001:0DB8:AAAA:1::/64 network 2001:0DB8:AAAA:2::/64 network 2001:0DB8:0000:1::/64 network 2001:0DB8:0000:2::/64 neighbor 2001:0DB8::FFFF activate neighbor 2001:0DB8::FFFF soft-reconfiguration inbound exit-address-family ! line vty ! @end example Which is logically much simpler than its initial configuration, as it now maintains only one BGP peering and all the filters (route-maps) have disappeared. @node Configuration of the Route Server itself @subsection Configuration of the Route Server itself As we said when we described the functions of a route server (@pxref{Description of the Route Server model}), it is in charge of all the route filtering. To achieve that, the In and Out filters from the RA, RB and RC configurations must be converted into Import and Export policies in the route server. This is a fragment of the route server configuration (we only show the policies for client RA): @example # Configuration for Route Server ('RS') ! hostname RS password ix ! bgp multiple-instance ! router bgp 65000 view RS no bgp default ipv4-unicast neighbor 2001:0DB8::A remote-as 65001 neighbor 2001:0DB8::B remote-as 65002 neighbor 2001:0DB8::C remote-as 65003 ! address-family ipv6 neighbor 2001:0DB8::A activate neighbor 2001:0DB8::A route-server-client neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import neighbor 2001:0DB8::A route-map RSCLIENT-A-EXPORT export neighbor 2001:0DB8::A soft-reconfiguration inbound neighbor 2001:0DB8::B activate neighbor 2001:0DB8::B route-server-client neighbor 2001:0DB8::B route-map RSCLIENT-B-IMPORT import neighbor 2001:0DB8::B route-map RSCLIENT-B-EXPORT export neighbor 2001:0DB8::B soft-reconfiguration inbound neighbor 2001:0DB8::C activate neighbor 2001:0DB8::C route-server-client neighbor 2001:0DB8::C route-map RSCLIENT-C-IMPORT import neighbor 2001:0DB8::C route-map RSCLIENT-C-EXPORT export neighbor 2001:0DB8::C soft-reconfiguration inbound exit-address-family ! ipv6 prefix-list COMMON-PREFIXES seq 5 permit 2001:0DB8:0000::/48 ge 64 le 64 ipv6 prefix-list COMMON-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-A-PREFIXES seq 5 permit 2001:0DB8:AAAA::/48 ge 64 le 64 ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-B-PREFIXES seq 5 permit 2001:0DB8:BBBB::/48 ge 64 le 64 ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-C-PREFIXES seq 5 permit 2001:0DB8:CCCC::/48 ge 64 le 64 ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any ! route-map RSCLIENT-A-IMPORT permit 10 match peer 2001:0DB8::B call A-IMPORT-FROM-B route-map RSCLIENT-A-IMPORT permit 20 match peer 2001:0DB8::C call A-IMPORT-FROM-C ! route-map A-IMPORT-FROM-B permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 100 route-map A-IMPORT-FROM-B permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! route-map A-IMPORT-FROM-C permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 200 route-map A-IMPORT-FROM-C permit 20 match ipv6 address prefix-list PEER-C-PREFIXES set community 65001:22222 ! route-map RSCLIENT-A-EXPORT permit 10 match peer 2001:0DB8::B match ipv6 address prefix-list PEER-A-PREFIXES route-map RSCLIENT-A-EXPORT permit 20 match peer 2001:0DB8::C match ipv6 address prefix-list PEER-A-PREFIXES ! ... ... ... @end example If you compare the initial configuration of RA with the route server configuration above, you can see how easy it is to generate the Import and Export policies for RA from the In and Out route-maps of RA's original configuration. When there was no route server, RA maintained two peerings, one with RB and another with RC. Each of this peerings had an In route-map configured. To build the Import route-map for client RA in the route server, simply add route-map entries following this scheme: @example route-map permit 10 match peer call route-map permit 20 match peer call @end example This is exactly the process that has been followed to generate the route-map RSCLIENT-A-IMPORT. The route-maps that are called inside it (A-IMPORT-FROM-B and A-IMPORT-FROM-C) are exactly the same than the In route-maps from the original configuration of RA (PEER-B-IN and PEER-C-IN), only the name is different. The same could have been done to create the Export policy for RA (route-map RSCLIENT-A-EXPORT), but in this case the original Out route-maps where so simple that we decided not to use the @var{call WORD} commands, and we integrated all in a single route-map (RSCLIENT-A-EXPORT). The Import and Export policies for RB and RC are not shown, but the process would be identical. @node Further considerations about Import and Export route-maps @subsection Further considerations about Import and Export route-maps The current version of the route server patch only allows to specify a route-map for import and export policies, while in a standard BGP speaker apart from route-maps there are other tools for performing input and output filtering (access-lists, community-lists, ...). But this does not represent any limitation, as all kinds of filters can be included in import/export route-maps. For example suppose that in the non-route-server scenario peer RA had the following filters configured for input from peer B: @example neighbor 2001:0DB8::B prefix-list LIST-1 in neighbor 2001:0DB8::B filter-list LIST-2 in neighbor 2001:0DB8::B route-map PEER-B-IN in ... ... route-map PEER-B-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set local-preference 100 route-map PEER-B-IN permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 @end example It is posible to write a single route-map which is equivalent to the three filters (the community-list, the prefix-list and the route-map). That route-map can then be used inside the Import policy in the route server. Lets see how to do it: @example neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import ... ! ... route-map RSCLIENT-A-IMPORT permit 10 match peer 2001:0DB8::B call A-IMPORT-FROM-B ... ... ! route-map A-IMPORT-FROM-B permit 1 match ipv6 address prefix-list LIST-1 match as-path LIST-2 on-match goto 10 route-map A-IMPORT-FROM-B deny 2 route-map A-IMPORT-FROM-B permit 10 match ipv6 address prefix-list COMMON-PREFIXES set local-preference 100 route-map A-IMPORT-FROM-B permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! ... ... @end example The route-map A-IMPORT-FROM-B is equivalent to the three filters (LIST-1, LIST-2 and PEER-B-IN). The first entry of route-map A-IMPORT-FROM-B (sequence number 1) matches if and only if both the prefix-list LIST-1 and the filter-list LIST-2 match. If that happens, due to the ``on-match goto 10'' statement the next route-map entry to be processed will be number 10, and as of that point route-map A-IMPORT-FROM-B is identical to PEER-B-IN. If the first entry does not match, `on-match goto 10'' will be ignored and the next processed entry will be number 2, which will deny the route. Thus, the result is the same that with the three original filters, i.e., if either LIST-1 or LIST-2 rejects the route, it does not reach the route-map PEER-B-IN. In case both LIST-1 and LIST-2 accept the route, it passes to PEER-B-IN, which can reject, accept or modify the route. quagga-1.2.4/doc/snmp.texi000066400000000000000000000144341325323223500154060ustar00rootroot00000000000000@node SNMP Support @chapter SNMP Support @acronym{SNMP,Simple Network Managing Protocol} is a widely implemented feature for collecting network information from router and/or host. Quagga itself does not support SNMP agent (server daemon) functionality but is able to connect to a SNMP agent using the SMUX protocol (@cite{RFC1227}) or the AgentX protocol (@cite{RFC2741}) and make the routing protocol MIBs available through it. @menu * Getting and installing an SNMP agent:: * AgentX configuration:: * SMUX configuration:: * MIB and command reference:: * Handling SNMP Traps:: @end menu @node Getting and installing an SNMP agent @section Getting and installing an SNMP agent There are several SNMP agent which support SMUX or AgentX. We recommend to use the latest version of @code{net-snmp} which was formerly known as @code{ucd-snmp}. It is free and open software and available at @uref{http://www.net-snmp.org/} and as binary package for most Linux distributions. @code{net-snmp} has to be compiled with @code{--with-mib-modules=agentx} to be able to accept connections from Quagga using AgentX protocol or with @code{--with-mib-modules=smux} to use SMUX protocol. Nowadays, SMUX is a legacy protocol. The AgentX protocol should be preferred for any new deployment. Both protocols have the same coverage. @node AgentX configuration @section AgentX configuration To enable AgentX protocol support, Quagga must have been build with the @code{--enable-snmp} or @code{--enable-snmp=agentx} option. Both the master SNMP agent (snmpd) and each of the Quagga daemons must be configured. In @code{/etc/snmp/snmpd.conf}, @code{master agentx} directive should be added. In each of the Quagga daemons, @code{agentx} command will enable AgentX support. @example /etc/snmp/snmpd.conf: # # example access restrictions setup # com2sec readonly default public group MyROGroup v1 readonly view all included .1 80 access MyROGroup "" any noauth exact all none none # # enable master agent for AgentX subagents # master agentx /etc/quagga/ospfd.conf: ! ... the rest of ospfd.conf has been omitted for clarity ... ! agentx ! @end example Upon successful connection, you should get something like this in the log of each Quagga daemons: @example 2012/05/25 11:39:08 ZEBRA: snmp[info]: NET-SNMP version 5.4.3 AgentX subagent connected @end example Then, you can use the following command to check everything works as expected: @example # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 [...] @end example The AgentX protocol can be transported over a Unix socket or using TCP or UDP. It usually defaults to a Unix socket and depends on how NetSNMP was built. If need to configure Quagga to use another transport, you can configure it through @code{/etc/snmp/quagga.conf}: @example /etc/snmp/quagga.conf: [snmpd] # Use a remote master agent agentXSocket tcp:192.168.15.12:705 @end example @node SMUX configuration @section SMUX configuration To enable SMUX protocol support, Quagga must have been build with the @code{--enable-snmp=smux} option. A separate connection has then to be established between the SNMP agent (snmpd) and each of the Quagga daemons. This connections each use different OID numbers and passwords. Be aware that this OID number is not the one that is used in queries by clients, it is solely used for the intercommunication of the daemons. In the following example the ospfd daemon will be connected to the snmpd daemon using the password "quagga_ospfd". For testing it is recommending to take exactly the below snmpd.conf as wrong access restrictions can be hard to debug. @example /etc/snmp/snmpd.conf: # # example access restrictions setup # com2sec readonly default public group MyROGroup v1 readonly view all included .1 80 access MyROGroup "" any noauth exact all none none # # the following line is relevant for Quagga # smuxpeer .1.3.6.1.4.1.3317.1.2.5 quagga_ospfd /etc/quagga/ospf: ! ... the rest of ospfd.conf has been omitted for clarity ... ! smux peer .1.3.6.1.4.1.3317.1.2.5 quagga_ospfd ! @end example After restarting snmpd and quagga, a successful connection can be verified in the syslog and by querying the SNMP daemon: @example snmpd[12300]: [smux_accept] accepted fd 12 from 127.0.0.1:36255 snmpd[12300]: accepted smux peer: \ oid GNOME-PRODUCT-ZEBRA-MIB::ospfd, quagga-0.96.5 # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 @end example Be warned that the current version (5.1.1) of the Net-SNMP daemon writes a line for every SNMP connect to the syslog which can lead to enormous log file sizes. If that is a problem you should consider to patch snmpd and comment out the troublesome @code{snmp_log()} line in the function @code{netsnmp_agent_check_packet()} in @code{agent/snmp_agent.c}. @node MIB and command reference @section MIB and command reference The following OID numbers are used for the interprocess communication of snmpd and the Quagga daemons with SMUX only. @example (OIDs below .iso.org.dod.internet.private.enterprises) zebra .1.3.6.1.4.1.3317.1.2.1 .gnome.gnomeProducts.zebra.zserv bgpd .1.3.6.1.4.1.3317.1.2.2 .gnome.gnomeProducts.zebra.bgpd ripd .1.3.6.1.4.1.3317.1.2.3 .gnome.gnomeProducts.zebra.ripd ospfd .1.3.6.1.4.1.3317.1.2.5 .gnome.gnomeProducts.zebra.ospfd ospf6d .1.3.6.1.4.1.3317.1.2.6 .gnome.gnomeProducts.zebra.ospf6d @end example Sadly, SNMP has not been implemented in all daemons yet. The following OID numbers are used for querying the SNMP daemon by a client: @example zebra .1.3.6.1.2.1.4.24 .iso.org.dot.internet.mgmt.mib-2.ip.ipForward ospfd .1.3.6.1.2.1.14 .iso.org.dot.internet.mgmt.mib-2.ospf bgpd .1.3.6.1.2.1.15 .iso.org.dot.internet.mgmt.mib-2.bgp ripd .1.3.6.1.2.1.23 .iso.org.dot.internet.mgmt.mib-2.rip2 ospf6d .1.3.6.1.3.102 .iso.org.dod.internet.experimental.ospfv3 @end example The following syntax is understood by the Quagga daemons for configuring SNMP using SMUX: @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 Here is the syntax for using AgentX: @deffn {Command} {agentx} {} @deffnx {Command} {no agentx} {} @end deffn @include snmptrap.texi quagga-1.2.4/doc/snmptrap.texi000066400000000000000000000141671325323223500163000ustar00rootroot00000000000000@c Documentation on configuring Quagga and snmpd for SNMP traps @c contributed by Jeroen Simonetti, jsimonetti@denit.net @node Handling SNMP Traps @section Handling SNMP Traps To handle snmp traps make sure your snmp setup of quagga works correctly as described in the quagga documentation in @xref{SNMP Support}. The BGP4 mib will send traps on peer up/down events. These should be visible in your snmp logs with a message similar to: @samp{snmpd[13733]: Got trap from peer on fd 14} To react on these traps they should be handled by a trapsink. Configure your trapsink by adding the following lines to @file{/etc/snmpd/snmpd.conf}: @example # send traps to the snmptrapd on localhost trapsink localhost @end example This will send all traps to an snmptrapd running on localhost. You can of course also use a dedicated management station to catch traps. Configure the snmptrapd daemon by adding the following line to @file{/etc/snmpd/snmptrapd.conf}: @c Documentation contributed by Jeroen Simonetti, jsimonetti@denit.net @example traphandle .1.3.6.1.4.1.3317.1.2.2 /etc/snmp/snmptrap_handle.sh @end example This will use the bash script @file{/etc/snmp/snmptrap_handle.sh} to handle the BGP4 traps. To add traps for other protocol daemons, lookup their appropriate OID from their mib. (For additional information about which traps are supported by your mib, lookup the mib on @uref{http://www.oidview.com/mibs/detail.html}). Make sure snmptrapd is started. The snmptrap_handle.sh script I personally use for handling BGP4 traps is below. You can of course do all sorts of things when handling traps, like sound a siren, have your display flash, etc., be creative ;). @verbatim #!/bin/bash # routers name ROUTER=`hostname -s` #email address use to sent out notification EMAILADDR="john@doe.com" #email address used (allongside above) where warnings should be sent EMAILADDR_WARN="sms-john@doe.com" # type of notification TYPE="Notice" # local snmp community for getting AS belonging to peer COMMUNITY="" # if a peer address is in $WARN_PEERS a warning should be sent WARN_PEERS="192.0.2.1" # get stdin INPUT=`cat -` # get some vars from stdin uptime=`echo $INPUT | cut -d' ' -f5` peer=`echo $INPUT | cut -d' ' -f8 | \ sed -e 's/SNMPv2-SMI::mib-2.15.3.1.14.//g'` peerstate=`echo $INPUT | cut -d' ' -f13` errorcode=`echo $INPUT | cut -d' ' -f9 | sed -e 's/\"//g'` suberrorcode=`echo $INPUT | cut -d' ' -f10 | sed -e 's/\"//g'` remoteas=`snmpget -v2c -c $COMMUNITY \ localhost SNMPv2-SMI::mib-2.15.3.1.9.$peer \ | cut -d' ' -f4` WHOISINFO=`whois -h whois.ripe.net " -r AS$remoteas" | \ egrep '(as-name|descr)'` asname=`echo "$WHOISINFO" | grep "^as-name:" | \ sed -e 's/^as-name://g' -e 's/ //g' -e 's/^ //g' | uniq` asdescr=`echo "$WHOISINFO" | grep "^descr:" | \ sed -e 's/^descr://g' -e 's/ //g' -e 's/^ //g' | uniq` # if peer address is in $WARN_PEER, the email should also # be sent to $EMAILADDR_WARN for ip in $WARN_PEERS; do if [ "x$ip" == "x$peer" ]; then EMAILADDR="$EMAILADDR,$EMAILADDR_WARN" TYPE="WARNING" break fi done # convert peer state case "$peerstate" in 1) peerstate="Idle" ;; 2) peerstate="Connect" ;; 3) peerstate="Active" ;; 4) peerstate="Opensent" ;; 5) peerstate="Openconfirm" ;; 6) peerstate="Established" ;; *) peerstate="Unknown" ;; esac # get textual messages for errors case "$errorcode" in 00) error="No error" suberror="" ;; 01) error="Message Header Error" case "$suberrorcode" in 01) suberror="Connection Not Synchronized" ;; 02) suberror="Bad Message Length" ;; 03) suberror="Bad Message Type" ;; *) suberror="Unknown" ;; esac ;; 02) error="OPEN Message Error" case "$suberrorcode" in 01) suberror="Unsupported Version Number" ;; 02) suberror="Bad Peer AS" ;; 03) suberror="Bad BGP Identifier" ;; 04) suberror="Unsupported Optional Parameter" ;; 05) suberror="Authentication Failure" ;; 06) suberror="Unacceptable Hold Time" ;; *) suberror="Unknown" ;; esac ;; 03) error="UPDATE Message Error" case "$suberrorcode" in 01) suberror="Malformed Attribute List" ;; 02) suberror="Unrecognized Well-known Attribute" ;; 03) suberror="Missing Well-known Attribute" ;; 04) suberror="Attribute Flags Error" ;; 05) suberror="Attribute Length Error" ;; 06) suberror="Invalid ORIGIN Attribute" ;; 07) suberror="AS Routing Loop" ;; 08) suberror="Invalid NEXT_HOP Attribute" ;; 09) suberror="Optional Attribute Error" ;; 10) suberror="Invalid Network Field" ;; 11) suberror="Malformed AS_PATH" ;; *) suberror="Unknown" ;; esac ;; 04) error="Hold Timer Expired" suberror="" ;; 05) error="Finite State Machine Error" suberror="" ;; 06) error="Cease" case "$suberrorcode" in 01) suberror="Maximum Number of Prefixes Reached" ;; 02) suberror="Administratively Shutdown" ;; 03) suberror="Peer Unconfigured" ;; 04) suberror="Administratively Reset" ;; 05) suberror="Connection Rejected" ;; 06) suberror="Other Configuration Change" ;; 07) suberror="Connection collision resolution" ;; 08) suberror="Out of Resource" ;; 09) suberror="MAX" ;; *) suberror="Unknown" ;; esac ;; *) error="Unknown" suberror="" ;; esac # create textual message from errorcodes if [ "x$suberror" == "x" ]; then NOTIFY="$errorcode ($error)" else NOTIFY="$errorcode/$suberrorcode ($error/$suberror)" fi # form a decent subject SUBJECT="$TYPE: $ROUTER [bgp] $peer is $peerstate: $NOTIFY" # create the email body MAIL=`cat << EOF BGP notification on router $ROUTER. Peer: $peer AS: $remoteas New state: $peerstate Notification: $NOTIFY Info: $asname $asdescr Snmpd uptime: $uptime EOF` # mail the notification echo "$MAIL" | mail -s "$SUBJECT" $EMAILADDR @end verbatim quagga-1.2.4/doc/stamp-vti000066400000000000000000000001451325323223500153770ustar00rootroot00000000000000@set UPDATED 19 February 2018 @set UPDATED-MONTH February 2018 @set EDITION 1.2.4 @set VERSION 1.2.4 quagga-1.2.4/doc/texinfo.css000066400000000000000000000054441325323223500157250ustar00rootroot00000000000000/* CSS style for Texinfo documents Public domain 2016 sirgazil. All rights waived. Obtained from: https://sirgazil.bitbucket.io/en/artifact https://sirgazil.bitbucket.io/en/doc/texinfo-css/tip/manual/static/css/document.css */ /* NATIVE ELEMENTS */ a:link {color: #000099; text-decoration: none;} a:visited { color: #6666cc; text-decoration: none; } a:active, a:focus, a:hover { color: #cc0000; text-decoration: underline; } abbr, acronym { cursor: help; } blockquote { color: #555753; font-style: oblique; margin: 30px 0px; padding-left: 3em; } body { background-color: white; box-shadow: 0 0 2px gray; box-sizing: border-box; color: #333; font-family: sans-serif; font-size: 16px; margin: 50px auto; max-width: 960px; padding: 50px; } code, samp, tt, var { color: purple; font-size: 0.8em; } div.example, div.lisp { margin: 0px; } dl { margin: 3em 0em; } dl dl { margin: 0em; } dt { background-color: #F5F5F5; padding: 0.5em; } h1, h2, h2.contents-heading, h3, h4 { padding: 20px 0px 0px 0px; font-weight: normal; } h1 { font-size: 2.4em; } h2 { font-size: 2.2em; font-weight: bold; } h3 { font-size: 1.8em; } h4 { font-size: 1.4em; } hr { background-color: silver; border-style: none; height: 1px; margin: 0px; } html { background-color: #F5F5F5; } img { max-width: 100%; } li { padding: 5px; } pre.display, pre.example, pre.format, pre.lisp, pre.verbatim{ overflow: auto; } pre.example, pre.lisp, pre.verbatim { background-color: #2D3743; border-color: #000; border-style: solid; border-width: thin; color: #E1E1E1; font-size: smaller; padding: 1em; } table { border-collapse: collapse; margin: 40px 0px; } table.index-cp *, table.index-fn *, table.index-ky *, table.index-pg *, table.index-tp *, table.index-vr * { background-color: inherit; border-style: none; } td, th { border-color: silver; border-style: solid; border-width: thin; padding: 10px; } th { background-color: #F5F5F5; } /* END NATIVE ELEMENTS */ /* CLASSES */ .contents { margin-bottom: 4em; } .float { margin: 3em 0em; } .float-caption { font-size: smaller; text-align: center; } .float > img { display: block; margin: auto; } .footnote { font-size: smaller; margin: 5em 0em; } .footnote h3 { display: inline; font-size: small; } .header { background-color: #F2F2F2; font-size: small; padding: 0.2em 1em; } .key { color: purple; font-size: 0.8em; } .menu * { border-style: none; } .menu td { padding: 0.5em 0em; } .menu td:last-child { width: 60%; } .menu th { background-color: inherit; } /* END CLASSES */ quagga-1.2.4/doc/texinfo.tex000066400000000000000000013147761325323223500157510ustar00rootroot00000000000000% 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{2016-02-05.07} % % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, % 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 % 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 3 of the % License, 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 program. If not, see . % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without % restriction. This Exception is an additional permission under section 7 % of the GNU General Public License, version 3 ("GPLv3"). % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: % http://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or % http://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or % http://www.gnu.org/software/texinfo/ (the Texinfo home page) % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % % 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; this makes foo.ps. % The extra TeX runs 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, to some % extent. You can get the existing language-specific files from the % full Texinfo distribution. % % The GNU Texinfo home page is http://www.gnu.org/software/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} \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. % For @tex, we can use \tabalign. \let\+ = \relax % Save some plain tex macros 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\ptexfootnote=\footnote \let\ptexgtr=> \let\ptexhat=^ \let\ptexi=\i \let\ptexindent=\indent \let\ptexinsert=\insert \let\ptexlbrace=\{ \let\ptexless=< \let\ptexnewwrite\newwrite \let\ptexnoindent=\noindent \let\ptexplus=+ \let\ptexraggedright=\raggedright \let\ptexrbrace=\} \let\ptexslash=\/ \let\ptexsp=\sp \let\ptexstar=\* \let\ptexsup=\sup \let\ptext=\t \let\ptextop=\top {\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode % If this character appears in an error message or help string, it % starts a new line in the output. \newlinechar = `^^J % 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 % Pre-3.0. \else \def\linenumber{l.\the\inputlineno:\space} \fi % 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\putworderror\undefined \gdef\putworderror{error}\fi \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi \ifx\putwordin\undefined \gdef\putwordin{in}\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\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\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\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % Give the space character the catcode for a space. \def\spaceisspace{\catcode`\ =10\relax} \chardef\dashChar = `\- \chardef\slashChar = `\/ \chardef\underChar = `\_ % Ignore a token. % \def\gobble#1{} % The following is used inside several \edef's. \def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} % Hyphenation fixes. \hyphenation{ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script ap-pen-dix bit-map bit-maps data-base data-bases eshell fall-ing half-way long-est man-u-script man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces spell-ing spell-ings stand-alone strong-est time-stamp time-stamps which-ever white-space wide-spread wrap-around } % 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. We also make % some effort to order the tracing commands to reduce output in the log % file; cf. trace.sty in LaTeX. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% \def\loggingall{% \tracingstats2 \tracingpages1 \tracinglostchars2 % 2 gives us more in etex \tracingparagraphs1 \tracingoutput1 \tracingmacros2 \tracingrestores1 \showboxbreadth\maxdimen \showboxdepth\maxdimen \ifx\eTeXversion\thisisundefined\else % etex gives us more logging \tracingscantokens1 \tracingifs1 \tracinggroups1 \tracingnesting2 \tracingassigns1 \fi \tracingcommands3 % 3 gives us more in etex \errorcontextlines16 }% % @errormsg{MSG}. Do the index-like expansions on MSG, but if things % aren't perfect, it's not the end of the world, being an error message, % after all. % \def\errormsg{\begingroup \indexnofonts \doerrormsg} \def\doerrormsg#1{\errmessage{#1}} % add check for \lastpenalty to plain's definitions. If the last thing % we did was a \nobreak, we don't want to insert more space. % \def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount \removelastskip\penalty-50\smallskip\fi\fi} \def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount \removelastskip\penalty-100\medskip\fi\fi} \def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount \removelastskip\penalty-200\bigskip\fi\fi} % Output routine % % 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 } % 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 % Output a mark which sets \thischapter, \thissection and \thiscolor. % We dump everything together because we only have one kind of mark. % This works because we only use \botmark / \topmark, not \firstmark. % % A mark contains a subexpression of the \ifcase ... \fi construct. % \get*marks macros below extract the needed part using \ifcase. % % Another complication is to let the user choose whether \thischapter % (\thissection) refers to the chapter (section) in effect at the top % of a page, or that at the bottom of a page. % \domark is called twice inside \chapmacro, to add one % mark before the section break, and one after. % In the second call \prevchapterdefs is the same as \lastchapterdefs, % and \prevsectiondefs is the same as \lastsectiondefs. % Then if the page is not broken at the mark, some of the previous % section appears on the page, and we can get the name of this section % from \firstmark for @everyheadingmarks top. % @everyheadingmarks bottom uses \botmark. % % See page 260 of The TeXbook. \def\domark{% \toks0=\expandafter{\lastchapterdefs}% \toks2=\expandafter{\lastsectiondefs}% \toks4=\expandafter{\prevchapterdefs}% \toks6=\expandafter{\prevsectiondefs}% \toks8=\expandafter{\lastcolordefs}% \mark{% \the\toks0 \the\toks2 % 0: marks for @everyheadingmarks top \noexpand\or \the\toks4 \the\toks6 % 1: for @everyheadingmarks bottom \noexpand\else \the\toks8 % 2: color marks }% } % \gettopheadingmarks, \getbottomheadingmarks, % \getcolormarks - extract needed part of mark. % % \topmark doesn't work for the very first chapter (after the title % page or the contents), so we use \firstmark there -- this gets us % the mark with the chapter defs, unless the user sneaks in, e.g., % @setcolor (or @url, or @link, etc.) between @contents and the very % first @chapter. \def\gettopheadingmarks{% \ifcase0\topmark\fi \ifx\thischapter\empty \ifcase0\firstmark\fi \fi } \def\getbottomheadingmarks{\ifcase1\botmark\fi} \def\getcolormarks{\ifcase2\topmark\fi} % Avoid "undefined control sequence" errors. \def\lastchapterdefs{} \def\lastsectiondefs{} \def\lastsection{} \def\prevchapterdefs{} \def\prevsectiondefs{} \def\lastcolordefs{} % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\pagewidth \newdimen\pageheight % Main output routine. % \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. % \shipout a vbox for a single page, adding an optional header, footer, % cropmarks, and footnote. This also causes index entries for this page % to be written to the auxiliary files. % \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Common context changes for both heading and footing. % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \def\commmonheadfootline{\let\hsize=\pagewidth \texinfochars} % % Retrieve the information for the headings from the marks in the page, % and call Plain TeX's \makeheadline and \makefootline, which use the % values in \headline and \footline. % % This is used to check if we are on the first page of a chapter. \ifcase1\topmark\fi \let\prevchaptername\thischaptername \ifcase0\firstmark\fi \let\curchaptername\thischaptername % \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi % \ifx\curchaptername\prevchaptername \let\thischapterheading\thischapter \else % \thischapterheading is the same as \thischapter except it is blank % for the first page of a chapter. This is to prevent the chapter name % being shown twice. \def\thischapterheading{}% \fi % \global\setbox\headlinebox = \vbox{\commmonheadfootline \makeheadline}% \global\setbox\footlinebox = \vbox{\commmonheadfootline \makefootline}% % {% % Set context for writing to auxiliary files like index files. % 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. % \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. % We don't want .vr (or whatever) entries like this: % \entry{{\indexbackslash }acronym}{32}{\code {\acronym}} % "\acronym" won't work when it's read back in; % it needs to be % {\code {{\backslashcurfont }acronym} \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi % \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 \oddfootingyyy.) % The \baselineskip=24pt in plain's \makefootline has no effect. \vskip 24pt \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 \indexdummies \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi } \newinsert\margin \dimen\margin=\maxdimen % Main part of page, including any footnotes \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\relax \unvbox#1\relax \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}} % Argument parsing % 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. % For example, \def\foo{\parsearg\fooxxx}. % \def\parsearg{\parseargusing{}} \def\parseargusing#1#2{% \def\argtorun{#2}% \begingroup \obeylines \spaceisspace #1% \parseargline\empty% Insert the \empty token, see \finishparsearg below. } {\obeylines % \gdef\parseargline#1^^M{% \endgroup % End of the group started in \parsearg. \argremovecomment #1\comment\ArgTerm% }% } % First remove any @comment, then any @c comment. Also remove a @texinfoc % comment (see \scanmacro for details). Pass the result on to \argcheckspaces. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#2\ArgTerm{\argremovetexinfoc #1\texinfoc\ArgTerm} \def\argremovetexinfoc#1\texinfoc#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} % Each occurrence of `\^^M' or `\^^M' is replaced by a single space. % % \argremovec might leave us with trailing space, e.g., % @end itemize @c foo % This space token undergoes the same procedure and is eventually removed % by \finishparsearg. % \def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} \def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} \def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% \def\temp{#3}% \ifx\temp\empty % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: \let\temp\finishparsearg \else \let\temp\argcheckspaces \fi % Put the space token in: \temp#1 #3\ArgTerm } % If a _delimited_ argument is enclosed in braces, they get stripped; so % to get _exactly_ the rest of the line, we had to prevent such situation. % We prepended an \empty token at the very beginning and we expand it now, % just before passing the control to \argtorun. % (Similarly, we have to think about #3 of \argcheckspacesY above: it is % either the null string, or it ends with \^^M---thus there is no danger % that a pair of braces would be stripped. % % But first, we have to remove the trailing space token. % \def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} % \parseargdef - define a command taking an argument on the line % % \parseargdef\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} \def\parseargdef#1{% \expandafter \doparseargdef \csname\string#1\endcsname #1% } \def\doparseargdef#1#2{% \def#2{\parsearg#1}% \def#1##1% } % Several utility definitions with active space: { \obeyspaces \gdef\obeyedspace{ } % 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. % \gdef\sepspaces{\obeyspaces\let =\tie} % 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 \ ). \gdef\unsepspaces{\let =\space} } \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} % Define the framework for environments in texinfo.tex. It's used like this: % % \envdef\foo{...} % \def\Efoo{...} % % It's the responsibility of \envdef to insert \begingroup before the % actual body; @end closes the group after calling \Efoo. \envdef also % defines \thisenv, so the current environment is known; @end checks % whether the environment name matches. The \checkenv macro can also be % used to check whether the current environment is the one expected. % % Non-false conditionals (@iftex, @ifset) don't fit into this, so they % are not treated as environments; they don't open a group. (The % implementation of @end takes care not to call \endgroup in this % special case.) % At run-time, environments start with this: \def\startenvironment#1{\begingroup\def\thisenv{#1}} % initialize \let\thisenv\empty % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} \def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% \def\temp{#1}% \ifx\thisenv\temp \else \badenverr \fi } % Environment mismatch, #1 expected: \def\badenverr{% \errhelp = \EMsimple \errmessage{This command can appear only \inenvironment\temp, not \inenvironment\thisenv}% } \def\inenvironment#1{% \ifx#1\empty outside of any environment% \else in environment \expandafter\string#1% \fi } % @end foo executes the definition of \Efoo. % But first, it executes a specialized version of \checkenv % \parseargdef\end{% \if 1\csname iscond.#1\endcsname \else % The general wording of \badenverr may not be ideal. \expandafter\checkenv\csname#1\endcsname \csname E#1\endcsname \endgroup \fi } \newhelp\EMsimple{Press RETURN to continue.} % 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\*{\unskip\hfil\break\hbox{}\ignorespaces} % @/ allows a line break. \let\/=\allowbreak % @. is an end-of-sentence period. \def\.{.\spacefactor=\endofsentencespacefactor\space} % @! is an end-of-sentence bang. \def\!{!\spacefactor=\endofsentencespacefactor\space} % @? is an end-of-sentence query. \def\?{?\spacefactor=\endofsentencespacefactor\space} % @frenchspacing on|off says whether to put extra space after punctuation. % \def\onword{on} \def\offword{off} % \parseargdef\frenchspacing{% \def\temp{#1}% \ifx\temp\onword \plainfrenchspacing \else\ifx\temp\offword \plainnonfrenchspacing \else \errhelp = \EMsimple \errmessage{Unknown @frenchspacing option `\temp', must be on|off}% \fi\fi } % @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. % % Another complication is that the group might be very large. This can % cause the glue on the previous page to be unduly stretched, because it % does not have much material. In this case, it's better to add an % explicit \vfill so that the extra space is at the bottom. The % threshold for doing this is if the group is more than \vfilllimit % percent of a page (\vfilllimit can be changed inside of @tex). % \newbox\groupbox \def\vfilllimit{0.7} % \envdef\group{% \ifnum\catcode`\^^M=\active \else \errhelp = \groupinvalidhelp \errmessage{@group invalid in context where filling is enabled}% \fi \startsavinginserts % \setbox\groupbox = \vtop\bgroup % 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 } % % The \vtop 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. Thus, space below is not quite equal to space % above. But it's pretty close. \def\Egroup{% % To get correct interline space between the last line of the group % and the first line afterwards, we have to propagate \prevdepth. \endgraf % Not \par, as it may have been set to \lisppar. \global\dimen1 = \prevdepth \egroup % End the \vtop. \addgroupbox \prevdepth = \dimen1 \checkinserts } \def\addgroupbox{ % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). \dimen2 = \pageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 \ifdim \pagetotal < \vfilllimit\pageheight \page \fi \fi \box\groupbox } % % 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 \parseargdef\need{% % Ensure vertical mode, so we don't make a big box in the middle of a % paragraph. \par % % If the @need value is less than one line space, it's useless. \dimen0 = #1\mil \dimen2 = \ht\strutbox \advance\dimen2 by \dp\strutbox \ifdim\dimen0 > \dimen2 % % Do a \strut just to make the height of this box be normal, so the % normal leading is inserted relative to the preceding line. % And a page break here is fine. \vtop to #1\mil{\strut\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 \fi } % @br forces paragraph break (and is undocumented). \let\br = \par % @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. \parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} % This defn is used inside nofill environments such as @example. \parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount \leftline{\hskip\leftskip{\rm#1}}}} % @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current % paragraph. For more general purposes, use the \margin insertion % class. WHICH is `l' or `r'. Not documented, written for gawk manual. % \newskip\inmarginspacing \inmarginspacing=1cm \def\strutdepth{\dp\strutbox} % \def\doinmargin#1#2{\strut\vadjust{% \nobreak \kern-\strutdepth \vtop to \strutdepth{% \baselineskip=\strutdepth \vss % if you have multiple lines of stuff to put here, you'll need to % make the vbox yourself of the appropriate size. \ifx#1l% \llap{\ignorespaces #2\hskip\inmarginspacing}% \else \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% \fi \null }% }} \def\inleftmargin{\doinmargin l} \def\inrightmargin{\doinmargin r} % % @inmargin{TEXT [, RIGHT-TEXT]} % (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; % else use TEXT for both). % \def\inmargin#1{\parseinmargin #1,,\finish} \def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \def\lefttext{#1}% have both texts \def\righttext{#2}% \else \def\lefttext{#1}% have only one text \def\righttext{#1}% \fi % \ifodd\pageno \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin \else \def\temp{\inleftmargin\lefttext}% \fi \temp } % @| 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). This command % is not documented, not supported, and doesn't work. % \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 }% }% } % @include FILE -- \input text of FILE. % \def\include{\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% {% \makevalueexpandable % we want to expand any @value in FILE. \turnoffactive % and allow special characters in the expansion \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @include of #1^^J}% \edef\temp{\noexpand\input #1 }% % % This trickery is to read FILE outside of a group, in case it makes % definitions, etc. \expandafter }\temp \popthisfilestack } \def\filenamecatcodes{% \catcode`\\=\other \catcode`~=\other \catcode`^=\other \catcode`_=\other \catcode`|=\other \catcode`<=\other \catcode`>=\other \catcode`+=\other \catcode`-=\other \catcode`\`=\other \catcode`\'=\other } \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } \def\pushthisfilestackX{% \expandafter\pushthisfilestackY\thisfile\StackTerm } \def\pushthisfilestackY #1\StackTerm #2\StackTerm {% \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% } \def\popthisfilestack{\errthisfilestackempty} \def\errthisfilestackempty{\errmessage{Internal error: the stack of filenames is empty.}} % \def\thisfile{} % @center line % outputs that line, centered. % \parseargdef\center{% \ifhmode \let\centersub\centerH \else \let\centersub\centerV \fi \centersub{\hfil \ignorespaces#1\unskip \hfil}% \let\centersub\relax % don't let the definition persist, just in case } \def\centerH#1{{% \hfil\break \advance\hsize by -\leftskip \advance\hsize by -\rightskip \line{#1}% \break }} % \newcount\centerpenalty \def\centerV#1{% % The idea here is the same as in \startdefun, \cartouche, etc.: if % @center is the first thing after a section heading, we need to wipe % out the negative parskip inserted by \sectionheading, but still % prevent a page break here. \centerpenalty = \lastpenalty \ifnum\centerpenalty>10000 \vskip\parskip \fi \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi \line{\kern\leftskip #1\kern\rightskip}% } % @sp n outputs n lines of vertical space % \parseargdef\sp{\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=\active% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other\commentxxx}% {\catcode`\^^M=\active% \gdef\commentxxx#1^^M{\endgroup% \futurelet\nexttoken\commentxxxx}% \gdef\commentxxxx{\ifx\nexttoken\aftermacro\expandafter\comment\fi}% } \def\c{\begingroup \catcode`\^^M=\active% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \cxxx} {\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}} % See comment in \scanmacro about why the definitions of @c and @comment differ % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % NCHARS can also be the word `asis' or `none'. % We cannot feasibly implement @paragraphindent asis, though. % \def\asisword{asis} % no translation, these are keywords \def\noneword{none} % \parseargdef\paragraphindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \defaultparindent = 0pt \else \defaultparindent = #1em \fi \fi \parindent = \defaultparindent } % @exampleindent NCHARS % We'll use ems for NCHARS like @paragraphindent. % It seems @exampleindent asis isn't necessary, but % I preserve it to make it similar to @paragraphindent. \parseargdef\exampleindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \lispnarrowing = 0pt \else \lispnarrowing = #1em \fi \fi } % @firstparagraphindent WORD % If WORD is `none', then suppress indentation of the first paragraph % after a section heading. If WORD is `insert', then do indent at such % paragraphs. % % The paragraph indentation is suppressed or not by calling % \suppressfirstparagraphindent, which the sectioning commands do. % We switch the definition of this back and forth according to WORD. % By default, we suppress indentation. % \def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} \def\insertword{insert} % \parseargdef\firstparagraphindent{% \def\temp{#1}% \ifx\temp\noneword \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent \else\ifx\temp\insertword \let\suppressfirstparagraphindent = \relax \else \errhelp = \EMsimple \errmessage{Unknown @firstparagraphindent option `\temp'}% \fi\fi } % Here is how we actually suppress indentation. Redefine \everypar to % \kern backwards by \parindent, and then reset itself to empty. % % We also make \indent itself not actually do anything until the next % paragraph. % \gdef\dosuppressfirstparagraphindent{% \gdef\indent {\restorefirstparagraphindent \indent}% \gdef\noindent{\restorefirstparagraphindent \noindent}% \global\everypar = {\kern -\parindent \restorefirstparagraphindent}% } % \gdef\restorefirstparagraphindent{% \global\let\indent = \ptexindent \global\let\noindent = \ptexnoindent \global\everypar = {}% } % @refill is a no-op. \let\refill=\relax % @setfilename INFO-FILENAME - ignored \let\setfilename=\comment % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{pdf,} % adobe `portable' document format \newcount\tempnum \newcount\lnkcount \newtoks\filename \newcount\filenamelength \newcount\pgn \newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD \newbox\boxA \newbox\boxB \newcount\countA \newif\ifpdf \newif\ifpdfmakepagedest % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as being undefined. \ifx\pdfoutput\thisisundefined \else \ifx\pdfoutput\relax \else \ifcase\pdfoutput \else \pdftrue \fi \fi \fi % PDF uses PostScript string constants for the names of xref targets, % for display in the outlines, and in other places. Thus, we have to % double any backslashes. Otherwise, a name like "\node" will be % interpreted as a newline (\n), followed by o, d, e. Not good. % % See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and % related messages. The final outcome is that it is up to the TeX user % to double the backslashes and otherwise make the string valid, so % that's what we do. pdftex 1.30.0 (ca.2005) introduced a primitive to % do this reliably, so we use it. % #1 is a control sequence in which to do the replacements, % which we \xdef. \def\txiescapepdf#1{% \ifx\pdfescapestring\thisisundefined % No primitive available; should we give a warning or log? % Many times it won't matter. \else % The expandable \pdfescapestring primitive escapes parentheses, % backslashes, and other special chars. \xdef#1{\pdfescapestring{#1}}% \fi } \newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images with PDF output, and none of those formats could be found. (.eps cannot be supported due to the design of the PDF format; use regular TeX (DVI output) for that.)} \ifpdf % % Color manipulation macros using ideas from pdfcolor.tex, % except using rgb instead of cmyk; the latter is said to render as a % very dark gray on-screen and a very dark halftone in print, instead % of actual black. The dark red here is dark enough to print on paper as % nearly black, but still distinguishable for online viewing. We use % black by default, though. \def\rgbDarkRed{0.50 0.09 0.12} \def\rgbBlack{0 0 0} % % rg sets the color for filling (usual text, etc.); % RG sets the color for stroking (thin rules, e.g., normal _'s). \def\pdfsetcolor#1{\pdfliteral{#1 rg #1 RG}} % % Set color, and create a mark which defines \thiscolor accordingly, % so that \makeheadline knows which color to restore. \def\setcolor#1{% \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% \domark \pdfsetcolor{#1}% } % \def\maincolor{\rgbBlack} \pdfsetcolor{\maincolor} \edef\thiscolor{\maincolor} \def\lastcolordefs{} % \def\makefootline{% \baselineskip24pt \line{\pdfsetcolor{\maincolor}\the\footline}% } % \def\makeheadline{% \vbox to 0pt{% \vskip-22.5pt \line{% \vbox to8.5pt{}% % Extract \thiscolor definition from the marks. \getcolormarks % Typeset the headline with \maincolor, then restore the color. \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% }% \vss }% \nointerlineskip } % % \pdfcatalog{/PageMode /UseOutlines} % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\dopdfimage#1#2#3{% \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % % pdftex (and the PDF format) support .pdf, .png, .jpg (among % others). Let's try in that order, PDF first since if % someone has a scalable image, presumably better to use that than a % bitmap. \let\pdfimgext=\empty \begingroup \openin 1 #1.pdf \ifeof 1 \openin 1 #1.PDF \ifeof 1 \openin 1 #1.png \ifeof 1 \openin 1 #1.jpg \ifeof 1 \openin 1 #1.jpeg \ifeof 1 \openin 1 #1.JPG \ifeof 1 \errhelp = \nopdfimagehelp \errmessage{Could not find image file #1 for pdf}% \else \gdef\pdfimgext{JPG}% \fi \else \gdef\pdfimgext{jpeg}% \fi \else \gdef\pdfimgext{jpg}% \fi \else \gdef\pdfimgext{png}% \fi \else \gdef\pdfimgext{PDF}% \fi \else \gdef\pdfimgext{pdf}% \fi \closein 1 \endgroup % % without \immediate, ancient pdftex seg faults when the same image is % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) \ifnum\pdftexversion < 14 \immediate\pdfimage \else \immediate\pdfximage \fi \ifdim \wd0 >0pt width \pdfimagewidth \fi \ifdim \wd2 >0pt height \pdfimageheight \fi \ifnum\pdftexversion<13 #1.\pdfimgext \else {#1.\pdfimgext}% \fi \ifnum\pdftexversion < 14 \else \pdfrefximage \pdflastximage \fi} % \def\pdfmkdest#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \indexnofonts \turnoffactive \makevalueexpandable \def\pdfdestname{#1}% \txiescapepdf\pdfdestname \safewhatsit{\pdfdest name{\pdfdestname} xyz}% }} % % used to mark target names; must be expandable. \def\pdfmkpgn#1{#1} % % by default, use black for everything. \def\urlcolor{\rgbBlack} \def\linkcolor{\rgbBlack} \def\endlink{\setcolor{\maincolor}\pdfendlink} % % Adding outlines to PDF; macros for calculating structure of outlines % come from Petr Olsak \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% \else \csname#1\endcsname \fi} \def\advancenumber#1{\tempnum=\expnumber{#1}\relax \advance\tempnum by 1 \expandafter\xdef\csname#1\endcsname{\the\tempnum}} % % #1 is the section text, which is what will be displayed in the % outline by the pdf viewer. #2 is the pdf expression for the number % of subentries (or empty, for subsubsections). #3 is the node text, % which might be empty if this toc entry had no corresponding node. % #4 is the page number % \def\dopdfoutline#1#2#3#4{% % Generate a link to the node text if that exists; else, use the % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worth the trouble, since most documents are normally structured. \edef\pdfoutlinedest{#3}% \ifx\pdfoutlinedest\empty \def\pdfoutlinedest{#4}% \else \txiescapepdf\pdfoutlinedest \fi % % Also escape PDF chars in the display string. \edef\pdfoutlinetext{#1}% \txiescapepdf\pdfoutlinetext % \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% } % \def\pdfmakeoutlines{% \begingroup % Read toc silently, to get counts of subentries for \pdfoutline. \def\partentry##1##2##3##4{}% ignore parts in the outlines \def\numchapentry##1##2##3##4{% \def\thischapnum{##2}% \def\thissecnum{0}% \def\thissubsecnum{0}% }% \def\numsecentry##1##2##3##4{% \advancenumber{chap\thischapnum}% \def\thissecnum{##2}% \def\thissubsecnum{0}% }% \def\numsubsecentry##1##2##3##4{% \advancenumber{sec\thissecnum}% \def\thissubsecnum{##2}% }% \def\numsubsubsecentry##1##2##3##4{% \advancenumber{subsec\thissubsecnum}% }% \def\thischapnum{0}% \def\thissecnum{0}% \def\thissubsecnum{0}% % % use \def rather than \let here because we redefine \chapentry et % al. a second time, below. \def\appentry{\numchapentry}% \def\appsecentry{\numsecentry}% \def\appsubsecentry{\numsubsecentry}% \def\appsubsubsecentry{\numsubsubsecentry}% \def\unnchapentry{\numchapentry}% \def\unnsecentry{\numsecentry}% \def\unnsubsecentry{\numsubsecentry}% \def\unnsubsubsecentry{\numsubsubsecentry}% \readdatafile{toc}% % % Read toc second time, this time actually producing the outlines. % The `-' means take the \expnumber as the absolute number of % subentries, which we calculated on our first read of the .toc above. % % We use the node names as the destinations. \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% count is always zero \dopdfoutline{##1}{}{##3}{##4}}% % % PDF outlines are displayed using system fonts, instead of % document fonts. Therefore we cannot use special characters, % since the encoding is unknown. For example, the eogonek from % Latin 2 (0xea) gets translated to a | character. Info from % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. % % TODO this right, we have to translate 8-bit characters to % their "best" equivalent, based on the @documentencoding. Too % much work for too little return. Just use the ASCII equivalents % we use for the index sort strings. % \indexnofonts \setupdatafile % We can have normal brace characters in the PDF outlines, unlike % Texinfo index files. So set that up. \def\{{\lbracecharliteral}% \def\}{\rbracecharliteral}% \catcode`\\=\active \otherbackslash \input \tocreadfilename \endgroup } {\catcode`[=1 \catcode`]=2 \catcode`{=\other \catcode`}=\other \gdef\lbracecharliteral[{]% \gdef\rbracecharliteral[}]% ] % \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \nextsp} \def\getfilename#1{% \filenamelength=0 % If we don't expand the argument now, \skipspaces will get % snagged on things like "@value{foo}". \edef\temp{#1}% \expandafter\skipspaces\temp|\relax } \ifnum\pdftexversion < 14 \let \startlink \pdfannotlink \else \let \startlink \pdfstartlink \fi % make a live url in pdf output. \def\pdfurl#1{% \begingroup % it seems we really need yet another set of dummies; have not % tried to figure out what each command should do in the context % of @url. for now, just make @/ a no-op, that's the only one % people have actually reported a problem with. % \normalturnoffactive \def\@{@}% \let\/=\empty \makevalueexpandable % do we want to go so far as to use \indexnofonts instead of just % special-casing \var here? \def\var##1{##1}% % \leavevmode\setcolor{\urlcolor}% \startlink attr{/Border [0 0 0]}% user{/Subtype /Link /A << /S /URI /URI (#1) >>}% \endgroup} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} \setcolor{\linkcolor}#1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else % non-pdf mode \let\pdfmkdest = \gobble \let\pdfurl = \gobble \let\endlink = \relax \let\setcolor = \gobble \let\pdfsetcolor = \gobble \let\pdfmakeoutlines = \relax \fi % \ifx\pdfoutput % % @image support for XeTeX % \newif\ifxeteximgpdf \ifx\XeTeXrevision\thisisundefined \else % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\doxeteximage#1#2#3{% \def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % % XeTeX (and the PDF format) support .pdf, .png, .jpg (among % others). Let's try in that order, PDF first since if % someone has a scalable image, presumably better to use that than a % bitmap. \let\xeteximgext=\empty \xeteximgpdffalse \begingroup \openin 1 #1.pdf \ifeof 1 \openin 1 #1.PDF \ifeof 1 \openin 1 #1.png \ifeof 1 \openin 1 #1.jpg \ifeof 1 \openin 1 #1.jpeg \ifeof 1 \openin 1 #1.JPG \ifeof 1 \errmessage{Could not find image file #1 for XeTeX}% \else \gdef\xeteximgext{JPG}% \fi \else \gdef\xeteximgext{jpeg}% \fi \else \gdef\xeteximgext{jpg}% \fi \else \gdef\xeteximgext{png}% \fi \else \gdef\xeteximgext{PDF} \global\xeteximgpdftrue% \fi \else \gdef\xeteximgext{pdf} \global\xeteximgpdftrue% \fi \closein 1 \endgroup % \ifxeteximgpdf \XeTeXpdffile "#1".\xeteximgext "" \else \XeTeXpicfile "#1".\xeteximgext "" \fi \ifdim \wd0 >0pt width \xeteximagewidth \fi \ifdim \wd2 >0pt height \xeteximageheight \fi \relax } \fi \message{fonts,} % Change the current font style to #1, remembering it in \curfontstyle. % For now, we do not accumulate font styles: @b{@i{foo}} prints foo in % italics, not bold italics. % \def\setfontstyle#1{% \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. \csname ten#1\endcsname % change the current font } % Select #1 fonts with the current style. % \def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} \def\rm{\fam=0 \setfontstyle{rm}} \def\it{\fam=\itfam \setfontstyle{it}} \def\sl{\fam=\slfam \setfontstyle{sl}} \def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} \def\tt{\fam=\ttfam \setfontstyle{tt}} % Unfortunately, we have to override this for titles and the like, since % in those cases "rm" is bold. Sigh. \def\rmisbold{\rm\def\curfontstyle{bf}} % Texinfo sort of supports the sans serif font style, which plain TeX does not. % So we set up a \sf. \newfam\sffam \def\sf{\fam=\sffam \setfontstyle{sf}} \let\li = \sf % Sometimes we call it \li, not \sf. % We don't need math for this font style. \def\ttsl{\setfontstyle{ttsl}} % 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} % % can get a sort of poor man's double spacing by redefining this. \def\baselinefactor{1} % \newdimen\textleading \def\setleading#1{% \dimen0 = #1\relax \normalbaselineskip = \baselinefactor\dimen0 \normallineskip = \lineskipfactor\normalbaselineskip \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip }% } % PDF CMaps. See also LaTeX's t1.cmap. % % do nothing with this by default. \expandafter\let\csname cmapOT1\endcsname\gobble \expandafter\let\csname cmapOT1IT\endcsname\gobble \expandafter\let\csname cmapOT1TT\endcsname\gobble % if we are producing pdf, and we have \pdffontattr, then define cmaps. % (\pdffontattr was introduced many years ago, but people still run % older pdftex's; it's easy to conditionalize, so we do.) \ifpdf \ifx\pdffontattr\thisisundefined \else \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1-0) %%Title: (TeX-OT1-0 TeX OT1 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1) /Supplement 0 >> def /CMapName /TeX-OT1-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <23> <26> <0023> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 40 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1IT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1IT-0) %%Title: (TeX-OT1IT-0 TeX OT1IT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1IT) /Supplement 0 >> def /CMapName /TeX-OT1IT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <25> <26> <0025> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 42 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <23> <0023> <24> <00A3> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1IT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1TT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1TT-0) %%Title: (TeX-OT1TT-0 TeX OT1TT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1TT) /Supplement 0 >> def /CMapName /TeX-OT1TT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 5 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <21> <26> <0021> <28> <5F> <0028> <61> <7E> <0061> endbfrange 32 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <2191> <0C> <2193> <0D> <0027> <0E> <00A1> <0F> <00BF> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <20> <2423> <27> <2019> <60> <2018> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1TT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% \fi\fi % Set the font macro #1 to the font named \fontprefix#2. % #3 is the font's design size, #4 is a scale factor, #5 is the CMap % encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit). % Example: % #1 = \textrm % #2 = \rmshape % #3 = 10 % #4 = \mainmagstep % #5 = OT1 % \def\setfont#1#2#3#4#5{% \font#1=\fontprefix#2#3 scaled #4 \csname cmap#5\endcsname#1% } % This is what gets called when #5 of \setfont is empty. \let\cmap\gobble % % (end of cmaps) % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix % before you read in texinfo.tex. \ifx\fontprefix\thisisundefined \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} % Definitions for a main text size of 11pt. (The default in Texinfo.) % \def\definetextfontsizexi{% % Text fonts (11.2pt, magstep1). \def\textnominalsize{11pt} \edef\mainmagstep{\magstephalf} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1095} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstep1}{OT1} \setfont\deftt\ttshape{10}{\magstep1}{OT1TT} \setfont\defsl\slshape{10}{\magstep1}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \let\tensl=\defsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter (and unnumbered) fonts (17.28pt). \def\chapnominalsize{17pt} \setfont\chaprm\rmbshape{12}{\magstep2}{OT1} \setfont\chapit\itbshape{10}{\magstep3}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep3}{OT1} \setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} \setfont\chapsf\sfbshape{17}{1000}{OT1} \let\chapbf=\chaprm \setfont\chapsc\scbshape{10}{\magstep3}{OT1} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 \def\chapecsize{1728} % Section fonts (14.4pt). \def\secnominalsize{14pt} \setfont\secrm\rmbshape{12}{\magstep1}{OT1} \setfont\secrmnotbold\rmshape{12}{\magstep1}{OT1} \setfont\secit\itbshape{10}{\magstep2}{OT1IT} \setfont\secsl\slbshape{10}{\magstep2}{OT1} \setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\secsf\sfbshape{12}{\magstep1}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep2}{OT1} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 \def\sececsize{1440} % Subsection fonts (13.15pt). \def\ssecnominalsize{13pt} \setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} \setfont\ssecit\itbshape{10}{1315}{OT1IT} \setfont\ssecsl\slbshape{10}{1315}{OT1} \setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} \setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1315}{OT1} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled 1315 \def\ssececsize{1200} % Reduced fonts for @acro in text (10pt). \def\reducednominalsize{10pt} \setfont\reducedrm\rmshape{10}{1000}{OT1} \setfont\reducedtt\ttshape{10}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{1000}{OT1} \setfont\reducedit\itshape{10}{1000}{OT1IT} \setfont\reducedsl\slshape{10}{1000}{OT1} \setfont\reducedsf\sfshape{10}{1000}{OT1} \setfont\reducedsc\scshape{10}{1000}{OT1} \setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} \font\reducedi=cmmi10 \font\reducedsy=cmsy10 \def\reducedecsize{1000} \textleading = 13.2pt % line spacing for 11pt CM \textfonts % reset the current fonts \rm } % end of 11pt text font size definitions, \definetextfontsizexi % Definitions to make the main text be 10pt Computer Modern, with % section, chapter, etc., sizes following suit. This is for the GNU % Press printing of the Emacs 22 manual. Maybe other manuals in the % future. Used with @smallbook, which sets the leading to 12pt. % \def\definetextfontsizex{% % Text fonts (10pt). \def\textnominalsize{10pt} \edef\mainmagstep{1000} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1000} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstephalf}{OT1} \setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} \setfont\defsl\slshape{10}{\magstephalf}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tensl=\defsl \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter fonts (14.4pt). \def\chapnominalsize{14pt} \setfont\chaprm\rmbshape{12}{\magstep1}{OT1} \setfont\chapit\itbshape{10}{\magstep2}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep2}{OT1} \setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\chapsf\sfbshape{12}{\magstep1}{OT1} \let\chapbf\chaprm \setfont\chapsc\scbshape{10}{\magstep2}{OT1} \font\chapi=cmmi12 scaled \magstep1 \font\chapsy=cmsy10 scaled \magstep2 \def\chapecsize{1440} % Section fonts (12pt). \def\secnominalsize{12pt} \setfont\secrm\rmbshape{12}{1000}{OT1} \setfont\secit\itbshape{10}{\magstep1}{OT1IT} \setfont\secsl\slbshape{10}{\magstep1}{OT1} \setfont\sectt\ttbshape{12}{1000}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} \setfont\secsf\sfbshape{12}{1000}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep1}{OT1} \font\seci=cmmi12 \font\secsy=cmsy10 scaled \magstep1 \def\sececsize{1200} % Subsection fonts (10pt). \def\ssecnominalsize{10pt} \setfont\ssecrm\rmbshape{10}{1000}{OT1} \setfont\ssecit\itbshape{10}{1000}{OT1IT} \setfont\ssecsl\slbshape{10}{1000}{OT1} \setfont\ssectt\ttbshape{10}{1000}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} \setfont\ssecsf\sfbshape{10}{1000}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1000}{OT1} \font\sseci=cmmi10 \font\ssecsy=cmsy10 \def\ssececsize{1000} % Reduced fonts for @acro in text (9pt). \def\reducednominalsize{9pt} \setfont\reducedrm\rmshape{9}{1000}{OT1} \setfont\reducedtt\ttshape{9}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{900}{OT1} \setfont\reducedit\itshape{9}{1000}{OT1IT} \setfont\reducedsl\slshape{9}{1000}{OT1} \setfont\reducedsf\sfshape{9}{1000}{OT1} \setfont\reducedsc\scshape{10}{900}{OT1} \setfont\reducedttsl\ttslshape{10}{900}{OT1TT} \font\reducedi=cmmi9 \font\reducedsy=cmsy9 \def\reducedecsize{0900} \divide\parskip by 2 % reduce space between paragraphs \textleading = 12pt % line spacing for 10pt CM \textfonts % reset the current fonts \rm } % end of 10pt text font size definitions, \definetextfontsizex % We provide the user-level command % @fonttextsize 10 % (or 11) to redefine the text font size. pt is assumed. % \def\xiword{11} \def\xword{10} \def\xwordpt{10pt} % \parseargdef\fonttextsize{% \def\textsizearg{#1}% %\wlog{doing @fonttextsize \textsizearg}% % % Set \globaldefs so that documents can use this inside @tex, since % makeinfo 4.8 does not support it, but we need it nonetheless. % \begingroup \globaldefs=1 \ifx\textsizearg\xword \definetextfontsizex \else \ifx\textsizearg\xiword \definetextfontsizexi \else \errhelp=\EMsimple \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} \fi\fi \endgroup } % In order for the font changes to affect most math symbols and letters, % we have to define the \textfont of the standard families. We don't % bother to reset \scriptfont and \scriptscriptfont; awaiting user need. % \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 because \STYLE needs to also set the % current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire % \tenSTYLE to set the current font. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used % in, e.g., the LaTeX logo and acronyms. % % This all needs generalizing, badly. % \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 \def\curfontsize{text}% \def\lsize{reduced}\def\lllsize{smaller}% \resetmathfonts \setleading{\textleading}} \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 \def\curfontsize{title}% \def\lsize{chap}\def\lllsize{subsec}% \resetmathfonts \setleading{27pt}} \def\titlefont#1{{\titlefonts\rmisbold #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 \def\curfontsize{chap}% \def\lsize{sec}\def\lllsize{text}% \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 \def\curfontsize{sec}% \def\lsize{subsec}\def\lllsize{reduced}% \resetmathfonts \setleading{17pt}} \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 \def\curfontsize{ssec}% \def\lsize{text}\def\lllsize{small}% \resetmathfonts \setleading{15pt}} \let\subsubsecfonts = \subsecfonts \def\reducedfonts{% \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy \let\tenttsl=\reducedttsl \def\curfontsize{reduced}% \def\lsize{small}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallfonts{% \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy \let\tenttsl=\smallttsl \def\curfontsize{small}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallerfonts{% \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy \let\tenttsl=\smallerttsl \def\curfontsize{smaller}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{9.5pt}} % Fonts for short table of contents. \setfont\shortcontrm\rmshape{12}{1000}{OT1} \setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 \setfont\shortcontsl\slshape{12}{1000}{OT1} \setfont\shortconttt\ttshape{12}{1000}{OT1TT} % Define these just so they can be easily changed for other fonts. \def\angleleft{$\langle$} \def\angleright{$\rangle$} % Set the fonts to use with the @small... environments. \let\smallexamplefonts = \smallfonts % About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample % can fit this many characters: % 8.5x11=86 smallbook=72 a4=90 a5=69 % If we use \scriptfonts (8pt), then we can fit this many characters: % 8.5x11=90+ smallbook=80 a4=90+ a5=77 % For me, subjectively, the few extra characters that fit aren't worth % the additional smallness of 8pt. So I'm making the default 9pt. % % By the way, for comparison, here's what fits with @example (10pt): % 8.5x11=71 smallbook=60 a4=75 a5=58 % --karl, 24jan03. % Set up the default fonts, so we can use them for creating boxes. % \definetextfontsizexi \message{markup,} % 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 } % Markup style infrastructure. \defmarkupstylesetup\INITMACRO will % define and register \INITMACRO to be called on markup style changes. % \INITMACRO can check \currentmarkupstyle for the innermost % style and the set of \ifmarkupSTYLE switches for all styles % currently in effect. \newif\ifmarkupvar \newif\ifmarkupsamp \newif\ifmarkupkey %\newif\ifmarkupfile % @file == @samp. %\newif\ifmarkupoption % @option == @samp. \newif\ifmarkupcode \newif\ifmarkupkbd %\newif\ifmarkupenv % @env == @code. %\newif\ifmarkupcommand % @command == @code. \newif\ifmarkuptex % @tex (and part of @math, for now). \newif\ifmarkupexample \newif\ifmarkupverb \newif\ifmarkupverbatim \let\currentmarkupstyle\empty \def\setupmarkupstyle#1{% \csname markup#1true\endcsname \def\currentmarkupstyle{#1}% \markupstylesetup } \let\markupstylesetup\empty \def\defmarkupstylesetup#1{% \expandafter\def\expandafter\markupstylesetup \expandafter{\markupstylesetup #1}% \def#1% } % Markup style setup for left and right quotes. \defmarkupstylesetup\markupsetuplq{% \expandafter\let\expandafter \temp \csname markupsetuplq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuplqdefault \else \temp \fi } \defmarkupstylesetup\markupsetuprq{% \expandafter\let\expandafter \temp \csname markupsetuprq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuprqdefault \else \temp \fi } { \catcode`\'=\active \catcode`\`=\active \gdef\markupsetuplqdefault{\let`\lq} \gdef\markupsetuprqdefault{\let'\rq} \gdef\markupsetcodequoteleft{\let`\codequoteleft} \gdef\markupsetcodequoteright{\let'\codequoteright} } \let\markupsetuplqcode \markupsetcodequoteleft \let\markupsetuprqcode \markupsetcodequoteright % \let\markupsetuplqexample \markupsetcodequoteleft \let\markupsetuprqexample \markupsetcodequoteright % \let\markupsetuplqkbd \markupsetcodequoteleft \let\markupsetuprqkbd \markupsetcodequoteright % \let\markupsetuplqsamp \markupsetcodequoteleft \let\markupsetuprqsamp \markupsetcodequoteright % \let\markupsetuplqverb \markupsetcodequoteleft \let\markupsetuprqverb \markupsetcodequoteright % \let\markupsetuplqverbatim \markupsetcodequoteleft \let\markupsetuprqverbatim \markupsetcodequoteright % Allow an option to not use regular directed right quote/apostrophe % (char 0x27), but instead the undirected quote from cmtt (char 0x0d). % The undirected quote is ugly, so don't make it the default, but it % works for pasting with more pdf viewers (at least evince), the % lilypond developers report. xpdf does work with the regular 0x27. % \def\codequoteright{% \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax '% \else \char'15 \fi \else \char'15 \fi } % % and a similar option for the left quote char vs. a grave accent. % Modern fonts display ASCII 0x60 as a grave accent, so some people like % the code environments to do likewise. % \def\codequoteleft{% \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax % [Knuth] pp. 380,381,391 % \relax disables Spanish ligatures ?` and !` of \tt font. \relax`% \else \char'22 \fi \else \char'22 \fi } % Commands to set the quote options. % \parseargdef\codequoteundirected{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxicodequoteundirected\endcsname = t% \else\ifx\temp\offword \expandafter\let\csname SETtxicodequoteundirected\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}% \fi\fi } % \parseargdef\codequotebacktick{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxicodequotebacktick\endcsname = t% \else\ifx\temp\offword \expandafter\let\csname SETtxicodequotebacktick\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}% \fi\fi } % [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font. \def\noligaturesquoteleft{\relax\lq} % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 % Font commands. % #1 is the font command (\sl or \it), #2 is the text to slant. % If we are in a monospaced environment, however, 1) always use \ttsl, % and 2) do not add an italic correction. \def\dosmartslant#1#2{% \ifusingtt {{\ttsl #2}\let\next=\relax}% {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}% \next } \def\smartslanted{\dosmartslant\sl} \def\smartitalic{\dosmartslant\it} % Output an italic correction unless \next (presumed to be the following % character) is such as not to need one. \def\smartitaliccorrection{% \ifx\next,% \else\ifx\next-% \else\ifx\next.% \else\ifx\next\.% \else\ifx\next\comma% \else\ptexslash \fi\fi\fi\fi\fi \aftersmartic } % Unconditional use \ttsl, and no ic. @var is set to this for defuns. \def\ttslanted#1{{\ttsl #1}} % @cite is like \smartslanted except unconditionally use \sl. We never want % ttsl for book titles, do we? \def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection} \def\aftersmartic{} \def\var#1{% \let\saveaftersmartic = \aftersmartic \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}% \smartslanted{#1}% } \let\i=\smartitalic \let\slanted=\smartslanted \let\dfn=\smartslanted \let\emph=\smartitalic % 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 % @b, explicit bold. Also @strong. \def\b#1{{\bf #1}} \let\strong=\b % @sansserif, explicit sans. \def\sansserif#1{{\sf #1}} % 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 = `- } % Set sfcode to normal for the chars that usually have another value. % Can't use plain's \frenchspacing because it uses the `\x notation, and % sometimes \x has an active definition that messes things up. % \catcode`@=11 \def\plainfrenchspacing{% \sfcode`\.=\@m \sfcode`\?=\@m \sfcode`\!=\@m \sfcode`\:=\@m \sfcode`\;=\@m \sfcode`\,=\@m \def\endofsentencespacefactor{1000}% for @. and friends } \def\plainnonfrenchspacing{% \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 \def\endofsentencespacefactor{3000}% for @. and friends } \catcode`@=\other \def\endofsentencespacefactor{3000}% default % @t, explicit typewriter. \def\t#1{% {\tt \rawbackslash \plainfrenchspacing #1}% \null } % @samp. \def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}} % @indicateurl is \samp, that is, with quotes. \let\indicateurl=\samp % @code (and similar) prints in typewriter, but with spaces the same % size as normal in the surrounding text, without hyphenation, etc. % This is a subroutine for that. \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 \plainfrenchspacing #1% }% \null % reset spacefactor to 1000 } % We *must* turn on hyphenation at `-' and `_' in @code. % (But see \codedashfinish below.) % 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 \catcode`\'=\active \catcode`\`=\active \global\let'=\rq \global\let`=\lq % default definitions % \global\def\code{\begingroup \setupmarkupstyle{code}% % The following should really be moved into \setupmarkupstyle handlers. \catcode\dashChar=\active \catcode\underChar=\active \ifallowcodebreaks \let-\codedash \let_\codeunder \else \let-\normaldash \let_\realunder \fi % Given -foo (with a single dash), we do not want to allow a break % after the hyphen. \global\let\codedashprev=\codedash % \codex } % \gdef\codedash{\futurelet\next\codedashfinish} \gdef\codedashfinish{% \normaldash % always output the dash character itself. % % Now, output a discretionary to allow a line break, unless % (a) the next character is a -, or % (b) the preceding character is a -. % E.g., given --posix, we do not want to allow a break after either -. % Given --foo-bar, we do want to allow a break between the - and the b. \ifx\next\codedash \else \ifx\codedashprev\codedash \else \discretionary{}{}{}\fi \fi % we need the space after the = for the case when \next itself is a % space token; it would get swallowed otherwise. As in @code{- a}. \global\let\codedashprev= \next } } \def\normaldash{-} % \def\codex #1{\tclose{#1}\endgroup} \def\codeunder{% % this is all so @math{@code{var_name}+1} can work. In math mode, _ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) % will therefore expand the active definition of _, which is us % (inside @code that is), therefore an endless loop. \ifusingtt{\ifmmode \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. \else\normalunderscore \fi \discretionary{}{}{}}% {\_}% } % An additional complication: the above will allow breaks after, e.g., % each of the four underscores in __typeof__. This is bad. % @allowcodebreaks provides a document-level way to turn breaking at - % and _ on and off. % \newif\ifallowcodebreaks \allowcodebreakstrue \def\keywordtrue{true} \def\keywordfalse{false} \parseargdef\allowcodebreaks{% \def\txiarg{#1}% \ifx\txiarg\keywordtrue \allowcodebreakstrue \else\ifx\txiarg\keywordfalse \allowcodebreaksfalse \else \errhelp = \EMsimple \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}% \fi\fi } % For @command, @env, @file, @option quotes seem unnecessary, % so use \code rather than \samp. \let\command=\code \let\env=\code \let\file=\code \let\option=\code % @uref (abbreviation for `urlref') aka @url 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. % TeX-only option to allow changing PDF output to show only the second % arg (if given), and not the url (which is then just the link target). \newif\ifurefurlonlylink % The main macro is \urefbreak, which allows breaking at expected % places within the url. (There used to be another version, which % didn't support automatic breaking.) \def\urefbreak{\begingroup \urefcatcodes \dourefbreak} \let\uref=\urefbreak % \def\dourefbreak#1{\urefbreakfinish #1,,,\finish} \def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% look for second arg \ifdim\wd0 > 0pt \ifpdf \ifurefurlonlylink % PDF plus option to not display url, show just arg \unhbox0 \else % PDF, normally display both arg and url for consistency, % visibility, if the pdf is eventually used to print, etc. \unhbox0\ (\urefcode{#1})% \fi \else \unhbox0\ (\urefcode{#1})% DVI, always show arg and url \fi \else \urefcode{#1}% only url given, so show it \fi \fi \endlink \endgroup} % Allow line breaks around only a few characters (only). \def\urefcatcodes{% \catcode`\&=\active \catcode`\.=\active \catcode`\#=\active \catcode`\?=\active \catcode`\/=\active } { \urefcatcodes % \global\def\urefcode{\begingroup \setupmarkupstyle{code}% \urefcatcodes \let&\urefcodeamp \let.\urefcodedot \let#\urefcodehash \let?\urefcodequest \let/\urefcodeslash \codex } % % By default, they are just regular characters. \global\def&{\normalamp} \global\def.{\normaldot} \global\def#{\normalhash} \global\def?{\normalquest} \global\def/{\normalslash} } % we put a little stretch before and after the breakable chars, to help % line breaking of long url's. The unequal skips make look better in % cmtt at least, especially for dots. \def\urefprestretchamount{.13em} \def\urefpoststretchamount{.1em} \def\urefprestretch{\urefprebreak \hskip0pt plus\urefprestretchamount\relax} \def\urefpoststretch{\urefpostbreak \hskip0pt plus\urefprestretchamount\relax} % \def\urefcodeamp{\urefprestretch \&\urefpoststretch} \def\urefcodedot{\urefprestretch .\urefpoststretch} \def\urefcodehash{\urefprestretch \#\urefpoststretch} \def\urefcodequest{\urefprestretch ?\urefpoststretch} \def\urefcodeslash{\futurelet\next\urefcodeslashfinish} { \catcode`\/=\active \global\def\urefcodeslashfinish{% \urefprestretch \slashChar % Allow line break only after the final / in a sequence of % slashes, to avoid line break between the slashes in http://. \ifx\next/\else \urefpoststretch \fi } } % One more complication: by default we'll break after the special % characters, but some people like to break before the special chars, so % allow that. Also allow no breaking at all, for manual control. % \parseargdef\urefbreakstyle{% \def\txiarg{#1}% \ifx\txiarg\wordnone \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak} \else\ifx\txiarg\wordbefore \def\urefprebreak{\allowbreak}\def\urefpostbreak{\nobreak} \else\ifx\txiarg\wordafter \def\urefprebreak{\nobreak}\def\urefpostbreak{\allowbreak} \else \errhelp = \EMsimple \errmessage{Unknown @urefbreakstyle setting `\txiarg'}% \fi\fi\fi } \def\wordafter{after} \def\wordbefore{before} \def\wordnone{none} \urefbreakstyle after % @url synonym for @uref, since that's how everyone uses it. % \let\url=\uref % rms does not like angle brackets --karl, 17may97. % So now @email is just like @uref, unless we are pdf. % %\def\email#1{\angleleft{\tt #1}\angleright} \ifpdf \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \else \let\email=\uref \fi % @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). \parseargdef\kbdinputstyle{% \def\txiarg{#1}% \ifx\txiarg\worddistinct \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% \else\ifx\txiarg\wordexample \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% \else\ifx\txiarg\wordcode \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% \else \errhelp = \EMsimple \errmessage{Unknown @kbdinputstyle setting `\txiarg'}% \fi\fi\fi } \def\worddistinct{distinct} \def\wordexample{example} \def\wordcode{code} % Default is `distinct'. \kbdinputstyle distinct % @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. \def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}} \def\xkey{\key} \def\kbdsub#1#2#3\par{% \def\one{#1}\def\three{#3}\def\threex{??}% \ifx\one\xkey\ifx\threex\three \key{#2}% \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi } % definition of @key that produces a lozenge. Doesn't adjust to text size. %\setfont\keyrm\rmshape{8}{1000}{OT1} %\font\keysy=cmsy9 %\def\key#1{{\keyrm\textfont2=\keysy \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}}}} % definition of @key with no lozenge. If the current font is already % monospace, don't change it; that way, we respect @kbdinputstyle. But % if it isn't monospace, then use \tt. % \def\key#1{{\setupmarkupstyle{key}% \nohyphenation \ifmonospace\else\tt\fi #1}\null} % @clicksequence{File @click{} Open ...} \def\clicksequence#1{\begingroup #1\endgroup} % @clickstyle @arrow (by default) \parseargdef\clickstyle{\def\click{#1}} \def\click{\arrow} % 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} % @acronym for "FBI", "NATO", and the like. % We print this one point size smaller, since it's intended for % all-uppercase. % \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% {\selectfonts\lsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi \null % reset \spacefactor=1000 } % @abbr for "Comput. J." and the like. % No font change, but don't do end-of-sentence spacing. % \def\abbr#1{\doabbr #1,,\finish} \def\doabbr#1,#2,#3\finish{% {\plainfrenchspacing #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi \null % reset \spacefactor=1000 } % @asis just yields its argument. Used with @table, for example. % \def\asis#1{#1} % @math outputs its argument in math mode. % % One complication: _ usually means subscripts, but it could also mean % an actual _ character, as in @math{@var{some_variable} + 1}. So make % _ active, and distinguish by seeing if the current family is \slfam, % which is what @var uses. { \catcode`\_ = \active \gdef\mathunderscore{% \catcode`\_=\active \def_{\ifnum\fam=\slfam \_\else\sb\fi}% } } % Another complication: we want \\ (and @\) to output a math (or tt) \. % FYI, plain.tex uses \\ as a temporary control sequence (for no % particular reason), but this is not advertised and we don't care. % % The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. \def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} % \def\math{% \ifmmode\else % only go into math if not in math mode already \tex \mathunderscore \let\\ = \mathbackslash \mathactive % make the texinfo accent commands work in math mode \let\"=\ddot \let\'=\acute \let\==\bar \let\^=\hat \let\`=\grave \let\u=\breve \let\v=\check \let\~=\tilde \let\dotaccent=\dot % have to provide another name for sup operator \let\mathopsup=\sup $\expandafter\finishmath\fi } \def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. % Some active characters (such as <) are spaced differently in math. % We have to reset their definitions in case the @math was an argument % to a command which sets the catcodes (such as @item or @section). % { \catcode`^ = \active \catcode`< = \active \catcode`> = \active \catcode`+ = \active \catcode`' = \active \gdef\mathactive{% \let^ = \ptexhat \let< = \ptexless \let> = \ptexgtr \let+ = \ptexplus \let' = \ptexquoteright } } % for @sub and @sup, if in math mode, just do a normal sub/superscript. % If in text, use math to place as sub/superscript, but switch % into text mode, with smaller fonts. This is a different font than the % one used for real math sub/superscripts (8pt vs. 7pt), but let's not % fix it (significant additions to font machinery) until someone notices. % \def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi} \def\finishsub#1{$\sb{\hbox{\selectfonts\lllsize #1}}$}% % \def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi} \def\finishsup#1{$\ptexsp{\hbox{\selectfonts\lllsize #1}}$}% % @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}. % Ignore unless FMTNAME == tex; then it is like @iftex and @tex, % except specified as a normal braced arg, so no newlines to worry about. % \def\outfmtnametex{tex} % \long\def\inlinefmt#1{\doinlinefmt #1,\finish} \long\def\doinlinefmt#1,#2,\finish{% \def\inlinefmtname{#1}% \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi } % % @inlinefmtifelse{FMTNAME,THEN-TEXT,ELSE-TEXT} expands THEN-TEXT if % FMTNAME is tex, else ELSE-TEXT. \long\def\inlinefmtifelse#1{\doinlinefmtifelse #1,,,\finish} \long\def\doinlinefmtifelse#1,#2,#3,#4,\finish{% \def\inlinefmtname{#1}% \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\else \ignorespaces #3\fi } % % For raw, must switch into @tex before parsing the argument, to avoid % setting catcodes prematurely. Doing it this way means that, for % example, @inlineraw{html, foo{bar} gets a parse error instead of being % ignored. But this isn't important because if people want a literal % *right* brace they would have to use a command anyway, so they may as % well use a command to get a left brace too. We could re-use the % delimiter character idea from \verb, but it seems like overkill. % \long\def\inlineraw{\tex \doinlineraw} \long\def\doinlineraw#1{\doinlinerawtwo #1,\finish} \def\doinlinerawtwo#1,#2,\finish{% \def\inlinerawname{#1}% \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi \endgroup % close group opened by \tex. } % @inlineifset{VAR, TEXT} expands TEXT if VAR is @set. % \long\def\inlineifset#1{\doinlineifset #1,\finish} \long\def\doinlineifset#1,#2,\finish{% \def\inlinevarname{#1}% \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \else\ignorespaces#2\fi } % @inlineifclear{VAR, TEXT} expands TEXT if VAR is not @set. % \long\def\inlineifclear#1{\doinlineifclear #1,\finish} \long\def\doinlineifclear#1,#2,\finish{% \def\inlinevarname{#1}% \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \ignorespaces#2\fi } \message{glyphs,} % and logos. % @@ prints an @, as does @atchar{}. \def\@{\char64 } \let\atchar=\@ % @{ @} @lbracechar{} @rbracechar{} all generate brace characters. % Unless we're in typewriter, use \ecfont because the CM text fonts do % not have braces, and we don't want to switch into math. \def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}} \def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}} \let\{=\mylbrace \let\lbracechar=\{ \let\}=\myrbrace \let\rbracechar=\} \begingroup % Definitions to produce \{ and \} commands for indices, % and @{ and @} for the aux/toc files. \catcode`\{ = \other \catcode`\} = \other \catcode`\[ = 1 \catcode`\] = 2 \catcode`\! = 0 \catcode`\\ = \other !gdef!lbracecmd[\{]% !gdef!rbracecmd[\}]% !gdef!lbraceatcmd[@{]% !gdef!rbraceatcmd[@}]% !endgroup % @comma{} to avoid , parsing problems. \let\comma = , % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent % Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. \let\, = \ptexc \let\dotaccent = \ptexdot \def\ringaccent#1{{\accent23 #1}} \let\tieaccent = \ptext \let\ubaraccent = \ptexb \let\udotaccent = \d % Other special characters: @questiondown @exclamdown @ordf @ordm % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} \def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} \def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} \def\jmacro{j} \def\dotless#1{% \def\temp{#1}% \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi \else \errmessage{@dotless can be used only with i or j}% \fi\fi } % The \TeX{} logo, as in plain, but resetting the spacing so that a % period following counts as ending a sentence. (Idea found in latex.) % \edef\TeX{\TeX \spacefactor=1000 } % @LaTeX{} logo. Not quite the same results as the definition in % latex.ltx, since we use a different font for the raised A; it's most % convenient for us to use an explicitly smaller font, rather than using % the \scriptstyle font (since we don't reset \scriptstyle and % \scriptscriptstyle). % \def\LaTeX{% L\kern-.36em {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{% \ifx\textnominalsize\xwordpt % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX. % Revert to plain's \scriptsize, which is 7pt. \count255=\the\fam $\fam\count255 \scriptstyle A$% \else % For 11pt, we can use our lllsize. \selectfonts\lllsize A% \fi }% \vss }}% \kern-.15em \TeX } % Some math mode symbols. Define \ensuremath to switch into math mode % unless we are already there. Expansion tricks may not be needed here, % but safer, and can't hurt. \def\ensuremath{\ifmmode \expandafter\asis \else\expandafter\ensuredmath \fi} \def\ensuredmath#1{$\relax#1$} % \def\bullet{\ensuremath\ptexbullet} \def\geq{\ensuremath\ge} \def\leq{\ensuremath\le} \def\minus{\ensuremath-} % @dots{} outputs an ellipsis using the current font. % We do .5em per period so that it has the same spacing in the cm % typewriter fonts as three actual period characters; on the other hand, % in other typewriter fonts three periods are wider than 1.5em. So do % whichever is larger. % \def\dots{% \leavevmode \setbox0=\hbox{...}% get width of three periods \ifdim\wd0 > 1.5em \dimen0 = \wd0 \else \dimen0 = 1.5em \fi \hbox to \dimen0{% \hskip 0pt plus.25fil .\hskip 0pt plus1fil .\hskip 0pt plus1fil .\hskip 0pt plus.5fil }% } % @enddots{} is an end-of-sentence ellipsis. % \def\enddots{% \dots \spacefactor=\endofsentencespacefactor } % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. % % Since these characters are used in examples, they should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % \def\point{$\star$} \def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}} \def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} \def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}} \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} \def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}} % The @error{} command. % Adapted from the TeXbook's \boxit. % \newbox\errorbox % {\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 \reducedsf \putworderror\kern-1.5pt} % \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} % \def\error{\leavevmode\lower.7ex\copy\errorbox} % @pounds{} is a sterling sign, which Knuth put in the CM italic font. % \def\pounds{{\it\$}} % @euro{} comes from a separate font, depending on the current style. % We use the free feym* fonts from the eurosym package by Henrik % Theiling, which support regular, slanted, bold and bold slanted (and % "outlined" (blackboard board, sort of) versions, which we don't need). % It is available from http://www.ctan.org/tex-archive/fonts/eurosym. % % Although only regular is the truly official Euro symbol, we ignore % that. The Euro is designed to be slightly taller than the regular % font height. % % feymr - regular % feymo - slanted % feybr - bold % feybo - bold slanted % % There is no good (free) typewriter version, to my knowledge. % A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. % Hmm. % % Also doesn't work in math. Do we need to do math with euro symbols? % Hope not. % % \def\euro{{\eurofont e}} \def\eurofont{% % We set the font at each command, rather than predefining it in % \textfonts and the other font-switching commands, so that % installations which never need the symbol don't have to have the % font installed. % % There is only one designed size (nominal 10pt), so we always scale % that to the current nominal size. % % By the way, simply using "at 1em" works for cmr10 and the like, but % does not work for cmbx10 and other extended/shrunken fonts. % \def\eurosize{\csname\curfontsize nominalsize\endcsname}% % \ifx\curfontstyle\bfstylename % bold: \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize \else % regular: \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize \fi \thiseurofont } % Glyphs from the EC fonts. We don't use \let for the aliases, because % sometimes we redefine the original macro, and the alias should reflect % the redefinition. % % Use LaTeX names for the Icelandic letters. \def\DH{{\ecfont \char"D0}} % Eth \def\dh{{\ecfont \char"F0}} % eth \def\TH{{\ecfont \char"DE}} % Thorn \def\th{{\ecfont \char"FE}} % thorn % \def\guillemetleft{{\ecfont \char"13}} \def\guillemotleft{\guillemetleft} \def\guillemetright{{\ecfont \char"14}} \def\guillemotright{\guillemetright} \def\guilsinglleft{{\ecfont \char"0E}} \def\guilsinglright{{\ecfont \char"0F}} \def\quotedblbase{{\ecfont \char"12}} \def\quotesinglbase{{\ecfont \char"0D}} % % This positioning is not perfect (see the ogonek LaTeX package), but % we have the precomposed glyphs for the most common cases. We put the % tests to use those glyphs in the single \ogonek macro so we have fewer % dummy definitions to worry about for index entries, etc. % % ogonek is also used with other letters in Lithuanian (IOU), but using % the precomposed glyphs for those is not so easy since they aren't in % the same EC font. \def\ogonek#1{{% \def\temp{#1}% \ifx\temp\macrocharA\Aogonek \else\ifx\temp\macrochara\aogonek \else\ifx\temp\macrocharE\Eogonek \else\ifx\temp\macrochare\eogonek \else \ecfont \setbox0=\hbox{#1}% \ifdim\ht0=1ex\accent"0C #1% \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}% \fi \fi\fi\fi\fi }% } \def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A} \def\aogonek{{\ecfont \char"A1}}\def\macrochara{a} \def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E} \def\eogonek{{\ecfont \char"A6}}\def\macrochare{e} % % Use the European Computer Modern fonts (cm-super in outline format) % for non-CM glyphs. That is ec* for regular text and tc* for the text % companion symbols (LaTeX TS1 encoding). Both are part of the ec % package and follow the same conventions. % \def\ecfont{\etcfont{e}} \def\tcfont{\etcfont{t}} % \def\etcfont#1{% % We can't distinguish serif/sans and italic/slanted, but this % is used for crude hacks anyway (like adding French and German % quotes to documents typeset with CM, where we lose kerning), so % hopefully nobody will notice/care. \edef\ecsize{\csname\curfontsize ecsize\endcsname}% \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% \ifmonospace % typewriter: \font\thisecfont = #1ctt\ecsize \space at \nominalsize \else \ifx\curfontstyle\bfstylename % bold: \font\thisecfont = #1cb\ifusingit{i}{x}\ecsize \space at \nominalsize \else % regular: \font\thisecfont = #1c\ifusingit{ti}{rm}\ecsize \space at \nominalsize \fi \fi \thisecfont } % @registeredsymbol - R in a circle. The font for the R should really % be smaller yet, but lllsize is the best we can do for now. % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% \hfil\crcr\Orb}}% }$% } % @textdegree - the normal degrees sign. % \def\textdegree{$^\circ$} % Laurent Siebenmann reports \Orb undefined with: % Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 % so we'll define it if necessary. % \ifx\Orb\thisisundefined \def\Orb{\mathhexbox20D} \fi % Quotes. \chardef\quotedblleft="5C \chardef\quotedblright=`\" \chardef\quoteleft=`\` \chardef\quoteright=`\' \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 \parseargdef\shorttitlepage{% \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}% \endgroup\page\hbox{}\page} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % % 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 \let\page = \oldpage \page \null }% } \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 % % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon % % 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 } \def\finishtitlepage{% \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } % Settings used for typesetting titles: no hyphenation, no indentation, % don't worry much about spacing, ragged right. This should be used % inside a \vbox, and fonts need to be set appropriately first. Because % it is always used for titles, nothing else, we call \rmisbold. \par % should be specified before the end of the \vbox, since a vbox is a group. % \def\raggedtitlesettings{% \rmisbold \hyphenpenalty=10000 \parindent=0pt \tolerance=5000 \ptexraggedright } % Macros to be used within @titlepage: \let\subtitlerm=\tenrm \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \parseargdef\title{% \checkenv\titlepage \vbox{\titlefonts \raggedtitlesettings #1\par}% % print a rule at the page bottom also. \finishedtitlepagefalse \vskip4pt \hrule height 4pt width \hsize \vskip4pt } \parseargdef\subtitle{% \checkenv\titlepage {\subtitlefont \rightline{#1}}% } % @author should come last, but may come many times. % It can also be used inside @quotation. % \parseargdef\author{% \def\temp{\quotation}% \ifx\thisenv\temp \def\quotationauthor{#1}% printed in \Equotation. \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi {\secfonts\rmisbold \leftline{#1}}% \fi } % 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 \makeheadline and \makefootline in Plain 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\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} \def\evenheadingyyy #1\|#2\|#3\|#4\finish{% \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddheading{\parsearg\oddheadingxxx} \def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} \def\oddheadingyyy #1\|#2\|#3\|#4\finish{% \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% \def\evenfooting{\parsearg\evenfootingxxx} \def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} \def\evenfootingyyy #1\|#2\|#3\|#4\finish{% \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddfooting{\parsearg\oddfootingxxx} \def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} \def\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 -12pt \global\advance\vsize by -12pt } \parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} % @evenheadingmarks top \thischapter <- chapter at the top of a page % @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page % % The same set of arguments for: % % @oddheadingmarks % @evenfootingmarks % @oddfootingmarks % @everyheadingmarks % @everyfootingmarks % These define \getoddheadingmarks, \getevenheadingmarks, % \getoddfootingmarks, and \getevenfootingmarks, each to one of % \gettopheadingmarks, \getbottomheadingmarks. % \def\evenheadingmarks{\headingmarks{even}{heading}} \def\oddheadingmarks{\headingmarks{odd}{heading}} \def\evenfootingmarks{\headingmarks{even}{footing}} \def\oddfootingmarks{\headingmarks{odd}{footing}} \def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} \headingmarks{odd}{heading}{#1} } \def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} \headingmarks{odd}{footing}{#1} } % #1 = even/odd, #2 = heading/footing, #3 = top/bottom. \def\headingmarks#1#2#3 {% \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname \global\expandafter\let\csname get#1#2marks\endcsname \temp } \everyheadingmarks bottom \everyfootingmarks bottom % @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{% non-global headings elimination \evenheadline={\hfil}\evenfootline={\hfil}% \oddheadline={\hfil}\oddfootline={\hfil}% } \def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting \HEADINGSoff % it's the default % 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{\thischapterheading\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{\thischapterheading\hfil\folio}} \global\oddheadline={\line{\thischapterheading\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{\thischapterheading\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapterheading\hfil\folio}} \global\oddheadline={\line{\thischapterheading\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % This produces Day Month Year style of output. % Only define if not already defined, in case a txi-??.tex file has set % up a different format (e.g., txi-cs.tex does this). \ifx\today\thisisundefined \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} \fi % @settitle line... specifies the title of the document, for headings. % It generates no output of its own. \def\thistitle{\putwordNoTitle} \def\settitle{\parsearg{\gdef\thistitle}} \message{tables,} % Tables -- @table, @ftable, @vtable, @item(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, @ftable, 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\itemzzz #1{\begingroup % \advance\hsize by -\rightskip \advance\hsize by -\tableindent \setbox0=\hbox{\itemindicate{#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\relax \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. However, if % what follows is an environment such as @example, there will be no % \parskip glue; then the negative vskip we just inserted would % cause the example and the item to crash together. So we use this % bizarre value of 10001 as a signal to \aboveenvbreak to insert % \parskip glue after all. Section titles are handled this way also. % \penalty 10001 \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 list environment}} \def\itemx{\errmessage{@itemx while not in a list environment}} % @table, @ftable, @vtable. \envdef\table{% \let\itemindex\gobble \tablecheck{table}% } \envdef\ftable{% \def\itemindex ##1{\doind {fn}{\code{##1}}}% \tablecheck{ftable}% } \envdef\vtable{% \def\itemindex ##1{\doind {vr}{\code{##1}}}% \tablecheck{vtable}% } \def\tablecheck#1{% \ifnum \the\catcode`\^^M=\active \endgroup \errmessage{This command won't work in this context; perhaps the problem is that we are \inenvironment\thisenv}% \def\next{\doignore{#1}}% \else \let\next\tablex \fi \next } \def\tablex#1{% \def\itemindicate{#1}% \parsearg\tabley } \def\tabley#1{% {% \makevalueexpandable \edef\temp{\noexpand\tablez #1\space\space\space}% \expandafter }\temp \endtablez } \def\tablez #1 #2 #3 #4\endtablez{% \aboveenvbreak \ifnum 0#1>0 \advance \leftskip by #1\mil \fi \ifnum 0#2>0 \tableindent=#2\mil \fi \ifnum 0#3>0 \advance \rightskip by #3\mil \fi \itemmax=\tableindent \advance \itemmax by -\itemmargin \advance \leftskip by \tableindent \exdentamount=\tableindent \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi \let\item = \internalBitem \let\itemx = \internalBitemx } \def\Etable{\endgraf\afterenvbreak} \let\Eftable\Etable \let\Evtable\Etable \let\Eitemize\Etable \let\Eenumerate\Etable % This is the counter used by @enumerate, which is really @itemize \newcount \itemno \envdef\itemize{\parsearg\doitemize} \def\doitemize#1{% \aboveenvbreak \itemmax=\itemindent \advance\itemmax by -\itemmargin \advance\leftskip by \itemindent \exdentamount=\itemindent \parindent=0pt \parskip=\smallskipamount \ifdim\parskip=0pt \parskip=2pt \fi % % Try typesetting the item mark so that if the document erroneously says % something like @itemize @samp (intending @table), there's an error % right away at the @itemize. It's not the best error message in the % world, but it's better than leaving it to the @item. This means if % the user wants an empty mark, they have to say @w{} not just @w. \def\itemcontents{#1}% \setbox0 = \hbox{\itemcontents}% % % @itemize with no arg is equivalent to @itemize @bullet. \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi % \let\item=\itemizeitem } % Definition of @item while inside @itemize and @enumerate. % \def\itemizeitem{% \advance\itemno by 1 % for enumerations {\let\par=\endgraf \smallbreak}% reasonable place to break {% % If the document has an @itemize directly after a section title, a % \nobreak will be last on the list, and \sectionheading will have % done a \vskip-\parskip. In that case, we don't want to zero % parskip, or the item text will crash with the heading. On the % other hand, when there is normal text preceding the item (as there % usually is), we do want to zero parskip, or there would be too much % space. In that case, we won't have a \nobreak before. At least % that's the theory. \ifnum\lastpenalty<10000 \parskip=0in \fi \noindent \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% % \ifinner\else \vadjust{\penalty 1200}% not good to break after first line of item. \fi % We can be in inner vertical mode in a footnote, although an % @itemize looks awful there. }% \flushcr } % \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'. % \envparseargdef\enumerate{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% % 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 \doitemize, 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 \doitemize{#1.}\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} % @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. % 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 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 @columnfraction, usually a decimal number like .5, but might % be just 1. We just use it, whatever it is. % \def\pickupwholefraction#1 {% \global\advance\colcount by 1 \expandafter\xdef\csname col\the\colcount\endcsname{#1\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\space}% 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-only commands. % % @headitem starts a heading row, which we typeset in bold. Assignments % have to be global since we are inside the implicit group of an % alignment entry. \everycr below resets \everytab so we don't have to % undo it ourselves. \def\headitemfont{\b}% for people to use in the template row; not changeable \def\headitem{% \checkenv\multitable \crcr \gdef\headitemcrhook{\nobreak}% attempt to avoid page break after headings \global\everytab={\bf}% can't use \headitemfont since the parsing differs \the\everytab % for the first item }% % % default for tables with no headings. \let\headitemcrhook=\relax % % A \tab used to include \hskip1sp. But then the space in a template % line is not enough. That is bad. So let's go back to just `&' until % we again encounter the problem the 1sp was intended to solve. % --karl, nathan@acm.org, 20apr99. \def\tab{\checkenv\multitable &\the\everytab}% % @multitable ... @end multitable definitions: % \newtoks\everytab % insert after every tab. % \envdef\multitable{% \vskip\parskip \startsavinginserts % % @item within a multitable starts a normal row. % We use \def instead of \let so that if one of the multitable entries % contains an @itemize, we don't choke on the \item (seen as \crcr aka % \endtemplate) expanding \doitemize. \def\item{\crcr}% % \tolerance=9500 \hbadness=9500 \setmultitablespacing \parskip=\multitableparskip \parindent=\multitableparindent \overfullrule=0pt \global\colcount=0 % \everycr = {% \noalign{% \global\everytab={}% Reset from possible headitem. \global\colcount=0 % Reset the column counter. % % Check for saved footnotes, etc.: \checkinserts % % Perhaps a \nobreak, then reset: \headitemcrhook \global\let\headitemcrhook=\relax }% }% % \parsearg\domultitable } \def\domultitable#1{% % To parse everything between @multitable and @item: \setuptable#1 \endsetuptable % % 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 \multistrut \vtop{% % Use the current \colcount to find the correct column width: \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\Emultitable{% \crcr \egroup % end the \halign \global\setpercentfalse } \def\setmultitablespacing{% \def\multistrut{\strut}% just use the standard line spacing % % Compute \multitablelinespace (if not defined by user) for use in % \multitableparskip calculation. We used define \multistrut based on % this, but (ironically) that caused the spacing to be off. % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. \ifdim\multitablelinespace=0pt \setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip \global\advance\multitablelinespace by-\ht0 \fi % 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. \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,} % @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, % @ifnotxml always succeed. They currently do nothing; we don't % attempt to check whether the conditionals are properly nested. But we % have to remember that they are conditionals, so that @end doesn't % attempt to close an environment group. % \def\makecond#1{% \expandafter\let\csname #1\endcsname = \relax \expandafter\let\csname iscond.#1\endcsname = 1 } \makecond{iftex} \makecond{ifnotdocbook} \makecond{ifnothtml} \makecond{ifnotinfo} \makecond{ifnotplaintext} \makecond{ifnotxml} % Ignore @ignore, @ifhtml, @ifinfo, and the like. % \def\direntry{\doignore{direntry}} \def\documentdescription{\doignore{documentdescription}} \def\docbook{\doignore{docbook}} \def\html{\doignore{html}} \def\ifdocbook{\doignore{ifdocbook}} \def\ifhtml{\doignore{ifhtml}} \def\ifinfo{\doignore{ifinfo}} \def\ifnottex{\doignore{ifnottex}} \def\ifplaintext{\doignore{ifplaintext}} \def\ifxml{\doignore{ifxml}} \def\ignore{\doignore{ignore}} \def\menu{\doignore{menu}} \def\xml{\doignore{xml}} % Ignore text until a line `@end #1', keeping track of nested conditionals. % % A count to remember the depth of nesting. \newcount\doignorecount \def\doignore#1{\begingroup % Scan in ``verbatim'' mode: \obeylines \catcode`\@ = \other \catcode`\{ = \other \catcode`\} = \other % % Make sure that spaces turn into tokens that match what \doignoretext wants. \spaceisspace % % Count number of #1's that we've seen. \doignorecount = 0 % % Swallow text until we reach the matching `@end #1'. \dodoignore{#1}% } { \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. \obeylines % % \gdef\dodoignore#1{% % #1 contains the command name as a string, e.g., `ifinfo'. % % Define a command to find the next `@end #1'. \long\def\doignoretext##1^^M@end #1{% \doignoretextyyy##1^^M@#1\_STOP_}% % % And this command to find another #1 command, at the beginning of a % line. (Otherwise, we would consider a line `@c @ifset', for % example, to count as an @ifset for nesting.) \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% % % And now expand that command. \doignoretext ^^M% }% } \def\doignoreyyy#1{% \def\temp{#1}% \ifx\temp\empty % Nothing found. \let\next\doignoretextzzz \else % Found a nested condition, ... \advance\doignorecount by 1 \let\next\doignoretextyyy % ..., look for another. % If we're here, #1 ends with ^^M\ifinfo (for example). \fi \next #1% the token \_STOP_ is present just after this macro. } % We have to swallow the remaining "\_STOP_". % \def\doignoretextzzz#1{% \ifnum\doignorecount = 0 % We have just found the outermost @end. \let\next\enddoignore \else % Still inside a nested condition. \advance\doignorecount by -1 \let\next\doignoretext % Look for the next @end. \fi \next } % Finish off ignored text. { \obeylines% % Ignore anything after the last `@end #1'; this matters in verbatim % environments, where otherwise the newline after an ignored conditional % would result in a blank line in the output. \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% } % @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. % We rely on the fact that \parsearg sets \catcode`\ =10. % \parseargdef\set{\setyyy#1 \endsetyyy} \def\setyyy#1 #2\endsetyyy{% {% \makevalueexpandable \def\temp{#2}% \edef\next{\gdef\makecsname{SET#1}}% \ifx\temp\empty \next{}% \else \setzzz#2\endsetzzz \fi }% } % Remove the trailing space \setxxx inserted. \def\setzzz#1 \endsetzzz{\next{#1}} % @clear VAR clears (i.e., unsets) the variable VAR. % \parseargdef\clear{% {% \makevalueexpandable \global\expandafter\let\csname SET#1\endcsname=\relax }% } % @value{foo} gets the text saved in variable foo. \def\value{\begingroup\makevalueexpandable\valuexxx} \def\valuexxx#1{\expandablevalue{#1}\endgroup} { \catcode`\-=\active \catcode`\_=\active % \gdef\makevalueexpandable{% \let\value = \expandablevalue % We don't want these characters active, ... \catcode`\-=\other \catcode`\_=\other % ..., but we might end up with active ones in the argument if % we're called from @code, as @code{@value{foo-bar_}}, though. % So \let them to their normal equivalents. \let-\normaldash \let_\normalunderscore } } % We have this subroutine so that we can handle at least some @value's % properly in indexes (we call \makevalueexpandable in \indexdummies). % The command has to be fully expandable (if the variable is set), 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). % % Unfortunately, this has the consequence that when _ is in the *value* % of an @set, it does not print properly in the roman fonts (get the cmr % dot accent at position 126 instead). No fix comes to mind, and it's % been this way since 2003 or earlier, so just ignore it. % \def\expandablevalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax {[No value for ``#1'']}% \message{Variable `#1', used in @value, is not set.}% \else \csname SET#1\endcsname \fi } % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % % To get the special treatment we need for `@end ifset,' we call % \makecond and then redefine. % \makecond{ifset} \def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} \def\doifset#1#2{% {% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname SET#2\endcsname\relax #1% If not set, redefine \next. \fi \expandafter }\next } \def\ifsetfail{\doignore{ifset}} % @ifclear VAR ... @end executes the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. % % The `\else' inside the `\doifset' parameter is a trick to reuse the % above code: if the variable is not set, do nothing, if it is set, % then redefine \next to \ifclearfail. % \makecond{ifclear} \def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} \def\ifclearfail{\doignore{ifclear}} % @ifcommandisdefined CMD ... @end executes the `...' if CMD (written % without the @) is in fact defined. We can only feasibly check at the % TeX level, so something like `mathcode' is going to considered % defined even though it is not a Texinfo command. % \makecond{ifcommanddefined} \def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}} % \def\doifcmddefined#1#2{{% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname #2\endcsname\relax #1% If not defined, \let\next as above. \fi \expandafter }\next } \def\ifcmddefinedfail{\doignore{ifcommanddefined}} % @ifcommandnotdefined CMD ... handled similar to @ifclear above. \makecond{ifcommandnotdefined} \def\ifcommandnotdefined{% \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}} \def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}} % Set the `txicommandconditionals' variable, so documents have a way to % test if the @ifcommand...defined conditionals are available. \set txicommandconditionals % @dircategory CATEGORY -- specify a category of the dir file % which this file should belong to. Ignore this in TeX. \let\dircategory=\comment % @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 macros and \if's. \edef\newwrite{\makecsname{ptexnewwrite}} % \newindex {foo} defines an index named IX. % It automatically defines \IXindex such that % \IXindex ...rest of line... puts an entry in the index IX. % It also defines \IXindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is IX. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \expandafter\chardef\csname#1indfile\endcsname=0 \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\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \expandafter\chardef\csname#1indfile\endcsname=0 \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % The default indices: \newindex{cp}% concepts, \newcodeindex{fn}% functions, \newcodeindex{vr}% variables, \newcodeindex{tp}% types, \newcodeindex{ky}% keys \newcodeindex{pg}% and programs. % @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. % % @syncodeindex foo bar similar, but put all entries made for index foo % inside @code. % \def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} \def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% % Only do \closeout if we haven't already done it, else we'll end up % closing the target index. \expandafter \ifx\csname donesynindex#2\endcsname \relax % The \closeout helps reduce unnecessary open files; the limit on the % Acorn RISC OS is a mere 16 files. \expandafter\closeout\csname#2indfile\endcsname \expandafter\let\csname donesynindex#2\endcsname = 1 \fi % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp % redefine \fooindex: \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% } % Define \doindex, the driver for all index macros. % Argument #1 is generated by the calling \fooindex macro, % and it the two-letter name of the index. \def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx} \def\doindexxxx #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx} \def\docodeindexxxx #1{\doind{\indexname}{\code{#1}}} % Used when writing an index entry out to an index file, to prevent % expansion of Texinfo commands that can appear in an index entry. % \def\indexdummies{% \escapechar = `\\ % use backslash in output files. \def\@{@}% change to @@ when we switch to @ as escape char in index files. \def\ {\realbackslash\space }% % % Need these unexpandable (because we define \tt as a dummy) % definitions when @{ or @} appear in index entry text. Also, more % complicated, when \tex is in effect and \{ is a \delimiter again. % We can't use \lbracecmd and \rbracecmd because texindex assumes % braces and backslashes are used only as delimiters. Perhaps we % should use @lbracechar and @rbracechar? \def\{{{\tt\char123}}% \def\}{{\tt\char125}}% % % Do the redefinitions. \commondummies } % For the aux and toc files, @ is the escape character. So we want to % redefine everything using @ as the escape character (instead of % \realbackslash, still used for index files). When everything uses @, % this will be simpler. % \def\atdummies{% \def\@{@@}% \def\ {@ }% \let\{ = \lbraceatcmd \let\} = \rbraceatcmd % % Do the redefinitions. \commondummies \otherbackslash } % Called from \indexdummies and \atdummies. % \def\commondummies{% % \definedummyword defines \#1 as \string\#1\space, thus effectively % preventing its expansion. This is used only for control words, % not control letters, because the \space would be incorrect for % control characters, but is needed to separate the control word % from whatever follows. % % For control letters, we have \definedummyletter, which omits the % space. % % These can be used both for control words that take an argument and % those that do not. If it is followed by {arg} in the input, then % that will dutifully get written to the index (or wherever). % \def\definedummyword ##1{\def##1{\string##1\space}}% \def\definedummyletter##1{\def##1{\string##1}}% \let\definedummyaccent\definedummyletter % \commondummiesnofonts % \definedummyletter\_% \definedummyletter\-% % % Non-English letters. \definedummyword\AA \definedummyword\AE \definedummyword\DH \definedummyword\L \definedummyword\O \definedummyword\OE \definedummyword\TH \definedummyword\aa \definedummyword\ae \definedummyword\dh \definedummyword\exclamdown \definedummyword\l \definedummyword\o \definedummyword\oe \definedummyword\ordf \definedummyword\ordm \definedummyword\questiondown \definedummyword\ss \definedummyword\th % % Although these internal commands shouldn't show up, sometimes they do. \definedummyword\bf \definedummyword\gtr \definedummyword\hat \definedummyword\less \definedummyword\sf \definedummyword\sl \definedummyword\tclose \definedummyword\tt % \definedummyword\LaTeX \definedummyword\TeX % % Assorted special characters. \definedummyword\arrow \definedummyword\bullet \definedummyword\comma \definedummyword\copyright \definedummyword\registeredsymbol \definedummyword\dots \definedummyword\enddots \definedummyword\entrybreak \definedummyword\equiv \definedummyword\error \definedummyword\euro \definedummyword\expansion \definedummyword\geq \definedummyword\guillemetleft \definedummyword\guillemetright \definedummyword\guilsinglleft \definedummyword\guilsinglright \definedummyword\lbracechar \definedummyword\leq \definedummyword\mathopsup \definedummyword\minus \definedummyword\ogonek \definedummyword\pounds \definedummyword\point \definedummyword\print \definedummyword\quotedblbase \definedummyword\quotedblleft \definedummyword\quotedblright \definedummyword\quoteleft \definedummyword\quoteright \definedummyword\quotesinglbase \definedummyword\rbracechar \definedummyword\result \definedummyword\sub \definedummyword\sup \definedummyword\textdegree % % We want to disable all macros so that they are not expanded by \write. \macrolist % \normalturnoffactive % % Handle some cases of @value -- where it does not contain any % (non-fully-expandable) commands. \makevalueexpandable } % \commondummiesnofonts: common to \commondummies and \indexnofonts. % Define \definedumyletter, \definedummyaccent and \definedummyword before % using. % \def\commondummiesnofonts{% % Control letters and accents. \definedummyletter\!% \definedummyaccent\"% \definedummyaccent\'% \definedummyletter\*% \definedummyaccent\,% \definedummyletter\.% \definedummyletter\/% \definedummyletter\:% \definedummyaccent\=% \definedummyletter\?% \definedummyaccent\^% \definedummyaccent\`% \definedummyaccent\~% \definedummyword\u \definedummyword\v \definedummyword\H \definedummyword\dotaccent \definedummyword\ogonek \definedummyword\ringaccent \definedummyword\tieaccent \definedummyword\ubaraccent \definedummyword\udotaccent \definedummyword\dotless % % Texinfo font commands. \definedummyword\b \definedummyword\i \definedummyword\r \definedummyword\sansserif \definedummyword\sc \definedummyword\slanted \definedummyword\t % % Commands that take arguments. \definedummyword\abbr \definedummyword\acronym \definedummyword\anchor \definedummyword\cite \definedummyword\code \definedummyword\command \definedummyword\dfn \definedummyword\dmn \definedummyword\email \definedummyword\emph \definedummyword\env \definedummyword\file \definedummyword\image \definedummyword\indicateurl \definedummyword\inforef \definedummyword\kbd \definedummyword\key \definedummyword\math \definedummyword\option \definedummyword\pxref \definedummyword\ref \definedummyword\samp \definedummyword\strong \definedummyword\tie \definedummyword\U \definedummyword\uref \definedummyword\url \definedummyword\var \definedummyword\verb \definedummyword\w \definedummyword\xref } % For testing: output @{ and @} in index sort strings as \{ and \}. \newif\ifusebracesinindexes \let\indexlbrace\relax \let\indexrbrace\relax {\catcode`\@=0 \catcode`\\=13 @gdef@backslashdisappear{@def\{}} } { \catcode`\<=13 \catcode`\-=13 \catcode`\`=13 \gdef\indexnonalnumdisappear{% \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax\else % @set txiindexlquoteignore makes us ignore left quotes in the sort term. % (Introduced for FSFS 2nd ed.) \let`=\empty \fi % \expandafter\ifx\csname SETtxiindexbackslashignore\endcsname\relax\else \backslashdisappear \fi % \expandafter\ifx\csname SETtxiindexhyphenignore\endcsname\relax\else \def-{}% \fi \expandafter\ifx\csname SETtxiindexlessthanignore\endcsname\relax\else \def<{}% \fi \expandafter\ifx\csname SETtxiindexatsignignore\endcsname\relax\else \def\@{}% \fi } \gdef\indexnonalnumreappear{% \useindexbackslash \let-\normaldash \let<\normalless \def\@{@}% } } % \indexnofonts is used when outputting the strings to sort the index % by, and when constructing control sequence names. It eliminates all % control sequences and just writes whatever the best ASCII sort string % would be for a given command (usually its argument). % \def\indexnofonts{% % Accent commands should become @asis. \def\definedummyaccent##1{\let##1\asis}% % We can just ignore other control letters. \def\definedummyletter##1{\let##1\empty}% % All control words become @asis by default; overrides below. \let\definedummyword\definedummyaccent \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command % and is used in the definitions of the active chars like <, >, |, etc. % Likewise with the other plain tex font commands. %\let\tt=\asis % \def\ { }% \def\@{@}% \def\_{\normalunderscore}% \def\-{}% @- shouldn't affect sorting % \uccode`\1=`\{ \uppercase{\def\{{1}}% \uccode`\1=`\} \uppercase{\def\}{1}}% \let\lbracechar\{% \let\rbracechar\}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\DH{DZZ}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\TH{TH}% \def\aa{aa}% \def\ae{ae}% \def\dh{dzz}% \def\exclamdown{!}% \def\l{l}% \def\oe{oe}% \def\ordf{a}% \def\ordm{o}% \def\o{o}% \def\questiondown{?}% \def\ss{ss}% \def\th{th}% % \def\LaTeX{LaTeX}% \def\TeX{TeX}% % % Assorted special characters. % (The following {} will end up in the sort string, but that's ok.) \def\arrow{->}% \def\bullet{bullet}% \def\comma{,}% \def\copyright{copyright}% \def\dots{...}% \def\enddots{...}% \def\equiv{==}% \def\error{error}% \def\euro{euro}% \def\expansion{==>}% \def\geq{>=}% \def\guillemetleft{<<}% \def\guillemetright{>>}% \def\guilsinglleft{<}% \def\guilsinglright{>}% \def\leq{<=}% \def\minus{-}% \def\point{.}% \def\pounds{pounds}% \def\print{-|}% \def\quotedblbase{"}% \def\quotedblleft{"}% \def\quotedblright{"}% \def\quoteleft{`}% \def\quoteright{'}% \def\quotesinglbase{,}% \def\registeredsymbol{R}% \def\result{=>}% \def\textdegree{o}% % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. % makeinfo does not expand macros in the argument to @deffn, which ends up % writing an index entry, and texindex isn't prepared for an index sort entry % that starts with \. % % Since macro invocations are followed by braces, we can just redefine them % to take a single TeX argument. The case of a macro invocation that % goes to end-of-line is not handled. % \macrolist } \let\SETmarginindex=\relax % put index entries in margin (undocumented)? % Most index entries go through here, but \dosubind is the general case. % #1 is the index name, #2 is the entry text. \def\doind#1#2{\dosubind{#1}{#2}{}} % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. % TODO: Two-level index? Operation index? % Workhorse for all indexes. % #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 most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% \requireopenindexfile{#1}% % Store the main index entry text (including the third arg). \toks0 = {#2}% % If third arg is present, precede it with a space. \def\thirdarg{#3}% \ifx\thirdarg\empty \else \toks0 = \expandafter{\the\toks0 \space #3}% \fi % \edef\writeto{\csname#1indfile\endcsname}% % \safewhatsit\dosubindwrite }% \fi } % Check if an index file has been opened, and if not, open it. \def\requireopenindexfile#1{% \ifnum\csname #1indfile\endcsname=0 \expandafter\newwrite \csname#1indfile\endcsname \edef\suffix{#1}% % A .fls suffix would conflict with the file extension for the output % of -recorder, so use .f1s instead. \ifx\suffix\indexisfl\def\suffix{f1}\fi % Open the file \immediate\openout\csname#1indfile\endcsname \jobname.\suffix % Using \immediate here prevents an object entering into the current box, % which could confound checks such as those in \safewhatsit for preceding % skips. \fi} \def\indexisfl{fl} % Output \ as {\indexbackslash}, because \ is an escape character in % the index files. \let\indexbackslash=\relax {\catcode`\@=0 \catcode`\\=\active @gdef@useindexbackslash{@def\{{@indexbackslash}}} } % Definition for writing index entry text. \def\sortas#1{\ignorespaces}% % Definition for writing index entry sort key. Should occur at the at % the beginning of the index entry, like % @cindex @sortas{september} \september % The \ignorespaces takes care of following space, but there's no way % to remove space before it. { \catcode`\-=13 \gdef\indexwritesortas{% \begingroup \indexnonalnumreappear \indexwritesortasxxx} \gdef\indexwritesortasxxx#1{% \xdef\indexsortkey{#1}\endgroup} } % Write the entry in \toks0 to the index file. % \def\dosubindwrite{% % Put the index entry in the margin if desired. \ifx\SETmarginindex\relax\else \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% \fi % % Remember, we are within a group. \indexdummies % Must do this here, since \bf, etc expand at this stage \useindexbackslash % \indexbackslash isn't defined now so it will be output % as is; and it will print as backslash. % The braces around \indexbrace are recognized by texindex. % % Get the string to sort by, by processing the index entry with all % font commands turned off. {\indexnofonts \def\lbracechar{{\indexlbrace}}% \def\rbracechar{{\indexrbrace}}% \let\{=\lbracechar \let\}=\rbracechar \indexnonalnumdisappear \xdef\indexsortkey{}% \let\sortas=\indexwritesortas \edef\temp{\the\toks0}% \setbox\dummybox = \hbox{\temp}% Make sure to execute any \sortas \ifx\indexsortkey\empty \xdef\indexsortkey{\temp}% \ifx\indexsortkey\empty\xdef\indexsortkey{ }\fi \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 (four in the % subentry case), texindex reduces to two when writing the .??s % sorted result. \edef\temp{% \write\writeto{% \string\entry{\indexsortkey}{\noexpand\folio}{\the\toks0}}% }% \temp } \newbox\dummybox % used above % Take care of unwanted page breaks/skips around a whatsit: % % 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 or \pdfdest 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. % % But wait, there is a catch there: % We'll have to check whether \lastskip is zero skip. \ifdim is not % sufficient for this purpose, as it ignores stretch and shrink parts % of the skip. The only way seems to be to check the textual % representation of the skip. % % The following is almost like \def\zeroskipmacro{0.0pt} except that % the ``p'' and ``t'' characters have catcode \other, not 11 (letter). % \edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} % \newskip\whatsitskip \newcount\whatsitpenalty % % ..., ready, GO: % \def\safewhatsit#1{\ifhmode #1% \else % \lastskip and \lastpenalty cannot both be nonzero simultaneously. \whatsitskip = \lastskip \edef\lastskipmacro{\the\lastskip}% \whatsitpenalty = \lastpenalty % % If \lastskip is nonzero, that means the last item was a % skip. And since a skip is discardable, that means this % -\whatsitskip glue we're inserting is preceded by a % non-discardable item, therefore it is not a potential % breakpoint, therefore no \nobreak needed. \ifx\lastskipmacro\zeroskipmacro \else \vskip-\whatsitskip \fi % #1% % \ifx\lastskipmacro\zeroskipmacro % If \lastskip was zero, perhaps the last item was a penalty, and % perhaps it was >=10000, e.g., a \nobreak. In that case, we want % to re-insert the same penalty (values >10000 are used for various % signals); since we just inserted a non-discardable item, any % following glue (such as a \parskip) would be a breakpoint. For example: % @deffn deffn-whatever % @vindex index-whatever % Description. % would allow a break between the index-whatever whatsit % and the "Description." paragraph. \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi \else % On the other hand, if we had a nonzero \lastskip, % this make-up glue would be preceded by a non-discardable item % (the whatsit from the \write), so we must insert a \nobreak. \nobreak\vskip\whatsitskip \fi \fi} % 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). % \parseargdef\printindex{\begingroup \dobreak \chapheadingskip{10000}% % \smallfonts \rm \tolerance = 9500 \plainfrenchspacing \everypar = {}% don't want the \kern\-parindent from indentation suppression. % % 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 % See comment in \requireopenindexfile. \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi \openin 1 \jobname.\indexname s \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 \catcode`\\ = 0 \escapechar = `\\ % % 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 \thisline \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{\ttbackslash}% \let\indexlbrace\{ % Likewise, set these sequences for braces \let\indexrbrace\} % used in the sort key. \begindoublecolumns \let\entryorphanpenalty=\indexorphanpenalty % % Read input from the index file line by line. \loopdo \ifeof1 \let\firsttoken\relax \else \read 1 to \nextline \edef\act{\gdef\noexpand\firsttoken{\getfirsttoken\nextline}}% \act \fi \thisline % \ifeof1\else \let\thisline\nextline \repeat %% \enddoublecolumns \fi \fi \closein 1 \endgroup} \def\getfirsttoken#1{\expandafter\getfirsttokenx#1\endfirsttoken} \long\def\getfirsttokenx#1#2\endfirsttoken{\noexpand#1} \def\loopdo#1\repeat{\def\body{#1}\loopdoxxx} \def\loopdoxxx{\let\next=\relax\body\let\next=\loopdoxxx\fi\next} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. {\catcode`\/=13 \catcode`\-=13 \catcode`\^=13 \catcode`\~=13 \catcode`\_=13 \catcode`\|=13 \catcode`\<=13 \catcode`\>=13 \catcode`\+=13 \catcode`\"=13 \catcode`\$=3 \gdef\initialglyphs{% % Some changes for non-alphabetic characters. Using the glyphs from the % math fonts looks more consistent than the typewriter font used elsewhere % for these characters. \def\indexbackslash{\math{\backslash}}% \let\\=\indexbackslash % % Can't get bold backslash so don't use bold forward slash \catcode`\/=13 \def/{{\secrmnotbold \normalslash}}% \def-{{\normaldash\normaldash}}% en dash `--' \def^{{\chapbf \normalcaret}}% \def~{{\chapbf \normaltilde}}% \def\_{% \leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }% \def|{$\vert$}% \def<{$\less$}% \def>{$\gtr$}% \def+{$\normalplus$}% }} \def\initial{% \bgroup \initialglyphs \initialx } \def\initialx#1{% % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. % The glue before the bonus allows a little bit of space at the % bottom of a column to reduce an increase in inter-line spacing. \nobreak \vskip 0pt plus 5\baselineskip \penalty -300 \vskip 0pt plus -5\baselineskip % % 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 1\baselineskip \leftline{\secfonts \kern-0.05em \secbf #1}% % \secfonts is inside the argument of \leftline so that the change of % \baselineskip will not affect any glue inserted before the vbox that % \leftline creates. % Do our best not to break after the initial. \nobreak \vskip .33\baselineskip plus .1\baselineskip \egroup % \initialglyphs } \newdimen\entryrightmargin \entryrightmargin=0pt % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. % \def\entry{% \begingroup % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % No extra space above this paragraph. \parskip = 0in % % When reading the text of entry, convert explicit line breaks % from @* into spaces. The user might give these in long section % titles, for instance. \def\*{\unskip\space\ignorespaces}% \def\entrybreak{\hfil\break}% An undocumented command % % A bit of stretch before each entry for the benefit of balancing % columns. \vskip 0pt plus0.5pt % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\entrybreak{\unskip\space\ignorespaces}% \def\doentry{% % Save the text of the entry \global\setbox\boxA=\hbox\bgroup \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. % Not absorbing as a macro argument reduces the chance of problems % with catcodes occurring. } {\catcode`\@=11 \gdef\finishentry#1{% \egroup % end box A \dimen@ = \wd\boxA % Length of text of entry \global\setbox\boxA=\hbox\bgroup\unhbox\boxA % #1 is the page number. % % Get the width of the page numbers, and only use % leaders if they are present. \global\setbox\boxB = \hbox{#1}% \ifdim\wd\boxB = 0pt \null\nobreak\hfill\ % \else % \null\nobreak\indexdotfill % Have leaders before the page number. % \ifpdf \pdfgettoks#1.% \bgroup\let\domark\relax \hskip\skip\thinshrinkable\the\toksA \egroup % The redefinion of \domark stops marks being added in \pdflink to % preserve coloured links across page boundaries. Otherwise the marks % would get in the way of \lastbox in \insertindexentrybox. \else \hskip\skip\thinshrinkable #1% \fi \fi \egroup % end \boxA \ifdim\wd\boxB = 0pt \global\setbox\entryindexbox=\vbox{\unhbox\boxA}% \else \global\setbox\entryindexbox=\vbox\bgroup \prevdepth=\entrylinedepth \noindent % We want the text of the entries to be aligned to the left, and the % page numbers to be aligned to the right. % \advance\leftskip by 0pt plus 1fil \advance\leftskip by 0pt plus -1fill \rightskip = 0pt plus -1fil \advance\rightskip by 0pt plus 1fill % Cause last line, which could consist of page numbers on their own % if the list of page numbers is long, to be aligned to the right. \parfillskip=0pt plus -1fill % \hangindent=1em % \advance\rightskip by \entryrightmargin % Determine how far we can stretch into the margin. % This allows, e.g., "Appendix H GNU Free Documentation License" to % fit on one line in @letterpaper format. \ifdim\entryrightmargin>2.1em \dimen@i=2.1em \else \dimen@i=0em \fi \advance \parfillskip by 0pt minus 1\dimen@i % \dimen@ii = \hsize \advance\dimen@ii by -1\leftskip \advance\dimen@ii by -1\entryrightmargin \advance\dimen@ii by 1\dimen@i \ifdim\wd\boxA > \dimen@ii % If the entry doesn't fit in one line \ifdim\dimen@ > 0.8\dimen@ii % due to long index text \dimen@ = 0.7\dimen@ % Try to split the text roughly evenly \dimen@ii = \hsize \advance \dimen@ii by -1em \ifnum\dimen@>\dimen@ii % If the entry is too long, use the whole line \dimen@ = \dimen@ii \fi \advance\leftskip by 0pt plus 1fill % ragged right \advance \dimen@ by 1\rightskip \parshape = 2 0pt \dimen@ 1em \dimen@ii % Ideally we'd add a finite glue at the end of the first line only, but % TeX doesn't seem to provide a way to do such a thing. \fi\fi \unhbox\boxA % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % Word spacing - no stretch \spaceskip=\fontdimen2\font minus \fontdimen4\font % \linepenalty=1000 % Discourage line breaks. \hyphenpenalty=5000 % Discourage hyphenation. % \par % format the paragraph \egroup % The \vbox \fi \endgroup % delay text of entry until after penalty \bgroup\aftergroup\insertindexentrybox \entryorphanpenalty }} \newskip\thinshrinkable \skip\thinshrinkable=.15em minus .15em \newbox\entryindexbox \def\insertindexentrybox{% \copy\entryindexbox % The following gets the depth of the last box. This is for even % line spacing when entries span several lines. \setbox\dummybox\vbox{% \unvbox\entryindexbox \nointerlineskip \lastbox \global\entrylinedepth=\prevdepth }% % Note that we couldn't simply \unvbox\entryindexbox followed by % \nointerlineskip\lastbox to remove the last box and then reinstate it, % because this resets how far the box has been \moveleft'ed to 0. \unvbox % doesn't affect \prevdepth either. } \newdimen\entrylinedepth % Default is no penalty \let\entryorphanpenalty\egroup % Used from \printindex. \firsttoken should be the first token % after the \entry. If it's not another \entry, we are at the last % line of a group of index entries, so insert a penalty to discourage % orphaned index entries. \long\def\indexorphanpenalty{% \def\isentry{\entry}% \ifx\firsttoken\isentry \else \unskip\penalty 9000 % The \unskip here stops breaking before the glue. It relies on the % \vskip above being there, otherwise there is an error % "You can't use `\unskip' in vertical mode". There has to be glue % in the current vertical list that hasn't been added to the % "current page". See Chapter 24 of the TeXbook. This contradicts % Section 8.3.7 in "TeX by Topic," though. \fi \egroup % now comes the box added with \aftergroup } % Like plain.tex's \dotfill, except uses up at least 1 em. % The filll stretch here overpowers both the fil and fill stretch to push % the page number to the right. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1filll} \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 \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else #2 \fi \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 % private names \newbox\partialpage \newdimen\doublecolumnhsize \newdimen\doublecolumntopgap \doublecolumntopgap = 0pt % Use inside an output routine to save \topmark and \firstmark \def\savemarks{% \global\savedtopmark=\expandafter{\topmark }% \global\savedfirstmark=\expandafter{\firstmark }% } \newtoks\savedtopmark \newtoks\savedfirstmark % Set \topmark and \firstmark for next time \output runs. % Can't be run from withinside \output (because any material % added while an output routine is active, including % penalties, is saved for after it finishes). The page so far % should be empty, otherwise what's on it will be thrown away. \def\restoremarks{% \mark{\the\savedtopmark}% \bgroup\output = {% \setbox\dummybox=\box\PAGE }abc\eject\egroup % "abc" because output routine doesn't fire for a completely empty page. \mark{\the\savedfirstmark}% } \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % If not much space left on page, start a new page. \ifdim\pagetotal>0.8\vsize\vfill\eject\fi % % 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 }% \savemarks }% \eject % run that output routine to set \partialpage \restoremarks % % We recover the two marks that the last output routine saved in order % to propagate the information in marks added around a chapter heading, % which could be otherwise be lost by the time the final page is output. % % % 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.) \global\doublecolumntopgap = \topskip \global\advance\doublecolumntopgap by -1\baselineskip \advance\vsize by -1\doublecolumntopgap \vsize = 2\vsize \topskip=0pt \global\entrylinedepth=0pt\relax } % The double-column output routine for all double-column pages except % the last, which is done by \balancecolumns. % \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 \advance\dimen@ by -\ht\partialpage % % box0 will be the left-hand column, box2 the right. \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty } % % Re-output the contents of the output page -- any previous material, % followed by the two boxes we just split, in box0 and box2. \def\pagesofar{% \unvbox\partialpage % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize \vbox{% \vskip\doublecolumntopgap \hbox to\pagewidth{\box0\hfil\box2}}% } % Finished with with double columns. \def\enddoublecolumns{% % The following penalty ensures that the page builder is exercised % _before_ we change the output routine. This is necessary in the % following situation: % % The last section of the index consists only of a single entry. % Before this section, \pagetotal is less than \pagegoal, so no % break occurs before the last section starts. However, the last % section, consisting of \initial and the single \entry, does not % fit on the page and has to be broken off. Without the following % penalty the page builder will not be exercised until \eject % below, and by that time we'll already have changed the output % routine to the \balancecolumns version, so the next-to-last % double-column page will be processed with \balancecolumns, which % is wrong: The two columns will go to the main vertical list, with % the broken-off section in the recent contributions. As soon as % the output routine finishes, TeX starts reconsidering the page % break. The two columns and the broken-off section both fit on the % page, because the two columns now take up only half of the page % goal. When TeX sees \eject from below which follows the final % section, it invokes the new output routine that we've set after % \balancecolumns below; \onepageout will try to fit the two columns % and the final section into the vbox of \pageheight (see % \pagebody), causing an overfull box. % % Note that glue won't work here, because glue does not exercise the % page builder, unlike penalties (see The TeXbook, pp. 280-281). \penalty0 % \output = {% % Split the last of the double-column material. \savemarks \balancecolumns % % Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. \global\output = {\onepageout{\pagecontents\PAGE}}% }% \eject \endgroup % started in \begindoublecolumns \restoremarks % Leave the double-column material on the current page, no automatic % page break. \box\balancedcolumns % % \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 } \newbox\balancedcolumns \setbox\balancedcolumns=\vbox{shouldnt see this}% % % Only called for the last of the double column material. \doublecolumnout % does the others. \def\balancecolumns{% \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \ifdim\dimen@<14\baselineskip % Don't split a short final column in two. \setbox2=\vbox{}% \else \divide\dimen@ by 2 % target to split to \dimen@ii = \dimen@ \splittopskip = \topskip % Loop until the second column is no higher than the first {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ % Remove glue from bottom of first column to % make sure it is higher than the second. \global\setbox1 = \vbox{\unvbox1\unpenalty\unskip}% \ifdim\ht3>\ht1 \global\advance\dimen@ by 1pt \repeat }% \multiply\dimen@ii by 4 \divide\dimen@ii by 5 \ifdim\ht3<\dimen@ii % Column heights are too different, so don't make their bottoms % flush with each other. The glue at the end of the second column % allows a second column to stretch, reducing the difference in % height between the two. \setbox0=\vbox to\dimen@{\unvbox1\vfill}% \setbox2=\vbox to\dimen@{\unvbox3\vskip 0pt plus 0.3\ht0}% \else \setbox0=\vbox to\dimen@{\unvbox1}% \setbox2=\vbox to\dimen@{\unvbox3}% \fi \fi % \global\setbox\balancedcolumns=\vbox{\pagesofar}% } \catcode`\@ = \other \message{sectioning,} % Chapters, sections, etc. % Let's start with @part. \outer\parseargdef\part{\partzzz{#1}} \def\partzzz#1{% \chapoddpage \null \vskip.3\vsize % move it down on the page a bit \begingroup \noindent \titlefonts\rmisbold #1\par % the text \let\lastnode=\empty % no node to associate with \writetocentry{part}{#1}{}% but put it in the toc \headingsoff % no headline or footline on the part page % This outputs a mark at the end of the page that clears \thischapter % and \thissection, as is done in \startcontents. \let\pchapsepmacro\relax \chapmacro{}{Yomitfromtoc}{}% \chapoddpage \endgroup } % \unnumberedno is an oxymoron. But we count the unnumbered % sections so that we can refer to them unambiguously in the pdf % outlines by their "section number". We avoid collisions with chapter % numbers by starting them at 10000. (If a document ever has 10000 % chapters, we're in trouble anyway, I'm sure.) \newcount\unnumberedno \unnumberedno = 10000 \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} % We do the following ugly conditional instead of the above simple % construct for the sake of pdftex, which needs the actual % letter in the expansion, not just typeset. % \def\appendixletter{% \ifnum\appendixno=`A A% \else\ifnum\appendixno=`B B% \else\ifnum\appendixno=`C C% \else\ifnum\appendixno=`D D% \else\ifnum\appendixno=`E E% \else\ifnum\appendixno=`F F% \else\ifnum\appendixno=`G G% \else\ifnum\appendixno=`H H% \else\ifnum\appendixno=`I I% \else\ifnum\appendixno=`J J% \else\ifnum\appendixno=`K K% \else\ifnum\appendixno=`L L% \else\ifnum\appendixno=`M M% \else\ifnum\appendixno=`N N% \else\ifnum\appendixno=`O O% \else\ifnum\appendixno=`P P% \else\ifnum\appendixno=`Q Q% \else\ifnum\appendixno=`R R% \else\ifnum\appendixno=`S S% \else\ifnum\appendixno=`T T% \else\ifnum\appendixno=`U U% \else\ifnum\appendixno=`V V% \else\ifnum\appendixno=`W W% \else\ifnum\appendixno=`X X% \else\ifnum\appendixno=`Y Y% \else\ifnum\appendixno=`Z Z% % The \the is necessary, despite appearances, because \appendixletter is % expanded while writing the .toc file. \char\appendixno is not % expandable, thus it is written literally, thus all appendixes come out % with the same letter (or @) in the toc without it. \else\char\the\appendixno \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} % Each @chapter defines these (using marks) as the number+name, number % and name of the chapter. Page headings and footings can use % these. @section does likewise. \def\thischapter{} \def\thischapternum{} \def\thischaptername{} \def\thissection{} \def\thissectionnum{} \def\thissectionname{} \newcount\absseclevel % used to calculate proper heading level \newcount\secbase\secbase=0 % @raisesections/@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 % we only have subsub. \chardef\maxseclevel = 3 % % A numbered section within an unnumbered changes to unnumbered too. % To achieve this, remember the "biggest" unnum. sec. we are currently in: \chardef\unnlevel = \maxseclevel % % Trace whether the current chapter is an appendix or not: % \chapheadtype is "N" or "A", unnumbered chapters are ignored. \def\chapheadtype{N} % Choose a heading macro % #1 is heading type % #2 is heading level % #3 is text for heading \def\genhead#1#2#3{% % Compute the abs. sec. level: \absseclevel=#2 \advance\absseclevel by \secbase % Make sure \absseclevel doesn't fall outside the range: \ifnum \absseclevel < 0 \absseclevel = 0 \else \ifnum \absseclevel > 3 \absseclevel = 3 \fi \fi % The heading type: \def\headtype{#1}% \if \headtype U% \ifnum \absseclevel < \unnlevel \chardef\unnlevel = \absseclevel \fi \else % Check for appendix sections: \ifnum \absseclevel = 0 \edef\chapheadtype{\headtype}% \else \if \headtype A\if \chapheadtype N% \errmessage{@appendix... within a non-appendix chapter}% \fi\fi \fi % Check for numbered within unnumbered: \ifnum \absseclevel > \unnlevel \def\headtype{U}% \else \chardef\unnlevel = 3 \fi \fi % Now print the heading: \if \headtype U% \ifcase\absseclevel \unnumberedzzz{#3}% \or \unnumberedseczzz{#3}% \or \unnumberedsubseczzz{#3}% \or \unnumberedsubsubseczzz{#3}% \fi \else \if \headtype A% \ifcase\absseclevel \appendixzzz{#3}% \or \appendixsectionzzz{#3}% \or \appendixsubseczzz{#3}% \or \appendixsubsubseczzz{#3}% \fi \else \ifcase\absseclevel \chapterzzz{#3}% \or \seczzz{#3}% \or \numberedsubseczzz{#3}% \or \numberedsubsubseczzz{#3}% \fi \fi \fi \suppressfirstparagraphindent } % an interface: \def\numhead{\genhead N} \def\apphead{\genhead A} \def\unnmhead{\genhead U} % @chapter, @appendix, @unnumbered. Increment top-level counter, reset % all lower-level sectioning counters to zero. % % Also set \chaplevelprefix, which we prepend to @float sequence numbers % (e.g., figures), q.v. By default (before any chapter), that is empty. \let\chaplevelprefix = \empty % \outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz#1{% % section resetting is \global in case the chapter is in a group, such % as an @include file. \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\chapno by 1 % % Used for \float. \gdef\chaplevelprefix{\the\chapno.}% \resetallfloatnos % % \putwordChapter can contain complex things in translations. \toks0=\expandafter{\putwordChapter}% \message{\the\toks0 \space \the\chapno}% % % Write the actual heading. \chapmacro{#1}{Ynumbered}{\the\chapno}% % % So @section and the like are numbered underneath this chapter. \global\let\section = \numberedsec \global\let\subsection = \numberedsubsec \global\let\subsubsection = \numberedsubsubsec } \outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz % \def\appendixzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\appendixno by 1 \gdef\chaplevelprefix{\appendixletter.}% \resetallfloatnos % % \putwordAppendix can contain complex things in translations. \toks0=\expandafter{\putwordAppendix}% \message{\the\toks0 \space \appendixletter}% % \chapmacro{#1}{Yappendix}{\appendixletter}% % \global\let\section = \appendixsec \global\let\subsection = \appendixsubsec \global\let\subsubsection = \appendixsubsubsec } % normally unnmhead0 calls unnumberedzzz: \outer\parseargdef\unnumbered{\unnmhead0{#1}} \def\unnumberedzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\unnumberedno by 1 % % Since an unnumbered has no number, no prefix for figures. \global\let\chaplevelprefix = \empty \resetallfloatnos % % 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)}% % \chapmacro{#1}{Ynothing}{\the\unnumberedno}% % \global\let\section = \unnumberedsec \global\let\subsection = \unnumberedsubsec \global\let\subsubsection = \unnumberedsubsubsec } % @centerchap is like @unnumbered, but the heading is centered. \outer\parseargdef\centerchap{% \let\centerparametersmaybe = \centerparameters \unnmhead0{#1}% \let\centerparametersmaybe = \relax } % @top is like @unnumbered. \let\top\unnumbered % Sections. % \outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz \def\seczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% } % normally calls appendixsectionzzz: \outer\parseargdef\appendixsection{\apphead1{#1}} \def\appendixsectionzzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% } \let\appendixsec\appendixsection % normally calls unnumberedseczzz: \outer\parseargdef\unnumberedsec{\unnmhead1{#1}} \def\unnumberedseczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% } % Subsections. % % normally calls numberedsubseczzz: \outer\parseargdef\numberedsubsec{\numhead2{#1}} \def\numberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% } % normally calls appendixsubseczzz: \outer\parseargdef\appendixsubsec{\apphead2{#1}} \def\appendixsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno}% } % normally calls unnumberedsubseczzz: \outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} \def\unnumberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno}% } % Subsubsections. % % normally numberedsubsubseczzz: \outer\parseargdef\numberedsubsubsec{\numhead3{#1}} \def\numberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynumbered}% {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% } % normally appendixsubsubseczzz: \outer\parseargdef\appendixsubsubsec{\apphead3{#1}} \def\appendixsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% } % normally unnumberedsubsubseczzz: \outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} \def\unnumberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% } % 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. \let\section = \numberedsec \let\subsection = \numberedsubsec \let\subsubsection = \numberedsubsubsec % Define @majorheading, @heading and @subheading \def\majorheading{% {\advance\chapheadingskip by 10pt \chapbreak }% \parsearg\chapheadingzzz } \def\chapheading{\chapbreak \parsearg\chapheadingzzz} \def\chapheadingzzz#1{% \vbox{\chapfonts \raggedtitlesettings #1\par}% \nobreak\bigskip \nobreak \suppressfirstparagraphindent } % @heading, @subheading, @subsubheading. \parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} % 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} % Parameter controlling skip before chapter headings (if needed) \newskip\chapheadingskip % Define plain chapter starts, and page on/off switching for it. \def\chapbreak{\dobreak \chapheadingskip {-4000}} % Start a new page \def\chappager{\par\vfill\supereject} % \chapoddpage - start on an odd page for a new chapter % Because \domark is called before \chapoddpage, the filler page will % get the headings for the next chapter, which is wrong. But we don't % care -- we just disable all headings on the filler page. \def\chapoddpage{% \chappager \ifodd\pageno \else \begingroup \headingsoff \null \chappager \endgroup \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 % \chapmacro - Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % Not used for @heading series. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yappendixkeyword{Yappendix} \def\Yomitfromtockeyword{Yomitfromtoc} % \def\chapmacro#1#2#3{% \expandafter\ifx\thisenv\titlepage\else \checkenv{}% chapters, etc., should not start inside an environment. \fi % FIXME: \chapmacro is currently called from inside \titlepage when % \setcontentsaftertitlepage to print the "Table of Contents" heading, but % this should probably be done by \sectionheading with an option to print % in chapter size. % % Insert the first mark before the heading break (see notes for \domark). \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% \gdef\thissection{}}% % \def\temptype{#2}% \ifx\temptype\Ynothingkeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{\thischaptername}}% \else\ifx\temptype\Yomitfromtockeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{}}% \else\ifx\temptype\Yappendixkeyword \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\appendixletter}% % \noexpand\putwordAppendix avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordAppendix{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \else \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\the\chapno}% % \noexpand\putwordChapter avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordChapter{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \fi\fi\fi % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert the chapter heading break. \pchapsepmacro % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \domark % {% \chapfonts \rmisbold \let\footnote=\errfootnoteheading % give better error message % % Have to define \lastsection before calling \donoderef, because the % xref code eventually uses it. On the other hand, it has to be called % after \pchapsepmacro, or the headline will change too soon. \gdef\lastsection{#1}% % % Only insert the separating space if we have a chapter/appendix % number, and don't print the unnumbered ``number''. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unnchap}% \else\ifx\temptype\Yomitfromtockeyword \setbox0 = \hbox{}% contents like unnumbered, but no toc entry \def\toctype{omit}% \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% \def\toctype{app}% \else \setbox0 = \hbox{#3\enspace}% \def\toctype{numchap}% \fi\fi\fi % % Write the toc entry for this chapter. Must come before the % \donoderef, because we include the current node name in the toc % entry, and \donoderef resets it to empty. \writetocentry{\toctype}{#1}{#3}% % % For pdftex, we have to write out the node definition (aka, make % the pdfdest) after any page break, but before the actual text has % been typeset. If the destination for the pdf outline is after the % text, then jumping from the outline may wind up with the text not % being visible, for instance under high magnification. \donoderef{#2}% % % Typeset the actual heading. \nobreak % Avoid page breaks at the interline glue. \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe \unhbox0 #1\par}% }% \nobreak\bigskip % no page break after a chapter title \nobreak } % @centerchap -- centered and unnumbered. \let\centerparametersmaybe = \relax \def\centerparameters{% \advance\rightskip by 3\rightskip \leftskip = \rightskip \parfillskip = 0pt } % I don't think this chapter style is supported any more, so I'm not % updating it with the new noderef stuff. We'll see. --karl, 11aug03. % \def\setchapterstyle #1 {\csname CHAPF#1\endcsname} % \def\unnchfopen #1{% \chapoddpage \vbox{\chapfonts \raggedtitlesettings #1\par}% \nobreak\bigskip\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 \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}% \nobreak\bigskip \nobreak } \def\CHAPFopen{% \global\let\chapmacro=\chfopen \global\let\centerchapmacro=\centerchfopen} % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % \newskip\secheadingskip \def\secheadingbreak{\dobreak \secheadingskip{-1000}} % Subsection titles. \newskip\subsecheadingskip \def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} % Subsubsection titles. \def\subsubsecheadingskip{\subsecheadingskip} \def\subsubsecheadingbreak{\subsecheadingbreak} % Print any size, any type, section title. % % #1 is the text of the title, % #2 is the section level (sec/subsec/subsubsec), % #3 is the section type (Ynumbered, Ynothing, Yappendix, Yomitfromtoc), % #4 is the section number. % \def\seckeyword{sec} % \def\sectionheading#1#2#3#4{% {% \def\sectionlevel{#2}% \def\temptype{#3}% % % It is ok for the @heading series commands to appear inside an % environment (it's been historically allowed, though the logic is % dubious), but not the others. \ifx\temptype\Yomitfromtockeyword\else \checkenv{}% non-@*heading should not be in an environment. \fi \let\footnote=\errfootnoteheading % % Switch to the right set of fonts. \csname #2fonts\endcsname \rmisbold % % Insert first mark before the heading break (see notes for \domark). \let\prevsectiondefs=\lastsectiondefs \ifx\temptype\Ynothingkeyword \ifx\sectionlevel\seckeyword \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% \gdef\thissection{\thissectionname}}% \fi \else\ifx\temptype\Yomitfromtockeyword % Don't redefine \thissection. \else\ifx\temptype\Yappendixkeyword \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \else \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \fi\fi\fi % % Go into vertical mode. Usually we'll already be there, but we % don't want the following whatsit to end up in a preceding paragraph % if the document didn't happen to have a blank line. \par % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert space above the heading. \csname #2headingbreak\endcsname % % Now the second mark, after the heading break. No break points % between here and the heading. \global\let\prevsectiondefs=\lastsectiondefs \domark % % Only insert the space after the number if we have a section number. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unn}% \gdef\lastsection{#1}% \else\ifx\temptype\Yomitfromtockeyword % for @headings -- no section number, don't include in toc, % and don't redefine \lastsection. \setbox0 = \hbox{}% \def\toctype{omit}% \let\sectionlevel=\empty \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{#4\enspace}% \def\toctype{app}% \gdef\lastsection{#1}% \else \setbox0 = \hbox{#4\enspace}% \def\toctype{num}% \gdef\lastsection{#1}% \fi\fi\fi % % Write the toc entry (before \donoderef). See comments in \chapmacro. \writetocentry{\toctype\sectionlevel}{#1}{#4}% % % Write the node reference (= pdf destination for pdftex). % Again, see comments in \chapmacro. \donoderef{#3}% % % Interline glue will be inserted when the vbox is completed. % That glue will be a valid breakpoint for the page, since it'll be % preceded by a whatsit (usually from the \donoderef, or from the % \writetocentry if there was no node). We don't want to allow that % break, since then the whatsits could end up on page n while the % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. \nobreak % % Output the actual section heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright \hangindent=\wd0 % zero if no section number \unhbox0 #1}% }% % Add extra space after the heading -- half of whatever came above it. % Don't allow stretch, though. \kern .5 \csname #2headingskip\endcsname % % Do not let the kern be a potential breakpoint, as it would be if it % was followed by glue. \nobreak % % We'll almost certainly start a paragraph next, so don't let that % glue accumulate. (Not a breakpoint because it's preceded by a % discardable item.) However, when a paragraph is not started next % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out % or the negative glue will cause weirdly wrong output, typically % obscuring the section heading with something else. \vskip-\parskip % % This is so the last item on the main vertical list is a known % \penalty > 10000, so \startdefun, etc., can recognize the situation % and do the needful. \penalty 10001 } \message{toc,} % Table of contents. \newwrite\tocfile % Write an entry to the toc file, opening it if necessary. % Called from @chapter, etc. % % Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} % We append the current node name (if any) and page number as additional % arguments for the \{chap,sec,...}entry macros which will eventually % read this. The node name is used in the pdf outlines as the % destination to jump to. % % We open the .toc file for writing here instead of at @setfilename (or % any other fixed time) so that @contents can be anywhere in the document. % But if #1 is `omit', then we don't do anything. This is used for the % table of contents chapter openings themselves. % \newif\iftocfileopened \def\omitkeyword{omit}% % \def\writetocentry#1#2#3{% \edef\writetoctype{#1}% \ifx\writetoctype\omitkeyword \else \iftocfileopened\else \immediate\openout\tocfile = \jobname.toc \global\tocfileopenedtrue \fi % \iflinks {\atdummies \edef\temp{% \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% \temp }% \fi \fi % % Tell \shipout to create a pdf destination on each page, if we're % writing pdf. These are used in the table of contents. We can't % just write one on every page because the title pages are numbered % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. \ifpdf \global\pdfmakepagedesttrue \fi } % These characters do not print properly in the Computer Modern roman % fonts, so we must take special care. This is more or less redundant % with the Texinfo input format setup at the end of this file. % \def\activecatcodes{% \catcode`\"=\active \catcode`\$=\active \catcode`\<=\active \catcode`\>=\active \catcode`\\=\active \catcode`\^=\active \catcode`\_=\active \catcode`\|=\active \catcode`\~=\active } % Read the toc file, which is essentially Texinfo input. \def\readtocfile{% \setupdatafile \activecatcodes \input \tocreadfilename } \newskip\contentsrightmargin \contentsrightmargin=1in \newcount\savepageno \newcount\lastnegativepageno \lastnegativepageno = -1 % 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. \chapmacro{#1}{Yomitfromtoc}{}% % \savepageno = \pageno \begingroup % Set up to handle contents files properly. \raggedbottom % Worry more about breakpoints than the bottom. \entryrightmargin=\contentsrightmargin % Don't use the full line length. % % Roman numerals for page numbers. \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi } % redefined for the two-volume lispref. We always output on % \jobname.toc even if this is redefined. % \def\tocreadfilename{\jobname.toc} % Normal (long) toc. % \def\contents{% \startcontents{\putwordTOC}% \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \ifeof 1 \else \pdfmakeoutlines \fi \closein 1 \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } % And just the chapters. \def\summarycontents{% \startcontents{\putwordShortTOC}% % \let\partentry = \shortpartentry \let\numchapentry = \shortchapentry \let\appentry = \shortchapentry \let\unnchapentry = \shortunnchapentry % We want a true roman here for the page numbers. \secfonts \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl \let\tt=\shortconttt \rm \hyphenpenalty = 10000 \advance\baselineskip by 1pt % Open it up a little. \def\numsecentry##1##2##3##4{} \let\appsecentry = \numsecentry \let\unnsecentry = \numsecentry \let\numsubsecentry = \numsecentry \let\appsubsecentry = \numsecentry \let\unnsubsecentry = \numsecentry \let\numsubsubsecentry = \numsecentry \let\appsubsubsecentry = \numsecentry \let\unnsubsubsecentry = \numsecentry \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \closein 1 \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } \let\shortcontents = \summarycontents % Typeset the label for a chapter or appendix for the short contents. % The arg is, e.g., `A' for an appendix, or `3' for a chapter. % \def\shortchaplabel#1{% % This space should be enough, since a single number is .5em, and the % widest letter (M) is 1em, at least in the Computer Modern fonts. % But use \hss just in case. % (This space doesn't include the extra space that gets added after % the label; that gets put in by \shortchapentry above.) % % We'd like to right-justify chapter numbers, but that looks strange % with appendix letters. And right-justifying numbers and % left-justifying letters looks strange when there is less than 10 % chapters. Have to read the whole toc once to know how many chapters % there are before deciding ... \hbox to 1em{#1\hss}% } % 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, ... % Parts, in the main contents. Replace the part number, which doesn't % exist, with an empty box. Let's hope all the numbers have the same width. % Also ignore the page number, which is conventionally not printed. \def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}} \def\partentry#1#2#3#4{\dochapentry{\numeralbox\labelspace#1}{}} % % Parts, in the short toc. \def\shortpartentry#1#2#3#4{% \penalty-300 \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip \shortchapentry{{\bf #1}}{\numeralbox}{}{}% } % Chapters, in the main contents. \def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% } % Appendices, in the main contents. % Need the word Appendix, and a fixed-size box. % \def\appendixbox#1{% % We use M since it's probably the widest letter. \setbox0 = \hbox{\putwordAppendix{} M}% \hbox to \wd0{\putwordAppendix{} #1\hss}} % \def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\hskip.7em#1}{#4}} % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} \def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} \let\appsecentry=\numsecentry \def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} % Subsections. \def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} \let\appsubsecentry=\numsubsecentry \def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} % And subsubsections. \def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} \let\appsubsubsecentry=\numsubsubsecentry \def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} % This parameter controls the indentation of the various levels. % Same as \defaultparindent. \newdimen\tocindent \tocindent = 15pt % 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 % Move the page numbers slightly to the right \advance\entryrightmargin by -0.05em \chapentryfonts \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} % We use the same \entry macro as for the index entries. \let\tocentry = \entry % 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} \def\subsecentryfonts{\textfonts} \def\subsubsecentryfonts{\textfonts} \message{environments,} % @foo ... @end foo. % @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 @ character. \envdef\tex{% \setupmarkupstyle{tex}% \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie \catcode `\%=14 \catcode `\+=\other \catcode `\"=\other \catcode `\|=\other \catcode `\<=\other \catcode `\>=\other \catcode `\`=\other \catcode `\'=\other \escapechar=`\\ % % ' is active in math mode (mathcode"8000). So reset it, and all our % other math active characters (just in case), to plain's definitions. \mathactive % % Inverse of the list at the beginning of the file. \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\indent=\ptexindent \let\noindent=\ptexnoindent \let\{=\ptexlbrace \let\+=\tabalign \let\}=\ptexrbrace \let\/=\ptexslash \let\sp=\ptexsp \let\*=\ptexstar %\let\sup=\ptexsup % do not redefine, we want @sup to work in math mode \let\t=\ptext \expandafter \let\csname top\endcsname=\ptextop % we've made it outer \let\frenchspacing=\plainfrenchspacing % \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% \def\@{@}% } % There is no need to define \Etex. % Define @lisp ... @end lisp. % @lisp environment forms a group so it can rebind things, % including the definition of @end lisp (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} % 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{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip \ifnum\lastpenalty<10000 % Penalize breaking before the environment, because preceding text % often leads into it. \penalty100 \fi \vskip\envskipamount \fi \fi }} \def\afterenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip % it's not a good place to break if the last penalty was \nobreak % or better ... \ifnum\lastpenalty<10000 \penalty-50 \fi \vskip\envskipamount \fi \fi }} % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will % also clear it, so that its embedded environments do the narrowing again. \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 \envdef\cartouche{% \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts \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 % % If this cartouche directly follows a sectioning command, we need the % \parskip glue (backspaced over by default) or the cartouche can % collide with the section heading. \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi % \setbox\groupbox=\vbox\bgroup \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup \hskip\lskip \vrule\kern3pt \vbox\bgroup \kern3pt \hsize=\cartinner \baselineskip=\normbskip \lineskip=\normlskip \parskip=\normpskip \vskip -\parskip \comment % For explanation, see the end of def\group. } \def\Ecartouche{% \ifhmode\par\fi \kern3pt \egroup \kern3pt\vrule \hskip\rskip \egroup \cartbot \egroup \addgroupbox \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \newdimen\nonfillparindent \def\nonfillstart{% \aboveenvbreak \ifdim\hfuzz < 12pt \hfuzz = 12pt \fi % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt % Turn off paragraph indentation but redefine \indent to emulate % the normal \indent. \nonfillparindent=\parindent \parindent = 0pt \let\indent\nonfillindent % \emergencystretch = 0pt % don't try to avoid overfull boxes \ifx\nonarrowing\relax \advance \leftskip by \lispnarrowing \exdentamount=\lispnarrowing \else \let\nonarrowing = \relax \fi \let\exdent=\nofillexdent } \begingroup \obeyspaces % We want to swallow spaces (but not other tokens) after the fake % @indent in our nonfill-environments, where spaces are normally % active and set to @tie, resulting in them not being ignored after % @indent. \gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}% \gdef\nonfillindentcheck{% \ifx\temp % \expandafter\nonfillindentgobble% \else% \leavevmode\nonfillindentbox% \fi% }% \endgroup \def\nonfillindentgobble#1{\nonfillindent} \def\nonfillindentbox{\hbox to \nonfillparindent{\hss}} % If you want all examples etc. small: @set dispenvsize small. % If you want even small examples the full size: @set dispenvsize nosmall. % This affects the following displayed environments: % @example, @display, @format, @lisp % \def\smallword{small} \def\nosmallword{nosmall} \let\SETdispenvsize\relax \def\setnormaldispenv{% \ifx\SETdispenvsize\smallword % end paragraph for sake of leading, in case document has no blank % line. This is redundant with what happens in \aboveenvbreak, but % we need to do it before changing the fonts, and it's inconvenient % to change the fonts afterward. \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } \def\setsmalldispenv{% \ifx\SETdispenvsize\nosmallword \else \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } % We often define two environments, @foo and @smallfoo. % Let's do it in one command. #1 is the env name, #2 the definition. \def\makedispenvdef#1#2{% \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}% \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}% \expandafter\let\csname E#1\endcsname \afterenvbreak \expandafter\let\csname Esmall#1\endcsname \afterenvbreak } % Define two environment synonyms (#1 and #2) for an environment. \def\maketwodispenvdef#1#2#3{% \makedispenvdef{#1}{#3}% \makedispenvdef{#2}{#3}% } % % @lisp: indented, narrowed, typewriter font; % @example: same as @lisp. % % @smallexample and @smalllisp: use smaller fonts. % Originally contributed by Pavel@xerox. % \maketwodispenvdef{lisp}{example}{% \nonfillstart \tt\setupmarkupstyle{example}% \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. \gobble % eat return } % @display/@smalldisplay: same as @lisp except keep current font. % \makedispenvdef{display}{% \nonfillstart \gobble } % @format/@smallformat: same as @display except don't narrow margins. % \makedispenvdef{format}{% \let\nonarrowing = t% \nonfillstart \gobble } % @flushleft: same as @format, but doesn't obey \SETdispenvsize. \envdef\flushleft{% \let\nonarrowing = t% \nonfillstart \gobble } \let\Eflushleft = \afterenvbreak % @flushright. % \envdef\flushright{% \let\nonarrowing = t% \nonfillstart \advance\leftskip by 0pt plus 1fill\relax \gobble } \let\Eflushright = \afterenvbreak % @raggedright does more-or-less normal line breaking but no right % justification. From plain.tex. Don't stretch around special % characters in urls in this environment, since the stretch at the right % should be enough. \envdef\raggedright{% \rightskip0pt plus2.4em \spaceskip.3333em \xspaceskip.5em\relax \def\urefprestretchamount{0pt}% \def\urefpoststretchamount{0pt}% } \let\Eraggedright\par \envdef\raggedleft{% \parindent=0pt \leftskip0pt plus2em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedleft\par \envdef\raggedcenter{% \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedcenter\par % @quotation does normal linebreaking (hence we can't use \nonfillstart) % and narrows the margins. We keep \parskip nonzero in general, since % we're doing normal filling. So, when using \aboveenvbreak and % \afterenvbreak, temporarily make \parskip 0. % \makedispenvdef{quotation}{\quotationstart} % \def\quotationstart{% \indentedblockstart % same as \indentedblock, but increase right margin too. \ifx\nonarrowing\relax \advance\rightskip by \lispnarrowing \fi \parsearg\quotationlabel } % We have retained a nonzero parskip for the environment, since we're % doing normal filling. % \def\Equotation{% \par \ifx\quotationauthor\thisisundefined\else % indent a bit. \leftline{\kern 2\leftskip \sl ---\quotationauthor}% \fi {\parskip=0pt \afterenvbreak}% } \def\Esmallquotation{\Equotation} % If we're given an argument, typeset it in bold with a colon after. \def\quotationlabel#1{% \def\temp{#1}% \ifx\temp\empty \else {\bf #1: }% \fi } % @indentedblock is like @quotation, but indents only on the left and % has no optional argument. % \makedispenvdef{indentedblock}{\indentedblockstart} % \def\indentedblockstart{% {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip \parindent=0pt % % @cartouche defines \nonarrowing to inhibit narrowing at next level down. \ifx\nonarrowing\relax \advance\leftskip by \lispnarrowing \exdentamount = \lispnarrowing \else \let\nonarrowing = \relax \fi } % Keep a nonzero parskip for the environment, since we're doing normal filling. % \def\Eindentedblock{% \par {\parskip=0pt \afterenvbreak}% } \def\Esmallindentedblock{\Eindentedblock} % LaTeX-like @verbatim...@end verbatim and @verb{...} % If we want to allow any as delimiter, % we need the curly braces so that makeinfo sees the @verb command, eg: % `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org % % [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. % % [Knuth] p.344; only we need to do the other characters Texinfo sets % active too. Otherwise, they get lost as the first character on a % verbatim line. \def\dospecials{% \do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% \do\<\do\>\do\|\do\@\do+\do\"% % Don't do the quotes -- if we do, @set txicodequoteundirected and % @set txicodequotebacktick will not have effect on @verb and % @verbatim, and ?` and !` ligatures won't get disabled. %\do\`\do\'% } % % [Knuth] p. 380 \def\uncatcodespecials{% \def\do##1{\catcode`##1=\other}\dospecials} % % Setup for the @verb command. % % Eight spaces for a tab \begingroup \catcode`\^^I=\active \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} \endgroup % \def\setupverb{% \tt % easiest (and conventionally used) font for verbatim \def\par{\leavevmode\endgraf}% \setupmarkupstyle{verb}% \tabeightspaces % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces } % Setup for the @verbatim environment % % Real tab expansion. \newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount % % We typeset each line of the verbatim in an \hbox, so we can handle % tabs. The \global is in case the verbatim line starts with an accent, % or some other command that starts with a begin-group. Otherwise, the % entire \verbbox would disappear at the corresponding end-group, before % it is typeset. Meanwhile, we can't have nested verbatim commands % (can we?), so the \global won't be overwriting itself. \newbox\verbbox \def\starttabbox{\global\setbox\verbbox=\hbox\bgroup} % \begingroup \catcode`\^^I=\active \gdef\tabexpand{% \catcode`\^^I=\active \def^^I{\leavevmode\egroup \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab \divide\dimen\verbbox by\tabw \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw \advance\dimen\verbbox by\tabw % advance to next multiple of \tabw \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox }% } \endgroup % start the verbatim environment. \def\setupverbatim{% \let\nonarrowing = t% \nonfillstart \tt % easiest (and conventionally used) font for verbatim % The \leavevmode here is for blank lines. Otherwise, we would % never \starttabox and the \egroup would end verbatim mode. \def\par{\leavevmode\egroup\box\verbbox\endgraf}% \tabexpand \setupmarkupstyle{verbatim}% % Respect line breaks, % print special symbols as themselves, and % make each space count. % Must do in this order: \obeylines \uncatcodespecials \sepspaces \everypar{\starttabbox}% } % Do the @verb magic: verbatim text is quoted by unique % delimiter characters. Before first delimiter expect a % right brace, after last delimiter expect closing brace: % % \def\doverb'{'#1'}'{#1} % % [Knuth] p. 382; only eat outer {} \begingroup \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] \endgroup % \def\verb{\begingroup\setupverb\doverb} % % % Do the @verbatim magic: define the macro \doverbatim so that % the (first) argument ends when '@end verbatim' is reached, ie: % % \def\doverbatim#1@end verbatim{#1} % % For Texinfo it's a lot easier than for LaTeX, % because texinfo's \verbatim doesn't stop at '\end{verbatim}': % we need not redefine '\', '{' and '}'. % % Inspired by LaTeX's verbatim command set [latex.ltx] % \begingroup \catcode`\ =\active \obeylines % % ignore everything up to the first ^^M, that's the newline at the end % of the @verbatim input line itself. Otherwise we get an extra blank % line in the output. \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% % We really want {...\end verbatim} in the body of the macro, but % without the active space; thus we have to use \xdef and \gobble. \endgroup % \envdef\verbatim{% \setupverbatim\doverbatim } \let\Everbatim = \afterenvbreak % @verbatiminclude FILE - insert text of file in verbatim environment. % \def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} % \def\doverbatiminclude#1{% {% \makevalueexpandable \setupverbatim \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}% \input #1 \afterenvbreak }% } % @copying ... @end copying. % Save the text away for @insertcopying later. % % We save the uninterpreted tokens, rather than creating a box. % Saving the text in a box would be much easier, but then all the % typesetting commands (@smallbook, font changes, etc.) have to be done % beforehand -- and a) we want @copying to be done first in the source % file; b) letting users define the frontmatter in as flexible order as % possible is desirable. % \def\copying{\checkenv{}\begingroup\scanargctxt\docopying} \def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} % \def\insertcopying{% \begingroup \parindent = 0pt % paragraph indentation looks wrong on title page \scanexp\copyingtext \endgroup } \message{defuns,} % @defun etc. \newskip\defbodyindent \defbodyindent=.4in \newskip\defargsindent \defargsindent=50pt \newskip\deflastargmargin \deflastargmargin=18pt \newcount\defunpenalty % Start the processing of @deffn: \def\startdefun{% \ifnum\lastpenalty<10000 \medbreak \defunpenalty=10003 % Will keep this @deffn together with the % following @def command, see below. \else % If there are two @def commands in a row, we'll have a \nobreak, % which is there to keep the function description together with its % header. But if there's nothing but headers, we need to allow a % break somewhere. Check specifically for penalty 10002, inserted % by \printdefunline, instead of 10000, since the sectioning % commands also insert a nobreak penalty, and we don't want to allow % a break between a section heading and a defun. % % As a further refinement, we avoid "club" headers by signalling % with penalty of 10003 after the very first @deffn in the % sequence (see above), and penalty of 10002 after any following % @def command. \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi % % Similarly, after a section heading, do not allow a break. % But do insert the glue. \medskip % preceded by discardable penalty, so not a breakpoint \fi % \parindent=0in \advance\leftskip by \defbodyindent \exdentamount=\defbodyindent } \def\dodefunx#1{% % First, check whether we are in the right environment: \checkenv#1% % % As above, allow line break if we have multiple x headers in a row. % It's not a great place, though. \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi % % And now, it's time to reuse the body of the original defun: \expandafter\gobbledefun#1% } \def\gobbledefun#1\startdefun{} % \printdefunline \deffnheader{text} % \def\printdefunline#1#2{% \begingroup % call \deffnheader: #1#2 \endheader % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil\relax \endgraf \nobreak\vskip -\parskip \penalty\defunpenalty % signal to \startdefun and \dodefunx % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts \endgroup } \def\Edefun{\endgraf\medbreak} % \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; % the only thing remaining is to define \deffnheader. % \def\makedefun#1{% \expandafter\let\csname E#1\endcsname = \Edefun \edef\temp{\noexpand\domakedefun \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% \temp } % \domakedefun \deffn \deffnx \deffnheader { (defn. of \deffnheader) } % % Define \deffn and \deffnx, without parameters. % \deffnheader has to be defined explicitly. % \def\domakedefun#1#2#3{% \envdef#1{% \startdefun \doingtypefnfalse % distinguish typed functions from all else \parseargusing\activeparens{\printdefunline#3}% }% \def#2{\dodefunx#1}% \def#3% } \newif\ifdoingtypefn % doing typed function? \newif\ifrettypeownline % typeset return type on its own line? % @deftypefnnewline on|off says whether the return type of typed functions % are printed on their own line. This affects @deftypefn, @deftypefun, % @deftypeop, and @deftypemethod. % \parseargdef\deftypefnnewline{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxideftypefnnl\endcsname = \empty \else\ifx\temp\offword \expandafter\let\csname SETtxideftypefnnl\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @txideftypefnnl value `\temp', must be on|off}% \fi\fi } % Untyped functions: % @deffn category name args \makedefun{deffn}{\deffngeneral{}} % @deffn category class name args \makedefun{defop}#1 {\defopon{#1\ \putwordon}} % \defopon {category on}class name args \def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deffngeneral {subind}category name args % \def\deffngeneral#1#2 #3 #4\endheader{% % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. \dosubind{fn}{\code{#3}}{#1}% \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% } % Typed functions: % @deftypefn category type name args \makedefun{deftypefn}{\deftypefngeneral{}} % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} % \deftypeopon {category on}class type name args \def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deftypefngeneral {subind}category type name args % \def\deftypefngeneral#1#2 #3 #4 #5\endheader{% \dosubind{fn}{\code{#4}}{#1}% \doingtypefntrue \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } % Typed variables: % @deftypevr category type var args \makedefun{deftypevr}{\deftypecvgeneral{}} % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} % \deftypecvof {category of}class type var args \def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } % \deftypecvgeneral {subind}category type var args % \def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% \dosubind{vr}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } % Untyped variables: % @defvr category var args \makedefun{defvr}#1 {\deftypevrheader{#1} {} } % @defcv category class var args \makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} % \defcvof {category of}class var args \def\defcvof#1#2 {\deftypecvof{#1}#2 {} } % Types: % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% \doind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } % Remaining @defun-like shortcuts: \makedefun{defun}{\deffnheader{\putwordDeffunc} } \makedefun{defmac}{\deffnheader{\putwordDefmac} } \makedefun{defspec}{\deffnheader{\putwordDefspec} } \makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } \makedefun{defvar}{\defvrheader{\putwordDefvar} } \makedefun{defopt}{\defvrheader{\putwordDefopt} } \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } \makedefun{defmethod}{\defopon\putwordMethodon} \makedefun{deftypemethod}{\deftypeopon\putwordMethodon} \makedefun{defivar}{\defcvof\putwordInstanceVariableof} \makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} % \defname, which formats the name of the @def (not the args). % #1 is the category, such as "Function". % #2 is the return type, if any. % #3 is the function name. % % We are followed by (but not passed) the arguments, if any. % \def\defname#1#2#3{% \par % Get the values of \leftskip and \rightskip as they were outside the @def... \advance\leftskip by -\defbodyindent % % Determine if we are typesetting the return type of a typed function % on a line by itself. \rettypeownlinefalse \ifdoingtypefn % doing a typed function specifically? % then check user option for putting return type on its own line: \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else \rettypeownlinetrue \fi \fi % % How we'll format the category name. Putting it in brackets helps % distinguish it from the body text that may end up on the next line % just below it. \def\temp{#1}% \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} % % Figure out line sizes for the paragraph shape. We'll always have at % least two. \tempnum = 2 % % The first line needs space for \box0; but if \rightskip is nonzero, % we need only space for the part of \box0 which exceeds it: \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip % % If doing a return type on its own line, we'll have another line. \ifrettypeownline \advance\tempnum by 1 \def\maybeshapeline{0in \hsize}% \else \def\maybeshapeline{}% \fi % % The continuations: \dimen2=\hsize \advance\dimen2 by -\defargsindent % % The final paragraph shape: \parshape \tempnum 0in \dimen0 \maybeshapeline \defargsindent \dimen2 % % Put the category name at the right margin. \noindent \hbox to 0pt{% \hfil\box0 \kern-\hsize % \hsize has to be shortened this way: \kern\leftskip % Intentionally do not respect \rightskip, since we need the space. }% % % Allow all lines to be underfull without complaint: \tolerance=10000 \hbadness=10000 \exdentamount=\defbodyindent {% % defun fonts. We use typewriter by default (used to be bold) because: % . we're printing identifiers, they should be in tt in principle. % . in languages with many accents, such as Czech or French, it's % common to leave accents off identifiers. The result looks ok in % tt, but exceedingly strange in rm. % . we don't want -- and --- to be treated as ligatures. % . this still does not fix the ?` and !` ligatures, but so far no % one has made identifiers using them :). \df \tt \def\temp{#2}% text of the return type \ifx\temp\empty\else \tclose{\temp}% typeset the return type \ifrettypeownline % put return type on its own line; prohibit line break following: \hfil\vadjust{\nobreak}\break \else \space % type on same line, so just followed by a space \fi \fi % no return type #3% output function name }% {\rm\enskip}% hskip 0.5 em of \tenrm % \boldbrax % arguments will be output next, if any. } % Print arguments in slanted roman (not ttsl), inconsistently with using % tt for the name. This is because literal text is sometimes needed in % the argument list (groff manual), and ttsl and tt are not very % distinguishable. Prevent hyphenation at `-' chars. % \def\defunargs#1{% % use sl by default (not ttsl), % tt for the names. \df \sl \hyphenchar\font=0 % % On the other hand, if an argument has two dashes (for instance), we % want a way to get ttsl. We used to recommend @var for that, so % leave the code in, but it's strange for @var to lead to typewriter. % Nowadays we recommend @code, since the difference between a ttsl hyphen % and a tt hyphen is pretty tiny. @code also disables ?` !`. \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}% #1% \sl\hyphenchar\font=45 } % We want ()&[] to print specially on the defun line. % \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 = ) % 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. { \activeparens \global\let(=\lparen \global\let)=\rparen \global\let[=\lbrack \global\let]=\rbrack \global\let& = \& \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} \gdef\magicamp{\let&=\amprm} } \newcount\parencount % If we encounter &foo, then turn on ()-hacking afterwards \newif\ifampseen \def\amprm#1 {\ampseentrue{\bf\ }} \def\parenfont{% \ifampseen % At the first level, print parens in roman, % otherwise use the default font. \ifnum \parencount=1 \rm \fi \else % The \sf parens (in \boldbrax) actually are a little bolder than % the contained text. This is especially needed for [ and ] . \sf \fi } \def\infirstlevel#1{% \ifampseen \ifnum\parencount=1 #1% \fi \fi } \def\bfafterword#1 {#1 \bf} \def\opnr{% \global\advance\parencount by 1 {\parenfont(}% \infirstlevel \bfafterword } \def\clnr{% {\parenfont)}% \infirstlevel \sl \global\advance\parencount by -1 } \newcount\brackcount \def\lbrb{% \global\advance\brackcount by 1 {\bf[}% } \def\rbrb{% {\bf]}% \global\advance\brackcount by -1 } \def\checkparencounts{% \ifnum\parencount=0 \else \badparencount \fi \ifnum\brackcount=0 \else \badbrackcount \fi } % these should not use \errmessage; the glibc manual, at least, actually % has such constructs (when documenting function pointers). \def\badparencount{% \message{Warning: unbalanced parentheses in @def...}% \global\parencount=0 } \def\badbrackcount{% \message{Warning: unbalanced square brackets in @def...}% \global\brackcount=0 } \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\thisisundefined \newwrite\macscribble \def\scantokens#1{% \toks0={#1}% \immediate\openout\macscribble=\jobname.tmp \immediate\write\macscribble{\the\toks0}% \immediate\closeout\macscribble \input \jobname.tmp } \fi \let\aftermacroxxx\relax \def\aftermacro{\aftermacroxxx} % alias because \c means cedilla in @tex or @math \let\texinfoc=\c % Used at the time of macro expansion. % Argument is macro body with arguments substituted \def\scanmacro#1{% \newlinechar`\^^M \def\xprocessmacroarg{\eatspaces}% % % Process the macro body under the current catcode regime. \scantokens{#1\texinfoc}\aftermacro% % % The \c is to remove the \newlinechar added by \scantokens, and % can be noticed by \parsearg. % The \aftermacro allows a \comment at the end of the macro definition % to duplicate itself past the final \newlinechar added by \scantokens: % this is used in the definition of \group to comment out a newline. We % don't do the same for \c to support Texinfo files with macros that ended % with a @c, which should no longer be necessary. % We avoid surrounding the call to \scantokens with \bgroup and \egroup % to allow macros to open or close groups themselves. } % Used for copying and captions \def\scanexp#1{% \bgroup % Undo catcode changes of \startcontents and \printindex % When called from @insertcopying or (short)caption, we need active % backslash to get it printed correctly. % FIXME: This may not be needed. %\catcode`\@=0 \catcode`\\=\active \escapechar=`\@ \edef\temp{\noexpand\scanmacro{#1}}% \temp \egroup } \newcount\paramno % Count of parameters \newtoks\macname % Macro name \newif\ifrecursive % Is it recursive? % List of all defined macros in the form % \definedummyword\macro1\definedummyword\macro2... % Currently is also contains all @aliases; the list can be split % if there is a need. \def\macrolist{} % Add the macro to \macrolist \def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} \def\addtomacrolistxxx#1{% \toks0 = \expandafter{\macrolist\definedummyword#1}% \xdef\macrolist{\the\toks0}% } % Utility routines. % This does \let #1 = #2, with \csnames; that is, % \let \csname#1\endcsname = \csname#2\endcsname % (except of course we have to play expansion games). % \def\cslet#1#2{% \expandafter\let \csname#1\expandafter\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=\other \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 \ % to recognize macro arguments; this is the job of \mbodybackslash. % % Non-ASCII encodings make 8-bit characters active, so un-activate % them to avoid their expansion. Must do this non-globally, to % confine the change to the current group. % % 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\scanctxt{% used as subroutine \catcode`\"=\other \catcode`\+=\other \catcode`\<=\other \catcode`\>=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\~=\other \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi } \def\scanargctxt{% used for copying and captions, not macros. \scanctxt \catcode`\@=\other \catcode`\\=\other \catcode`\^^M=\other } \def\macrobodyctxt{% used for @macro definitions \scanctxt \catcode`\ =\other \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other \catcode`\^^M=\other \usembodybackslash } % Used when scanning braced macro arguments. Note, however, that catcode % changes here are ineffectual if the macro invocation was nested inside % an argument to another Texinfo command. \def\macroargctxt{% \scanctxt \catcode`\ =\active \catcode`\^^M=\other \catcode`\\=\active } \def\macrolineargctxt{% used for whole-line arguments without braces \scanctxt \catcode`\{=\other \catcode`\}=\other } % \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\margbackslash#1{\char`\#1 } \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\relax \else \expandafter\parsemargdef \argl;% \if\paramno>256\relax \ifx\eTeXversion\thisisundefined \errhelp = \EMsimple \errmessage{You need eTeX to compile a file with macros with more than 256 arguments} \fi \fi \fi \if1\csname ismacro.\the\macname\endcsname \message{Warning: redefining \the\macname}% \else \expandafter\ifx\csname \the\macname\endcsname \relax \else \errmessage{Macro name \the\macname\space already defined}\fi \global\cslet{macsave.\the\macname}{\the\macname}% \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% \addtomacrolist{\the\macname}% \fi \begingroup \macrobodyctxt \ifrecursive \expandafter\parsermacbody \else \expandafter\parsemacbody \fi} \parseargdef\unmacro{% \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 \expandafter\let\csname#1\endcsname \relax \let\definedummyword\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else \errmessage{Macro #1 not defined}% \fi } % Called by \do from \dounmacro on each macro. The idea is to omit any % macro definitions that have been changed to \relax. % \def\unmacrodo#1{% \ifx #1\relax % remove this \else \noexpand\definedummyword \noexpand#1% \fi } % \getargs -- Parse the arguments to a @macro line. Set \macname to % the name of the macro, and \argl to the braced argument list. \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}} % This made use of the 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. % Parse the optional {params} list to @macro or @rmacro. % Set \paramno to the number of arguments, % and \paramlist to a parameter text for the macro (e.g. #1,#2,#3 for a % three-param macro.) Define \macarg.BLAH for each BLAH in the params % list to some hook where the argument is to be expanded. If there are % less than 10 arguments that hook is to be replaced by ##N where N % is the position in that list, that is to say the macro arguments are to be % defined `a la TeX in the macro body. % % That gets used by \mbodybackslash (above). % % If there are 10 or more arguments, a different technique is used: see % \parsemmanyargdef. % \def\parsemargdef#1;{% \paramno=0\def\paramlist{}% \let\hash\relax % \hash is redefined to `#' later to get it into definitions \let\processmacroarg\relax \parsemargdefxxx#1,;,% \ifnum\paramno<10\relax\else \paramno0\relax \parsemmanyargdef@@#1,;,% 10 or more arguments \fi } \def\parsemargdefxxx#1,{% \if#1;\let\next=\relax \else \let\next=\parsemargdefxxx \advance\paramno by 1 \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname {\processmacroarg{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} % \parsemacbody, \parsermacbody % % Read recursive and nonrecursive macro bodies. (They're different since % rec and nonrec macros end differently.) % % We are in \macrobodyctxt, and the \xdef causes backslashshes in the macro % body to be transformed. % Set \macrobody to the body of the macro, and call \defmacro. % {\catcode`\ =\other\long\gdef\parsemacbody#1@end macro{% \xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}% {\catcode`\ =\other\long\gdef\parsermacbody#1@end rmacro{% \xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}% % Make @ a letter, so that we can make private-to-Texinfo macro names. \edef\texiatcatcode{\the\catcode`\@} \catcode `@=11\relax %%%%%%%%%%%%%% Code for > 10 arguments only %%%%%%%%%%%%%%%%%% % If there are 10 or more arguments, a different technique is used, where the % hook remains in the body, and when macro is to be expanded the body is % processed again to replace the arguments. % % In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the % argument N value and then \edef the body (nothing else will expand because of % the catcode regime under which the body was input). % % If you compile with TeX (not eTeX), and you have macros with 10 or more % arguments, no macro can have more than 256 arguments (else error). % % In case that there are 10 or more arguments we parse again the arguments % list to set new definitions for the \macarg.BLAH macros corresponding to % each BLAH argument. It was anyhow needed to parse already once this list % in order to count the arguments, and as macros with at most 9 arguments % are by far more frequent than macro with 10 or more arguments, defining % twice the \macarg.BLAH macros does not cost too much processing power. \def\parsemmanyargdef@@#1,{% \if#1;\let\next=\relax \else \let\next=\parsemmanyargdef@@ \edef\tempb{\eatspaces{#1}}% \expandafter\def\expandafter\tempa \expandafter{\csname macarg.\tempb\endcsname}% % Note that we need some extra \noexpand\noexpand, this is because we % don't want \the to be expanded in the \parsermacbody as it uses an % \xdef . \expandafter\edef\tempa {\noexpand\noexpand\noexpand\the\toks\the\paramno}% \advance\paramno by 1\relax \fi\next} \let\endargs@\relax \let\nil@\relax \def\nilm@{\nil@}% \long\def\nillm@{\nil@}% % This macro is expanded during the Texinfo macro expansion, not during its % definition. It gets all the arguments' values and assigns them to macros % macarg.ARGNAME % % #1 is the macro name % #2 is the list of argument names % #3 is the list of argument values \def\getargvals@#1#2#3{% \def\macargdeflist@{}% \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion. \def\paramlist{#2,\nil@}% \def\macroname{#1}% \begingroup \macroargctxt \def\argvaluelist{#3,\nil@}% \def\@tempa{#3}% \ifx\@tempa\empty \setemptyargvalues@ \else \getargvals@@ \fi } \def\getargvals@@{% \ifx\paramlist\nilm@ % Some sanity check needed here that \argvaluelist is also empty. \ifx\argvaluelist\nillm@ \else \errhelp = \EMsimple \errmessage{Too many arguments in macro `\macroname'!}% \fi \let\next\macargexpandinbody@ \else \ifx\argvaluelist\nillm@ % No more arguments values passed to macro. Set remaining named-arg % macros to empty. \let\next\setemptyargvalues@ \else % pop current arg name into \@tempb \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}% \expandafter\@tempa\expandafter{\paramlist}% % pop current argument value into \@tempc \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}% \expandafter\@tempa\expandafter{\argvaluelist}% % Here \@tempb is the current arg name and \@tempc is the current arg value. % First place the new argument macro definition into \@tempd \expandafter\macname\expandafter{\@tempc}% \expandafter\let\csname macarg.\@tempb\endcsname\relax \expandafter\def\expandafter\@tempe\expandafter{% \csname macarg.\@tempb\endcsname}% \edef\@tempd{\long\def\@tempe{\the\macname}}% \push@\@tempd\macargdeflist@ \let\next\getargvals@@ \fi \fi \next } \def\push@#1#2{% \expandafter\expandafter\expandafter\def \expandafter\expandafter\expandafter#2% \expandafter\expandafter\expandafter{% \expandafter#1#2}% } % Replace arguments by their values in the macro body, and place the result % in macro \@tempa. % \def\macvalstoargs@{% % To do this we use the property that token registers that are \the'ed % within an \edef expand only once. So we are going to place all argument % values into respective token registers. % % First we save the token context, and initialize argument numbering. \begingroup \paramno0\relax % Then, for each argument number #N, we place the corresponding argument % value into a new token list register \toks#N \expandafter\putargsintokens@\saveparamlist@,;,% % Then, we expand the body so that argument are replaced by their % values. The trick for values not to be expanded themselves is that they % are within tokens and that tokens expand only once in an \edef . \edef\@tempc{\csname mac.\macroname .body\endcsname}% % Now we restore the token stack pointer to free the token list registers % which we have used, but we make sure that expanded body is saved after % group. \expandafter \endgroup \expandafter\def\expandafter\@tempa\expandafter{\@tempc}% } % Define the named-macro outside of this group and then close this group. % \def\macargexpandinbody@{% \expandafter \endgroup \macargdeflist@ % First the replace in body the macro arguments by their values, the result % is in \@tempa . \macvalstoargs@ % Then we point at the \norecurse or \gobble (for recursive) macro value % with \@tempb . \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname % Depending on whether it is recursive or not, we need some tailing % \egroup . \ifx\@tempb\gobble \let\@tempc\relax \else \let\@tempc\egroup \fi % And now we do the real job: \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}% \@tempd } \def\putargsintokens@#1,{% \if#1;\let\next\relax \else \let\next\putargsintokens@ % First we allocate the new token list register, and give it a temporary % alias \@tempb . \toksdef\@tempb\the\paramno % Then we place the argument value into that token list register. \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname \expandafter\@tempb\expandafter{\@tempa}% \advance\paramno by 1\relax \fi \next } % Trailing missing arguments are set to empty. % \def\setemptyargvalues@{% \ifx\paramlist\nilm@ \let\next\macargexpandinbody@ \else \expandafter\setemptyargvaluesparser@\paramlist\endargs@ \let\next\setemptyargvalues@ \fi \next } \def\setemptyargvaluesparser@#1,#2\endargs@{% \expandafter\def\expandafter\@tempa\expandafter{% \expandafter\def\csname macarg.#1\endcsname{}}% \push@\@tempa\macargdeflist@ \def\paramlist{#2}% } % #1 is the element target macro % #2 is the list macro % #3,#4\endargs@ is the list value \def\pop@#1#2#3,#4\endargs@{% \def#1{#3}% \def#2{#4}% } \long\def\longpop@#1#2#3,#4\endargs@{% \long\def#1{#3}% \long\def#2{#4}% } %%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%% % Remove following spaces at the expansion stage. % This works because spaces are discarded before each argument when TeX is % getting the arguments for a macro. % This must not be immediately followed by a }. \long\def\gobblespaces#1{#1} % This defines a Texinfo @macro or @rmacro, called by \parsemacbody. % \macrobody has the body of the macro in it, with placeholders for % its parameters, looking like "\processmacroarg{\hash 1}". % \paramno is the number of parameters % \paramlist is a TeX parameter text, e.g. "#1,#2,#3," % There are eight cases: recursive and nonrecursive macros of zero, one, % up to nine, and many arguments. % \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 \ifnum\paramno=1 \def\processmacroarg{\gobblespaces}% % This removes the pair of braces around the argument. We don't % use \eatspaces, because this can cause ends of lines to be lost % when the argument to \eatspaces is read, leading to line-based % commands like "@itemize" not being read correctly. \else \def\processmacroarg{\xprocessmacroarg}% \let\xprocessmacroarg\relax \fi \ifrecursive %%%%%%%%%%%%%% Recursive %%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\macrobody}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup \noexpand\braceorline \expandafter\noexpand\csname\the\macname @@@\endcsname}% \expandafter\xdef\csname\the\macname @@@\endcsname##1{% \expandafter\noexpand\csname\the\macname @@@@\endcsname{% \noexpand\gobblespaces##1\empty}% % The \empty is for \gobblespaces in case #1 is empty }% \expandafter\xdef\csname\the\macname @@@@\endcsname##1{% \egroup\noexpand\scanmacro{\macrobody}}% \else \ifnum\paramno<10\relax % at most 9 % See non-recursive section below for comments \expandafter\xdef\csname\the\macname\endcsname{% \bgroup \noexpand\expandafter \noexpand\macroargctxt \noexpand\expandafter \expandafter\noexpand\csname\the\macname @@\endcsname}% \expandafter\xdef\csname\the\macname @@\endcsname##1{% \noexpand\passargtomacro \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}% \expandafter\xdef\csname\the\macname @@@\endcsname##1{% \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname @@@@\endcsname\paramlist{% \egroup\noexpand\scanmacro{\macrobody}}% \else % 10 or more \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble \fi \fi \else %%%%%%%%%%%%%%%%%%%%%% Non-recursive %%%%%%%%%%%%%%%%%%%%%%%%%% \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\macrobody}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup \noexpand\braceorline \expandafter\noexpand\csname\the\macname @@@\endcsname}% \expandafter\xdef\csname\the\macname @@@\endcsname##1{% \expandafter\noexpand\csname\the\macname @@@@\endcsname{% \noexpand\gobblespaces##1\empty}% % The \empty is for \gobblespaces in case #1 is empty }% \expandafter\xdef\csname\the\macname @@@@\endcsname##1{% \egroup \noexpand\scanmacro{\macrobody}% }% \else % at most 9 \ifnum\paramno<10\relax % @MACNAME sets the context for reading the macro argument % @MACNAME@@ gets the argument, processes backslashes and appends a % comma. % @MACNAME@@@ removes braces surrounding the argument list. % @MACNAME@@@@ scans the macro body with arguments substituted. \expandafter\xdef\csname\the\macname\endcsname{% \bgroup \noexpand\expandafter % This \expandafter skip any spaces after the \noexpand\macroargctxt % macro before we change the catcode of space. \noexpand\expandafter \expandafter\noexpand\csname\the\macname @@\endcsname}% \expandafter\xdef\csname\the\macname @@\endcsname##1{% \noexpand\passargtomacro \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}% \expandafter\xdef\csname\the\macname @@@\endcsname##1{% \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname @@@@\endcsname\paramlist{% \egroup\noexpand\scanmacro{\macrobody}}% \else % 10 or more: \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse \fi \fi \fi} \catcode `\@\texiatcatcode\relax % end private-to-Texinfo catcodes \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % {\catcode`\@=0 \catcode`\\=13 % We need to manipulate \ so use @ as escape @catcode`@_=11 % private names @catcode`@!=11 % used as argument separator % \passargtomacro#1#2 - % Call #1 with a list of tokens #2, with any doubled backslashes in #2 % compressed to one. % % This implementation works by expansion, and not execution (so we cannot use % \def or similar). This reduces the risk of this failing in contexts where % complete expansion is done with no execution (for example, in writing out to % an auxiliary file for an index entry). % % State is kept in the input stream: the argument passed to % @look_ahead, @gobble_and_check_finish and @add_segment is % % THE_MACRO ARG_RESULT ! {PENDING_BS} NEXT_TOKEN (... rest of input) % % where: % THE_MACRO - name of the macro we want to call % ARG_RESULT - argument list we build to pass to that macro % PENDING_BS - either a backslash or nothing % NEXT_TOKEN - used to look ahead in the input stream to see what's coming next @gdef@passargtomacro#1#2{% @add_segment #1!{}@relax#2\@_finish\% } @gdef@_finish{@_finishx} @global@let@_finishx@relax % #1 - THE_MACRO ARG_RESULT % #2 - PENDING_BS % #3 - NEXT_TOKEN % #4 used to look ahead % % If the next token is not a backslash, process the rest of the argument; % otherwise, remove the next token. @gdef@look_ahead#1!#2#3#4{% @ifx#4\% @expandafter@gobble_and_check_finish @else @expandafter@add_segment @fi#1!{#2}#4#4% } % #1 - THE_MACRO ARG_RESULT % #2 - PENDING_BS % #3 - NEXT_TOKEN % #4 should be a backslash, which is gobbled. % #5 looks ahead % % Double backslash found. Add a single backslash, and look ahead. @gdef@gobble_and_check_finish#1!#2#3#4#5{% @add_segment#1\!{}#5#5% } @gdef@is_fi{@fi} % #1 - THE_MACRO ARG_RESULT % #2 - PENDING_BS % #3 - NEXT_TOKEN % #4 is input stream until next backslash % % Input stream is either at the start of the argument, or just after a % backslash sequence, either a lone backslash, or a doubled backslash. % NEXT_TOKEN contains the first token in the input stream: if it is \finish, % finish; otherwise, append to ARG_RESULT the segment of the argument up until % the next backslash. PENDING_BACKSLASH contains a backslash to represent % a backslash just before the start of the input stream that has not been % added to ARG_RESULT. @gdef@add_segment#1!#2#3#4\{% @ifx#3@_finish @call_the_macro#1!% @else % append the pending backslash to the result, followed by the next segment @expandafter@is_fi@look_ahead#1#2#4!{\}@fi % this @fi is discarded by @look_ahead. % we can't get rid of it with \expandafter because we don't know how % long #4 is. } % #1 - THE_MACRO % #2 - ARG_RESULT % #3 discards the res of the conditional in @add_segment, and @is_fi ends the % conditional. @gdef@call_the_macro#1#2!#3@fi{@is_fi #1{#2}} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \braceorline MAC is used for a one-argument macro MAC. It checks % whether the next non-whitespace character is a {. It sets the context % for reading the argument (slightly different in the two cases). Then, % to read the argument, in the whole-line case, it then calls the regular % \parsearg MAC; in the lbrace case, it calls \passargtomacro MAC. % \def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup \macroargctxt \expandafter\passargtomacro \else \macrolineargctxt\expandafter\parsearg \fi \macnamexxx} % @alias. % We need some trickery to remove the optional spaces around the equal % sign. Make them active and then expand them all to nothing. % \def\alias{\parseargusing\obeyspaces\aliasxxx} \def\aliasxxx #1{\aliasyyy#1\relax} \def\aliasyyy #1=#2\relax{% {% \expandafter\let\obeyedspace=\empty \addtomacrolist{#1}% \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% }% \next } \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 only job in TeX is to define \lastnode, which is used in % cross-references. The @node line might or might not have commas, and % might or might not have spaces before the first comma, like: % @node foo , bar , ... % We don't want such trailing spaces in the node name. % \parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} % % also remove a trailing comma, in case of something like this: % @node Help-Cross, , , Cross-refs \def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} \def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} \let\nwnode=\node \let\lastnode=\empty % Write a cross-reference definition for the current node. #1 is the % type (Ynumbered, Yappendix, Ynothing). % \def\donoderef#1{% \ifx\lastnode\empty\else \setref{\lastnode}{#1}% \global\let\lastnode=\empty \fi } % @anchor{NAME} -- define xref target at arbitrary point. % \newcount\savesfregister % \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} \def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} % \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an % anchor), which consists of three parts: % 1) NAME-title - the current sectioning name taken from \lastsection, % or the anchor name. % 2) NAME-snt - section number and type, passed as the SNT arg, or % empty for anchors. % 3) NAME-pg - the page number. % % This is called from \donoderef, \anchor, and \dofloat. In the case of % floats, there is an additional part, which is not written here: % 4) NAME-lof - the text as it should appear in a @listoffloats. % \def\setref#1#2{% \pdfmkdest{#1}% \iflinks {% \requireauxfile \atdummies % preserve commands, but don't expand them \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef }% \toks0 = \expandafter{\lastsection}% \immediate \writexrdef{title}{\the\toks0 }% \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout }% \fi } % @xrefautosectiontitle on|off says whether @section(ing) names are used % automatically in xrefs, if the third arg is not explicitly specified. % This was provided as a "secret" @set xref-automatic-section-title % variable, now it's official. % \parseargdef\xrefautomaticsectiontitle{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETxref-automatic-section-title\endcsname = \empty \else\ifx\temp\offword \expandafter\let\csname SETxref-automatic-section-title\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @xrefautomaticsectiontitle value `\temp', must be on|off}% \fi\fi } % % @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{\putwordsee{} \xrefXX} \def\xref{\putwordSee{} \xrefXX} \def\ref{\xrefXX} \def\xrefXX#1{\def\xrefXXarg{#1}\futurelet\tokenafterxref\xrefXXX} \def\xrefXXX{\expandafter\xrefX\expandafter[\xrefXXarg,,,,,,,]} % \newbox\toprefbox \newbox\printedrefnamebox \newbox\infofilenamebox \newbox\printedmanualbox % \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup \unsepspaces % % Get args without leading/trailing spaces. \def\printedrefname{\ignorespaces #3}% \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}% % \def\infofilename{\ignorespaces #4}% \setbox\infofilenamebox = \hbox{\infofilename\unskip}% % \def\printedmanual{\ignorespaces #5}% \setbox\printedmanualbox = \hbox{\printedmanual\unskip}% % % If the printed reference name (arg #3) was not explicitly given in % the @xref, figure out what we want to use. \ifdim \wd\printedrefnamebox = 0pt % No printed node name was explicitly given. \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax % Not auto section-title: use node name inside the square brackets. \def\printedrefname{\ignorespaces #1}% \else % Auto section-title: use chapter/section title inside % the square brackets if we have it. \ifdim \wd\printedmanualbox > 0pt % It is in another manual, so we don't have it; use node name. \def\printedrefname{\ignorespaces #1}% \else \ifhavexrefs % We (should) know the real title if we have the xref values. \def\printedrefname{\refx{#1-title}{}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% \fi% \fi \fi \fi % % Make link in pdf output. \ifpdf {\indexnofonts \turnoffactive \makevalueexpandable % This expands tokens, so do it after making catcode changes, so _ % etc. don't get their TeX definitions. This ignores all spaces in % #4, including (wrongly) those in the middle of the filename. \getfilename{#4}% % % This (wrongly) does not take account of leading or trailing % spaces in #1, which should be ignored. \edef\pdfxrefdest{#1}% \ifx\pdfxrefdest\empty \def\pdfxrefdest{Top}% no empty targets \else \txiescapepdf\pdfxrefdest % escape PDF special chars \fi % \leavevmode \startlink attr{/Border [0 0 0]}% \ifnum\filenamelength>0 goto file{\the\filename.pdf} name{\pdfxrefdest}% \else goto name{\pdfmkpgn{\pdfxrefdest}}% \fi }% \setcolor{\linkcolor}% \fi {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". \iffloat distinguishes them by % \Xthisreftitle being set to a magic string. \iffloat\Xthisreftitle % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd\printedrefnamebox = 0pt \refx{#1-snt}{}% \else \printedrefname \fi % % If the user also gave the printed manual name (fifth arg), append % "in MANUALNAME". \ifdim \wd\printedmanualbox > 0pt \space \putwordin{} \cite{\printedmanual}% \fi \else % node/anchor (non-float) references. % % If we use \unhbox 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 \wd\printedmanualbox > 0pt % Cross-manual reference with a printed manual name. % \crossmanualxref{\cite{\printedmanual\unskip}}% % \else\ifdim \wd\infofilenamebox > 0pt % Cross-manual reference with only an info filename (arg 4), no % printed manual name (arg 5). This is essentially the same as % the case above; we output the filename, since we have nothing else. % \crossmanualxref{\code{\infofilename\unskip}}% % \else % Reference within this manual. % % _ (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. {\turnoffactive % 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 }% % output the `[mynode]' via the macro below so it can be overridden. \xrefprintnodename\printedrefname % % But we always want a comma and a space: ,\space % % output the `page 3'. \turnoffactive \putwordpage\tie\refx{#1-pg}{}% % Add a , if xref followed by a space \if\space\noexpand\tokenafterxref ,% \else\ifx\ \tokenafterxref ,% @TAB \else\ifx\*\tokenafterxref ,% @* \else\ifx\ \tokenafterxref ,% @SPACE \else\ifx\ \tokenafterxref ,% @NL \else\ifx\tie\tokenafterxref ,% @tie \fi\fi\fi\fi\fi\fi \fi\fi \fi \endlink \endgroup} % Output a cross-manual xref to #1. Used just above (twice). % % Only include the text "Section ``foo'' in" if the foo is neither % missing or Top. Thus, @xref{,,,foo,The Foo Manual} outputs simply % "see The Foo Manual", the idea being to refer to the whole manual. % % But, this being TeX, we can't easily compare our node name against the % string "Top" while ignoring the possible spaces before and after in % the input. By adding the arbitrary 7sp below, we make it much less % likely that a real node name would have the same width as "Top" (e.g., % in a monospaced font). Hopefully it will never happen in practice. % % For the same basic reason, we retypeset the "Top" at every % reference, since the current font is indeterminate. % \def\crossmanualxref#1{% \setbox\toprefbox = \hbox{Top\kern7sp}% \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}% \ifdim \wd2 > 7sp % nonempty? \ifdim \wd2 = \wd\toprefbox \else % same as Top? \putwordSection{} ``\printedrefname'' \putwordin{}\space \fi \fi #1% } % This macro is called from \xrefX for the `[nodename]' part of xref % output. It's a separate macro only so it can be changed more easily, % since square brackets don't work well in some documents. Particularly % one that Bob is working on :). % \def\xrefprintnodename#1{[#1]} % Things referred to by \setref. % \def\Ynothing{} \def\Yomitfromtoc{} \def\Ynumbered{% \ifnum\secno=0 \putwordChapter@tie \the\chapno \else \ifnum\subsecno=0 \putwordSection@tie \the\chapno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie \the\chapno.\the\secno.\the\subsecno \else \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } \def\Yappendix{% \ifnum\secno=0 \putwordAppendix@tie @char\the\appendixno{}% \else \ifnum\subsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno \else \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\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{% \requireauxfile {% \indexnofonts \otherbackslash \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% \ifx\thisrefX\relax % If not defined, say something at least. \angleleft un\-de\-fined\angleright \iflinks \ifhavexrefs {\toks0 = {#1}% avoid expansion of possibly-complex value \message{\linenumber Undefined cross reference `\the\toks0'.}}% \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. \thisrefX \fi #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Usually it's % just a \def (we prepend XR to the control sequence name to avoid % collisions). But if this is a float type, we have more work to do. % \def\xrdef#1#2{% {% The node name might contain 8-bit characters, which in our current % implementation are changed to commands like @'e. Don't let these % mess up the control sequence name. \indexnofonts \turnoffactive \xdef\safexrefname{#1}% }% % \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR\safexrefname\endcsname % it was a float, and we have the (safe) float type in \iffloattype. \expandafter\let\expandafter\floatlist \csname floatlist\iffloattype\endcsname % % Is this the first time we've seen this float type? \expandafter\ifx\floatlist\relax \toks0 = {\do}% yes, so just \do \else % had it before, so preserve previous elements in list. \toks0 = \expandafter{\floatlist\do}% \fi % % Remember this xref in the control sequence \floatlistFLOATTYPE, % for later use in \listoffloats. \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 {\safexrefname}}% \fi } % 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 at the beginning of the file. % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % Used when writing to the aux file, or when using data from it. \def\requireauxfile{% \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi \global\let\requireauxfile=\relax % Only do this once. } % Read the last existing aux file, if any. No error if none exists. % \def\tryauxfile{% \openin 1 \jobname.aux \ifeof 1 \else \readdatafile{aux}% \global\havexrefstrue \fi \closein 1 } \def\setupdatafile{% \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 % It was suggested to set the catcode of ^ to 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 % % Special characters. Should be turned off anyway, but... \catcode`\~=\other \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 % % This is to support \ in node names and titles, since the \ % characters end up in a \csname. It's easier than % leaving it active and making its active definition an actual \ % character. What I don't understand is why it works in the *value* % of the xrdef. Seems like it should be a catcode12 \, and that % should not typeset properly. But it works, so I'm moving on for % now. --karl, 15jan04. \catcode`\\=\other % % Make the characters 128-255 be printing characters. {\setnonasciicharscatcodenonglobal\other}% % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 \catcode`\@=0 } \def\readdatafile#1{% \begingroup \setupdatafile \input\jobname.#1 \endgroup} \message{insertions,} % including 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 {\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}\ptexslash\fi % % Remove inadvertent blank space before typesetting the footnote number. \unskip \thisfootno\@sf \dofootnote }% % 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) fails inside footnotes because the tokens are fixed when % the footnote is read. --karl, 16nov96. % \gdef\dofootnote{% \insert\footins\bgroup % % Nested footnotes are not supported in TeX, that would take a lot % more work. (\startsavinginserts does not suffice.) \let\footnote=\errfootnotenest % % 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. \hsize=\pagewidth \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 % \smallfonts \rm % % Because we use hanging indentation in footnotes, a @noindent appears % to exdent this text, so make it be a no-op. makeinfo does not use % hanging indentation so @noindent can still be needed within footnote % text after an @example or the like (not that this is good style). \let\noindent = \relax % % Hang the footnote text off the number. Use \everypar in case the % footnote extends for more than one paragraph. \everypar = {\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 % % Invoke rest of plain TeX footnote routine. \futurelet\next\fo@t } }%end \catcode `\@=11 \def\errfootnotenest{% \errhelp=\EMsimple \errmessage{Nested footnotes not supported in texinfo.tex, even though they work in makeinfo; sorry} } \def\errfootnoteheading{% \errhelp=\EMsimple \errmessage{Footnotes in chapters, sections, etc., are not supported} } % In case a @footnote appears in a vbox, save the footnote text and create % the real \insert just after the vbox finished. Otherwise, the insertion % would be lost. % Similarly, if a @footnote appears inside an alignment, save the footnote % text to a box and make the \insert when a row of the table is finished. % And the same can be done for other insert classes. --kasal, 16nov03. % % Replace the \insert primitive by a cheating macro. % Deeper inside, just make sure that the saved insertions are not spilled % out prematurely. % \def\startsavinginserts{% \ifx \insert\ptexinsert \let\insert\saveinsert \else \let\checkinserts\relax \fi } % This \insert replacement works for both \insert\footins{foo} and % \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. % \def\saveinsert#1{% \edef\next{\noexpand\savetobox \makeSAVEname#1}% \afterassignment\next % swallow the left brace \let\temp = } \def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} \def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} \def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} \def\placesaveins#1{% \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname {\box#1}% } % eat @SAVE -- beware, all of them have catcode \other: { \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) \gdef\gobblesave @SAVE{} } % initialization: \def\newsaveins #1{% \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% \next } \def\newsaveinsX #1{% \csname newbox\endcsname #1% \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts \checksaveins #1}% } % initialize: \let\checkinserts\empty \newsaveins\footins \newsaveins\margin % @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 % Do not bother showing banner with epsf.tex v2.7k (available in % doc/epsf.tex and on ctan). \def\epsfannounce{\toks0 = }% \input epsf.tex \fi \closein 1 % % We will only complain once about lack of epsf.tex. \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.} % \def\image#1{% \ifx\epsfbox\thisisundefined \ifwarnednoepsf \else \errhelp = \noepsfhelp \errmessage{epsf.tex not found, images will be ignored}% \global\warnednoepsftrue \fi \else \imagexxx #1,,,,,\finish \fi } % % Arguments to @image: % #1 is (mandatory) image filename; we tack on .eps extension. % #2 is (optional) width, #3 is (optional) height. % #4 is (ignored optional) html alt text. % #5 is (ignored optional) extension. % #6 is just the usual extra ignored arg for parsing stuff. \newif\ifimagevmode \def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup \catcode`\^^M = 5 % in case we're inside an example \normalturnoffactive % allow _ et al. in names \def\xprocessmacroarg{\eatspaces}% in case we are being used via a macro % If the image is by itself, center it. \ifvmode \imagevmodetrue \else \ifx\centersub\centerV % for @center @image, we need a vbox so we can have our vertical space \imagevmodetrue \vbox\bgroup % vbox has better behavior than vtop herev \fi\fi % \ifimagevmode \nobreak\medskip % Usually we'll have text after the image which will insert % \parskip glue, so insert it here too to equalize the space % above and below. \nobreak\vskip\parskip \nobreak \fi % % Leave vertical mode so that indentation from an enclosing % environment such as @quotation is respected. % However, if we're at the top level, we don't want the % normal paragraph indentation. % On the other hand, if we are in the case of @center @image, we don't % want to start a paragraph, which will create a hsize-width box and % eradicate the centering. \ifx\centersub\centerV\else \noindent \fi % % Output the image. \ifpdf % For pdfTeX and LuaTeX <= 0.80 \dopdfimage{#1}{#2}{#3}% \else \ifx\XeTeXrevision\thisisundefined % For epsf.tex % \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 \epsfbox{#1.eps}% \else % For XeTeX \doxeteximage{#1}{#2}{#3}% \fi \fi % \ifimagevmode \medskip % space after a standalone image \fi \ifx\centersub\centerV \egroup \fi \endgroup} % @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, % etc. We don't actually implement floating yet, we always include the % float "here". But it seemed the best name for the future. % \envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} % There may be a space before second and/or third parameter; delete it. \def\eatcommaspace#1, {#1,} % #1 is the optional FLOATTYPE, the text label for this float, typically % "Figure", "Table", "Example", etc. Can't contain commas. If omitted, % this float will not be numbered and cannot be referred to. % % #2 is the optional xref label. Also must be present for the float to % be referable. % % #3 is the optional positioning argument; for now, it is ignored. It % will somehow specify the positions allowed to float to (here, top, bottom). % % We keep a separate counter for each FLOATTYPE, which we reset at each % chapter-level command. \let\resetallfloatnos=\empty % \def\dofloat#1,#2,#3,#4\finish{% \let\thiscaption=\empty \let\thisshortcaption=\empty % % don't lose footnotes inside @float. % % BEWARE: when the floats start float, we have to issue warning whenever an % insert appears inside a float which could possibly float. --kasal, 26may04 % \startsavinginserts % % We can't be used inside a paragraph. \par % \vtop\bgroup \def\floattype{#1}% \def\floatlabel{#2}% \def\floatloc{#3}% we do nothing with this yet. % \ifx\floattype\empty \let\safefloattype=\empty \else {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% \fi % % If label is given but no type, we handle that as the empty type. \ifx\floatlabel\empty \else % We want each FLOATTYPE to be numbered separately (Figure 1, % Table 1, Figure 2, ...). (And if no label, no number.) % \expandafter\getfloatno\csname\safefloattype floatno\endcsname \global\advance\floatno by 1 % {% % This magic value for \lastsection is output by \setref as the % XREFLABEL-title value. \xrefX uses it to distinguish float % labels (which have a completely different output format) from % node and anchor labels. And \xrdef uses it to construct the % lists of floats. % \edef\lastsection{\floatmagic=\safefloattype}% \setref{\floatlabel}{Yfloat}% }% \fi % % start with \parskip glue, I guess. \vskip\parskip % % Don't suppress indentation if a float happens to start a section. \restorefirstparagraphindent } % we have these possibilities: % @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap % @float Foo,lbl & no caption: Foo 1.1 % @float Foo & @caption{Cap}: Foo: Cap % @float Foo & no caption: Foo % @float ,lbl & Caption{Cap}: 1.1: Cap % @float ,lbl & no caption: 1.1 % @float & @caption{Cap}: Cap % @float & no caption: % \def\Efloat{% \let\floatident = \empty % % In all cases, if we have a float type, it comes first. \ifx\floattype\empty \else \def\floatident{\floattype}\fi % % If we have an xref label, the number comes next. \ifx\floatlabel\empty \else \ifx\floattype\empty \else % if also had float type, need tie first. \appendtomacro\floatident{\tie}% \fi % the number. \appendtomacro\floatident{\chaplevelprefix\the\floatno}% \fi % % Start the printed caption with what we've constructed in % \floatident, but keep it separate; we need \floatident again. \let\captionline = \floatident % \ifx\thiscaption\empty \else \ifx\floatident\empty \else \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. \appendtomacro\captionline{\scanexp\thiscaption}% \fi % % If we have anything to print, print it, with space before. % Eventually this needs to become an \insert. \ifx\captionline\empty \else \vskip.5\parskip \captionline % % Space below caption. \vskip\parskip \fi % % If have an xref label, write the list of floats info. Do this % after the caption, to avoid chance of it being a breakpoint. \ifx\floatlabel\empty \else % Write the text that goes in the lof to the aux file as % \floatlabel-lof. Besides \floatident, we include the short % caption if specified, else the full caption if specified, else nothing. {% \requireauxfile \atdummies % % since we read the caption text in the macro world, where ^^M % is turned into a normal character, we have to scan it back, so % we don't write the literal three characters "^^M" into the aux file. \scanexp{% \xdef\noexpand\gtemp{% \ifx\thisshortcaption\empty \thiscaption \else \thisshortcaption \fi }% }% \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident \ifx\gtemp\empty \else : \gtemp \fi}}% }% \fi \egroup % end of \vtop % % place the captured inserts % % BEWARE: when the floats start floating, we have to issue warning % whenever an insert appears inside a float which could possibly % float. --kasal, 26may04 % \checkinserts } % Append the tokens #2 to the definition of macro #1, not expanding either. % \def\appendtomacro#1#2{% \expandafter\def\expandafter#1\expandafter{#1#2}% } % @caption, @shortcaption % \def\caption{\docaption\thiscaption} \def\shortcaption{\docaption\thisshortcaption} \def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} \def\defcaption#1#2{\egroup \def#1{#2}} % The parameter is the control sequence identifying the counter we are % going to use. Create it if it doesn't exist and assign it to \floatno. \def\getfloatno#1{% \ifx#1\relax % Haven't seen this figure type before. \csname newcount\endcsname #1% % % Remember to reset this floatno at the next chap. \expandafter\gdef\expandafter\resetallfloatnos \expandafter{\resetallfloatnos #1=0 }% \fi \let\floatno#1% } % \setref calls this to get the XREFLABEL-snt value. We want an @xref % to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we % first read the @float command. % \def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% % Magic string used for the XREFLABEL-title value, so \xrefX can % distinguish floats from other xref types. \def\floatmagic{!!float!!} % #1 is the control sequence we are passed; we expand into a conditional % which is true if #1 represents a float ref. That is, the magic % \lastsection value which we \setref above. % \def\iffloat#1{\expandafter\doiffloat#1==\finish} % % #1 is (maybe) the \floatmagic string. If so, #2 will be the % (safe) float type for this float. We set \iffloattype to #2. % \def\doiffloat#1=#2=#3\finish{% \def\temp{#1}% \def\iffloattype{#2}% \ifx\temp\floatmagic } % @listoffloats FLOATTYPE - print a list of floats like a table of contents. % \parseargdef\listoffloats{% \def\floattype{#1}% floattype {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% % % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax \ifhavexrefs % if the user said @listoffloats foo but never @float foo. \message{\linenumber No `\safefloattype' floats to list.}% \fi \else \begingroup \leftskip=\tocindent % indent these entries like a toc \let\do=\listoffloatsdo \csname floatlist\safefloattype\endcsname \endgroup \fi } % This is called on each entry in a list of floats. We're passed the % xref label, in the form LABEL-title, which is how we save it in the % aux file. We strip off the -title and look up \XRLABEL-lof, which % has the text we're supposed to typeset here. % % Figures without xref labels will not be included in the list (since % they won't appear in the aux file). % \def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} \def\listoffloatsdoentry#1-title\finish{{% % Can't fully expand XR#1-lof because it can contain anything. Just % pass the control sequence. On the other hand, XR#1-pg is just the % page number, and we want to fully expand that so we can get a link % in pdf output. \toksA = \expandafter{\csname XR#1-lof\endcsname}% % % use the same \entry macro we use to generate the TOC and index. \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% \writeentry }} \message{localization,} % For single-language documents, @documentlanguage is usually given very % early, just after @documentencoding. Single argument is the language % (de) or locale (de_DE) abbreviation. % { \catcode`\_ = \active \globaldefs=1 \parseargdef\documentlanguage{% \tex % read txi-??.tex file in plain TeX. % Read the file by the name they passed if it exists. \let_ = \normalunderscore % normal _ character for filename test \openin 1 txi-#1.tex \ifeof 1 \documentlanguagetrywithoutunderscore #1_\finish \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 \endgroup % end raw TeX } % % If they passed de_DE, and txi-de_DE.tex doesn't exist, % try txi-de.tex. % \gdef\documentlanguagetrywithoutunderscore#1_#2\finish{% \openin 1 txi-#1.tex \ifeof 1 \errhelp = \nolanghelp \errmessage{Cannot read language file txi-#1.tex}% \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 } }% end of special _ catcode % \newhelp\nolanghelp{The given language definition file cannot be found or is empty. Maybe you need to install it? Putting it in the current directory should work if nowhere else does.} % This macro is called from txi-??.tex files; the first argument is the % \language name to set (without the "\lang@" prefix), the second and % third args are \{left,right}hyphenmin. % % The language names to pass are determined when the format is built. % See the etex.log file created at that time, e.g., % /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log. % % With TeX Live 2008, etex now includes hyphenation patterns for all % available languages. This means we can support hyphenation in % Texinfo, at least to some extent. (This still doesn't solve the % accented characters problem.) % \catcode`@=11 \def\txisetlanguage#1#2#3{% % do not set the language if the name is undefined in the current TeX. \expandafter\ifx\csname lang@#1\endcsname \relax \message{no patterns for #1}% \else \global\language = \csname lang@#1\endcsname \fi % but there is no harm in adjusting the hyphenmin values regardless. \global\lefthyphenmin = #2\relax \global\righthyphenmin = #3\relax } % Get input by bytes instead of by UTF-8 codepoints for XeTeX and LuaTeX, % otherwise the encoding support is completely broken. \ifx\XeTeXrevision\thisisundefined \else \XeTeXdefaultencoding "bytes" % For subsequent files to be read \XeTeXinputencoding "bytes" % Effective in texinfo.tex only % Unfortunately, there seems to be no corresponding XeTeX command for % output encoding. This is a problem for auxiliary index and TOC files. % The only solution would be perhaps to write out @U{...} sequences in % place of UTF-8 characters. \fi \ifx\luatexversion\thisisundefined \else \directlua{ local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub local function convert_char (char) return utf8_char(byte(char)) end local function convert_line (line) return gsub(line, ".", convert_char) end callback.register("process_input_buffer", convert_line) local function convert_line_out (line) local line_out = "" for c in string.utfvalues(line) do line_out = line_out .. string.char(c) end return line_out end callback.register("process_output_buffer", convert_line_out) } \fi % Helpers for encodings. % Set the catcode of characters 128 through 255 to the specified number. % \def\setnonasciicharscatcode#1{% \count255=128 \loop\ifnum\count255<256 \global\catcode\count255=#1\relax \advance\count255 by 1 \repeat } \def\setnonasciicharscatcodenonglobal#1{% \count255=128 \loop\ifnum\count255<256 \catcode\count255=#1\relax \advance\count255 by 1 \repeat } % @documentencoding sets the definition of non-ASCII characters % according to the specified encoding. % \def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz} \def\documentencodingzzz#1{% % Get input by bytes instead of by UTF-8 codepoints for XeTeX, % otherwise the encoding support is completely broken. % This settings is for the document root file. \ifx\XeTeXrevision\thisisundefined \else \XeTeXinputencoding "bytes" \fi % % Encoding being declared for the document. \def\declaredencoding{\csname #1.enc\endcsname}% % % Supported encodings: names converted to tokens in order to be able % to compare them with \ifx. \def\ascii{\csname US-ASCII.enc\endcsname}% \def\latnine{\csname ISO-8859-15.enc\endcsname}% \def\latone{\csname ISO-8859-1.enc\endcsname}% \def\lattwo{\csname ISO-8859-2.enc\endcsname}% \def\utfeight{\csname UTF-8.enc\endcsname}% % \ifx \declaredencoding \ascii \asciichardefs % \else \ifx \declaredencoding \lattwo \setnonasciicharscatcode\active \lattwochardefs % \else \ifx \declaredencoding \latone \setnonasciicharscatcode\active \latonechardefs % \else \ifx \declaredencoding \latnine \setnonasciicharscatcode\active \latninechardefs % \else \ifx \declaredencoding \utfeight \setnonasciicharscatcode\active % since we already invoked \utfeightchardefs at the top level % (below), do not re-invoke it, then our check for duplicated % definitions triggers. Making non-ascii chars active is enough. % \else \message{Ignoring unknown document encoding: #1.}% % \fi % utfeight \fi % latnine \fi % latone \fi % lattwo \fi % ascii } % emacs-page % A message to be logged when using a character that isn't available % the default font encoding (OT1). % \def\missingcharmsg#1{\message{Character missing, sorry: #1.}} % Take account of \c (plain) vs. \, (Texinfo) difference. \def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} % First, make active non-ASCII characters in order for them to be % correctly categorized when TeX reads the replacement text of % macros containing the character definitions. \setnonasciicharscatcode\active % % Latin1 (ISO-8859-1) character definitions. \def\latonechardefs{% \gdef^^a0{\tie} \gdef^^a1{\exclamdown} \gdef^^a2{{\tcfont \char162}} % cent \gdef^^a3{\pounds} \gdef^^a4{{\tcfont \char164}} % currency \gdef^^a5{{\tcfont \char165}} % yen \gdef^^a6{{\tcfont \char166}} % broken bar \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\copyright} \gdef^^aa{\ordf} \gdef^^ab{\guillemetleft} \gdef^^ac{\ensuremath\lnot} \gdef^^ad{\-} \gdef^^ae{\registeredsymbol} \gdef^^af{\={}} % \gdef^^b0{\textdegree} \gdef^^b1{$\pm$} \gdef^^b2{$^2$} \gdef^^b3{$^3$} \gdef^^b4{\'{}} \gdef^^b5{$\mu$} \gdef^^b6{\P} \gdef^^b7{\ensuremath\cdot} \gdef^^b8{\cedilla\ } \gdef^^b9{$^1$} \gdef^^ba{\ordm} \gdef^^bb{\guillemetright} \gdef^^bc{$1\over4$} \gdef^^bd{$1\over2$} \gdef^^be{$3\over4$} \gdef^^bf{\questiondown} % \gdef^^c0{\`A} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\~A} \gdef^^c4{\"A} \gdef^^c5{\ringaccent A} \gdef^^c6{\AE} \gdef^^c7{\cedilla C} \gdef^^c8{\`E} \gdef^^c9{\'E} \gdef^^ca{\^E} \gdef^^cb{\"E} \gdef^^cc{\`I} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\"I} % \gdef^^d0{\DH} \gdef^^d1{\~N} \gdef^^d2{\`O} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\~O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\O} \gdef^^d9{\`U} \gdef^^da{\'U} \gdef^^db{\^U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\TH} \gdef^^df{\ss} % \gdef^^e0{\`a} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\~a} \gdef^^e4{\"a} \gdef^^e5{\ringaccent a} \gdef^^e6{\ae} \gdef^^e7{\cedilla c} \gdef^^e8{\`e} \gdef^^e9{\'e} \gdef^^ea{\^e} \gdef^^eb{\"e} \gdef^^ec{\`{\dotless i}} \gdef^^ed{\'{\dotless i}} \gdef^^ee{\^{\dotless i}} \gdef^^ef{\"{\dotless i}} % \gdef^^f0{\dh} \gdef^^f1{\~n} \gdef^^f2{\`o} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\~o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\o} \gdef^^f9{\`u} \gdef^^fa{\'u} \gdef^^fb{\^u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\th} \gdef^^ff{\"y} } % Latin9 (ISO-8859-15) encoding character definitions. \def\latninechardefs{% % Encoding is almost identical to Latin1. \latonechardefs % \gdef^^a4{\euro} \gdef^^a6{\v S} \gdef^^a8{\v s} \gdef^^b4{\v Z} \gdef^^b8{\v z} \gdef^^bc{\OE} \gdef^^bd{\oe} \gdef^^be{\"Y} } % Latin2 (ISO-8859-2) character definitions. \def\lattwochardefs{% \gdef^^a0{\tie} \gdef^^a1{\ogonek{A}} \gdef^^a2{\u{}} \gdef^^a3{\L} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\v L} \gdef^^a6{\'S} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\v S} \gdef^^aa{\cedilla S} \gdef^^ab{\v T} \gdef^^ac{\'Z} \gdef^^ad{\-} \gdef^^ae{\v Z} \gdef^^af{\dotaccent Z} % \gdef^^b0{\textdegree} \gdef^^b1{\ogonek{a}} \gdef^^b2{\ogonek{ }} \gdef^^b3{\l} \gdef^^b4{\'{}} \gdef^^b5{\v l} \gdef^^b6{\'s} \gdef^^b7{\v{}} \gdef^^b8{\cedilla\ } \gdef^^b9{\v s} \gdef^^ba{\cedilla s} \gdef^^bb{\v t} \gdef^^bc{\'z} \gdef^^bd{\H{}} \gdef^^be{\v z} \gdef^^bf{\dotaccent z} % \gdef^^c0{\'R} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\u A} \gdef^^c4{\"A} \gdef^^c5{\'L} \gdef^^c6{\'C} \gdef^^c7{\cedilla C} \gdef^^c8{\v C} \gdef^^c9{\'E} \gdef^^ca{\ogonek{E}} \gdef^^cb{\"E} \gdef^^cc{\v E} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\v D} % \gdef^^d0{\DH} \gdef^^d1{\'N} \gdef^^d2{\v N} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\H O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\v R} \gdef^^d9{\ringaccent U} \gdef^^da{\'U} \gdef^^db{\H U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\cedilla T} \gdef^^df{\ss} % \gdef^^e0{\'r} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\u a} \gdef^^e4{\"a} \gdef^^e5{\'l} \gdef^^e6{\'c} \gdef^^e7{\cedilla c} \gdef^^e8{\v c} \gdef^^e9{\'e} \gdef^^ea{\ogonek{e}} \gdef^^eb{\"e} \gdef^^ec{\v e} \gdef^^ed{\'{\dotless{i}}} \gdef^^ee{\^{\dotless{i}}} \gdef^^ef{\v d} % \gdef^^f0{\dh} \gdef^^f1{\'n} \gdef^^f2{\v n} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\H o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\v r} \gdef^^f9{\ringaccent u} \gdef^^fa{\'u} \gdef^^fb{\H u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\cedilla t} \gdef^^ff{\dotaccent{}} } % UTF-8 character definitions. % % This code to support UTF-8 is based on LaTeX's utf8.def, with some % changes for Texinfo conventions. It is included here under the GPL by % permission from Frank Mittelbach and the LaTeX team. % \newcount\countUTFx \newcount\countUTFy \newcount\countUTFz \gdef\UTFviiiTwoOctets#1#2{\expandafter \UTFviiiDefined\csname u8:#1\string #2\endcsname} % \gdef\UTFviiiThreeOctets#1#2#3{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} % \gdef\UTFviiiFourOctets#1#2#3#4{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} \gdef\UTFviiiDefined#1{% \ifx #1\relax \message{\linenumber Unicode char \string #1 not defined for Texinfo}% \else \expandafter #1% \fi } \begingroup \catcode`\~13 \catcode`\"12 \def\UTFviiiLoop{% \global\catcode\countUTFx\active \uccode`\~\countUTFx \uppercase\expandafter{\UTFviiiTmp}% \advance\countUTFx by 1 \ifnum\countUTFx < \countUTFy \expandafter\UTFviiiLoop \fi} \countUTFx = "C2 \countUTFy = "E0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiTwoOctets\string~}} \UTFviiiLoop \countUTFx = "E0 \countUTFy = "F0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiThreeOctets\string~}} \UTFviiiLoop \countUTFx = "F0 \countUTFy = "F4 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiFourOctets\string~}} \UTFviiiLoop \endgroup \def\globallet{\global\let} % save some \expandafter's below % @U{xxxx} to produce U+xxxx, if we support it. \def\U#1{% \expandafter\ifx\csname uni:#1\endcsname \relax \errhelp = \EMsimple \errmessage{Unicode character U+#1 not supported, sorry}% \else \csname uni:#1\endcsname \fi } \begingroup \catcode`\"=12 \catcode`\<=12 \catcode`\.=12 \catcode`\,=12 \catcode`\;=12 \catcode`\!=12 \catcode`\~=13 \gdef\DeclareUnicodeCharacter#1#2{% \countUTFz = "#1\relax %\wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% \begingroup \parseXMLCharref \def\UTFviiiTwoOctets##1##2{% \csname u8:##1\string ##2\endcsname}% \def\UTFviiiThreeOctets##1##2##3{% \csname u8:##1\string ##2\string ##3\endcsname}% \def\UTFviiiFourOctets##1##2##3##4{% \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter \gdef\UTFviiiTmp{#2}% % \expandafter\ifx\csname uni:#1\endcsname \relax \else \message{Internal error, already defined: #1}% \fi % % define an additional control sequence for this code point. \expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp \endgroup} \gdef\parseXMLCharref{% \ifnum\countUTFz < "A0\relax \errhelp = \EMsimple \errmessage{Cannot define Unicode char value < 00A0}% \else\ifnum\countUTFz < "800\relax \parseUTFviiiA,% \parseUTFviiiB C\UTFviiiTwoOctets.,% \else\ifnum\countUTFz < "10000\relax \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% \else \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiA!% \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% \fi\fi\fi } \gdef\parseUTFviiiA#1{% \countUTFx = \countUTFz \divide\countUTFz by 64 \countUTFy = \countUTFz \multiply\countUTFz by 64 \advance\countUTFx by -\countUTFz \advance\countUTFx by 128 \uccode `#1\countUTFx \countUTFz = \countUTFy} \gdef\parseUTFviiiB#1#2#3#4{% \advance\countUTFz by "#10\relax \uccode `#3\countUTFz \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} \endgroup % https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M % U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block) % U+0080..U+00FF = https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block) % U+0100..U+017F = https://en.wikipedia.org/wiki/Latin_Extended-A % U+0180..U+024F = https://en.wikipedia.org/wiki/Latin_Extended-B % % Many of our renditions are less than wonderful, and all the missing % characters are available somewhere. Loading the necessary fonts % awaits user request. We can't truly support Unicode without % reimplementing everything that's been done in LaTeX for many years, % plus probably using luatex or xetex, and who knows what else. % We won't be doing that here in this simple file. But we can try to at % least make most of the characters not bomb out. % \def\utfeightchardefs{% \DeclareUnicodeCharacter{00A0}{\tie} \DeclareUnicodeCharacter{00A1}{\exclamdown} \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent \DeclareUnicodeCharacter{00A3}{\pounds} \DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency \DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen \DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar \DeclareUnicodeCharacter{00A7}{\S} \DeclareUnicodeCharacter{00A8}{\"{ }} \DeclareUnicodeCharacter{00A9}{\copyright} \DeclareUnicodeCharacter{00AA}{\ordf} \DeclareUnicodeCharacter{00AB}{\guillemetleft} \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot} \DeclareUnicodeCharacter{00AD}{\-} \DeclareUnicodeCharacter{00AE}{\registeredsymbol} \DeclareUnicodeCharacter{00AF}{\={ }} % \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} \DeclareUnicodeCharacter{00B1}{\ensuremath\pm} \DeclareUnicodeCharacter{00B2}{$^2$} \DeclareUnicodeCharacter{00B3}{$^3$} \DeclareUnicodeCharacter{00B4}{\'{ }} \DeclareUnicodeCharacter{00B5}{$\mu$} \DeclareUnicodeCharacter{00B6}{\P} \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot} \DeclareUnicodeCharacter{00B8}{\cedilla{ }} \DeclareUnicodeCharacter{00B9}{$^1$} \DeclareUnicodeCharacter{00BA}{\ordm} \DeclareUnicodeCharacter{00BB}{\guillemetright} \DeclareUnicodeCharacter{00BC}{$1\over4$} \DeclareUnicodeCharacter{00BD}{$1\over2$} \DeclareUnicodeCharacter{00BE}{$3\over4$} \DeclareUnicodeCharacter{00BF}{\questiondown} % \DeclareUnicodeCharacter{00C0}{\`A} \DeclareUnicodeCharacter{00C1}{\'A} \DeclareUnicodeCharacter{00C2}{\^A} \DeclareUnicodeCharacter{00C3}{\~A} \DeclareUnicodeCharacter{00C4}{\"A} \DeclareUnicodeCharacter{00C5}{\AA} \DeclareUnicodeCharacter{00C6}{\AE} \DeclareUnicodeCharacter{00C7}{\cedilla{C}} \DeclareUnicodeCharacter{00C8}{\`E} \DeclareUnicodeCharacter{00C9}{\'E} \DeclareUnicodeCharacter{00CA}{\^E} \DeclareUnicodeCharacter{00CB}{\"E} \DeclareUnicodeCharacter{00CC}{\`I} \DeclareUnicodeCharacter{00CD}{\'I} \DeclareUnicodeCharacter{00CE}{\^I} \DeclareUnicodeCharacter{00CF}{\"I} % \DeclareUnicodeCharacter{00D0}{\DH} \DeclareUnicodeCharacter{00D1}{\~N} \DeclareUnicodeCharacter{00D2}{\`O} \DeclareUnicodeCharacter{00D3}{\'O} \DeclareUnicodeCharacter{00D4}{\^O} \DeclareUnicodeCharacter{00D5}{\~O} \DeclareUnicodeCharacter{00D6}{\"O} \DeclareUnicodeCharacter{00D7}{\ensuremath\times} \DeclareUnicodeCharacter{00D8}{\O} \DeclareUnicodeCharacter{00D9}{\`U} \DeclareUnicodeCharacter{00DA}{\'U} \DeclareUnicodeCharacter{00DB}{\^U} \DeclareUnicodeCharacter{00DC}{\"U} \DeclareUnicodeCharacter{00DD}{\'Y} \DeclareUnicodeCharacter{00DE}{\TH} \DeclareUnicodeCharacter{00DF}{\ss} % \DeclareUnicodeCharacter{00E0}{\`a} \DeclareUnicodeCharacter{00E1}{\'a} \DeclareUnicodeCharacter{00E2}{\^a} \DeclareUnicodeCharacter{00E3}{\~a} \DeclareUnicodeCharacter{00E4}{\"a} \DeclareUnicodeCharacter{00E5}{\aa} \DeclareUnicodeCharacter{00E6}{\ae} \DeclareUnicodeCharacter{00E7}{\cedilla{c}} \DeclareUnicodeCharacter{00E8}{\`e} \DeclareUnicodeCharacter{00E9}{\'e} \DeclareUnicodeCharacter{00EA}{\^e} \DeclareUnicodeCharacter{00EB}{\"e} \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} % \DeclareUnicodeCharacter{00F0}{\dh} \DeclareUnicodeCharacter{00F1}{\~n} \DeclareUnicodeCharacter{00F2}{\`o} \DeclareUnicodeCharacter{00F3}{\'o} \DeclareUnicodeCharacter{00F4}{\^o} \DeclareUnicodeCharacter{00F5}{\~o} \DeclareUnicodeCharacter{00F6}{\"o} \DeclareUnicodeCharacter{00F7}{\ensuremath\div} \DeclareUnicodeCharacter{00F8}{\o} \DeclareUnicodeCharacter{00F9}{\`u} \DeclareUnicodeCharacter{00FA}{\'u} \DeclareUnicodeCharacter{00FB}{\^u} \DeclareUnicodeCharacter{00FC}{\"u} \DeclareUnicodeCharacter{00FD}{\'y} \DeclareUnicodeCharacter{00FE}{\th} \DeclareUnicodeCharacter{00FF}{\"y} % \DeclareUnicodeCharacter{0100}{\=A} \DeclareUnicodeCharacter{0101}{\=a} \DeclareUnicodeCharacter{0102}{\u{A}} \DeclareUnicodeCharacter{0103}{\u{a}} \DeclareUnicodeCharacter{0104}{\ogonek{A}} \DeclareUnicodeCharacter{0105}{\ogonek{a}} \DeclareUnicodeCharacter{0106}{\'C} \DeclareUnicodeCharacter{0107}{\'c} \DeclareUnicodeCharacter{0108}{\^C} \DeclareUnicodeCharacter{0109}{\^c} \DeclareUnicodeCharacter{010A}{\dotaccent{C}} \DeclareUnicodeCharacter{010B}{\dotaccent{c}} \DeclareUnicodeCharacter{010C}{\v{C}} \DeclareUnicodeCharacter{010D}{\v{c}} \DeclareUnicodeCharacter{010E}{\v{D}} \DeclareUnicodeCharacter{010F}{d'} % \DeclareUnicodeCharacter{0110}{\DH} \DeclareUnicodeCharacter{0111}{\dh} \DeclareUnicodeCharacter{0112}{\=E} \DeclareUnicodeCharacter{0113}{\=e} \DeclareUnicodeCharacter{0114}{\u{E}} \DeclareUnicodeCharacter{0115}{\u{e}} \DeclareUnicodeCharacter{0116}{\dotaccent{E}} \DeclareUnicodeCharacter{0117}{\dotaccent{e}} \DeclareUnicodeCharacter{0118}{\ogonek{E}} \DeclareUnicodeCharacter{0119}{\ogonek{e}} \DeclareUnicodeCharacter{011A}{\v{E}} \DeclareUnicodeCharacter{011B}{\v{e}} \DeclareUnicodeCharacter{011C}{\^G} \DeclareUnicodeCharacter{011D}{\^g} \DeclareUnicodeCharacter{011E}{\u{G}} \DeclareUnicodeCharacter{011F}{\u{g}} % \DeclareUnicodeCharacter{0120}{\dotaccent{G}} \DeclareUnicodeCharacter{0121}{\dotaccent{g}} \DeclareUnicodeCharacter{0122}{\cedilla{G}} \DeclareUnicodeCharacter{0123}{\cedilla{g}} \DeclareUnicodeCharacter{0124}{\^H} \DeclareUnicodeCharacter{0125}{\^h} \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}} \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}} \DeclareUnicodeCharacter{0128}{\~I} \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} \DeclareUnicodeCharacter{012A}{\=I} \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} \DeclareUnicodeCharacter{012C}{\u{I}} \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} \DeclareUnicodeCharacter{012E}{\ogonek{I}} \DeclareUnicodeCharacter{012F}{\ogonek{i}} % \DeclareUnicodeCharacter{0130}{\dotaccent{I}} \DeclareUnicodeCharacter{0131}{\dotless{i}} \DeclareUnicodeCharacter{0132}{IJ} \DeclareUnicodeCharacter{0133}{ij} \DeclareUnicodeCharacter{0134}{\^J} \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} \DeclareUnicodeCharacter{0136}{\cedilla{K}} \DeclareUnicodeCharacter{0137}{\cedilla{k}} \DeclareUnicodeCharacter{0138}{\ensuremath\kappa} \DeclareUnicodeCharacter{0139}{\'L} \DeclareUnicodeCharacter{013A}{\'l} \DeclareUnicodeCharacter{013B}{\cedilla{L}} \DeclareUnicodeCharacter{013C}{\cedilla{l}} \DeclareUnicodeCharacter{013D}{L'}% should kern \DeclareUnicodeCharacter{013E}{l'}% should kern \DeclareUnicodeCharacter{013F}{L\U{00B7}} % \DeclareUnicodeCharacter{0140}{l\U{00B7}} \DeclareUnicodeCharacter{0141}{\L} \DeclareUnicodeCharacter{0142}{\l} \DeclareUnicodeCharacter{0143}{\'N} \DeclareUnicodeCharacter{0144}{\'n} \DeclareUnicodeCharacter{0145}{\cedilla{N}} \DeclareUnicodeCharacter{0146}{\cedilla{n}} \DeclareUnicodeCharacter{0147}{\v{N}} \DeclareUnicodeCharacter{0148}{\v{n}} \DeclareUnicodeCharacter{0149}{'n} \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}} \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}} \DeclareUnicodeCharacter{014C}{\=O} \DeclareUnicodeCharacter{014D}{\=o} \DeclareUnicodeCharacter{014E}{\u{O}} \DeclareUnicodeCharacter{014F}{\u{o}} % \DeclareUnicodeCharacter{0150}{\H{O}} \DeclareUnicodeCharacter{0151}{\H{o}} \DeclareUnicodeCharacter{0152}{\OE} \DeclareUnicodeCharacter{0153}{\oe} \DeclareUnicodeCharacter{0154}{\'R} \DeclareUnicodeCharacter{0155}{\'r} \DeclareUnicodeCharacter{0156}{\cedilla{R}} \DeclareUnicodeCharacter{0157}{\cedilla{r}} \DeclareUnicodeCharacter{0158}{\v{R}} \DeclareUnicodeCharacter{0159}{\v{r}} \DeclareUnicodeCharacter{015A}{\'S} \DeclareUnicodeCharacter{015B}{\'s} \DeclareUnicodeCharacter{015C}{\^S} \DeclareUnicodeCharacter{015D}{\^s} \DeclareUnicodeCharacter{015E}{\cedilla{S}} \DeclareUnicodeCharacter{015F}{\cedilla{s}} % \DeclareUnicodeCharacter{0160}{\v{S}} \DeclareUnicodeCharacter{0161}{\v{s}} \DeclareUnicodeCharacter{0162}{\cedilla{T}} \DeclareUnicodeCharacter{0163}{\cedilla{t}} \DeclareUnicodeCharacter{0164}{\v{T}} \DeclareUnicodeCharacter{0165}{\v{t}} \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}} \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}} \DeclareUnicodeCharacter{0168}{\~U} \DeclareUnicodeCharacter{0169}{\~u} \DeclareUnicodeCharacter{016A}{\=U} \DeclareUnicodeCharacter{016B}{\=u} \DeclareUnicodeCharacter{016C}{\u{U}} \DeclareUnicodeCharacter{016D}{\u{u}} \DeclareUnicodeCharacter{016E}{\ringaccent{U}} \DeclareUnicodeCharacter{016F}{\ringaccent{u}} % \DeclareUnicodeCharacter{0170}{\H{U}} \DeclareUnicodeCharacter{0171}{\H{u}} \DeclareUnicodeCharacter{0172}{\ogonek{U}} \DeclareUnicodeCharacter{0173}{\ogonek{u}} \DeclareUnicodeCharacter{0174}{\^W} \DeclareUnicodeCharacter{0175}{\^w} \DeclareUnicodeCharacter{0176}{\^Y} \DeclareUnicodeCharacter{0177}{\^y} \DeclareUnicodeCharacter{0178}{\"Y} \DeclareUnicodeCharacter{0179}{\'Z} \DeclareUnicodeCharacter{017A}{\'z} \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} \DeclareUnicodeCharacter{017C}{\dotaccent{z}} \DeclareUnicodeCharacter{017D}{\v{Z}} \DeclareUnicodeCharacter{017E}{\v{z}} \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}} % \DeclareUnicodeCharacter{01C4}{D\v{Z}} \DeclareUnicodeCharacter{01C5}{D\v{z}} \DeclareUnicodeCharacter{01C6}{d\v{z}} \DeclareUnicodeCharacter{01C7}{LJ} \DeclareUnicodeCharacter{01C8}{Lj} \DeclareUnicodeCharacter{01C9}{lj} \DeclareUnicodeCharacter{01CA}{NJ} \DeclareUnicodeCharacter{01CB}{Nj} \DeclareUnicodeCharacter{01CC}{nj} \DeclareUnicodeCharacter{01CD}{\v{A}} \DeclareUnicodeCharacter{01CE}{\v{a}} \DeclareUnicodeCharacter{01CF}{\v{I}} % \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} \DeclareUnicodeCharacter{01D1}{\v{O}} \DeclareUnicodeCharacter{01D2}{\v{o}} \DeclareUnicodeCharacter{01D3}{\v{U}} \DeclareUnicodeCharacter{01D4}{\v{u}} % \DeclareUnicodeCharacter{01E2}{\={\AE}} \DeclareUnicodeCharacter{01E3}{\={\ae}} \DeclareUnicodeCharacter{01E6}{\v{G}} \DeclareUnicodeCharacter{01E7}{\v{g}} \DeclareUnicodeCharacter{01E8}{\v{K}} \DeclareUnicodeCharacter{01E9}{\v{k}} % \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} \DeclareUnicodeCharacter{01F1}{DZ} \DeclareUnicodeCharacter{01F2}{Dz} \DeclareUnicodeCharacter{01F3}{dz} \DeclareUnicodeCharacter{01F4}{\'G} \DeclareUnicodeCharacter{01F5}{\'g} \DeclareUnicodeCharacter{01F8}{\`N} \DeclareUnicodeCharacter{01F9}{\`n} \DeclareUnicodeCharacter{01FC}{\'{\AE}} \DeclareUnicodeCharacter{01FD}{\'{\ae}} \DeclareUnicodeCharacter{01FE}{\'{\O}} \DeclareUnicodeCharacter{01FF}{\'{\o}} % \DeclareUnicodeCharacter{021E}{\v{H}} \DeclareUnicodeCharacter{021F}{\v{h}} % \DeclareUnicodeCharacter{0226}{\dotaccent{A}} \DeclareUnicodeCharacter{0227}{\dotaccent{a}} \DeclareUnicodeCharacter{0228}{\cedilla{E}} \DeclareUnicodeCharacter{0229}{\cedilla{e}} \DeclareUnicodeCharacter{022E}{\dotaccent{O}} \DeclareUnicodeCharacter{022F}{\dotaccent{o}} % \DeclareUnicodeCharacter{0232}{\=Y} \DeclareUnicodeCharacter{0233}{\=y} \DeclareUnicodeCharacter{0237}{\dotless{j}} % \DeclareUnicodeCharacter{02DB}{\ogonek{ }} % % Greek letters upper case \DeclareUnicodeCharacter{0391}{{\it A}} \DeclareUnicodeCharacter{0392}{{\it B}} \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}} \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}} \DeclareUnicodeCharacter{0395}{{\it E}} \DeclareUnicodeCharacter{0396}{{\it Z}} \DeclareUnicodeCharacter{0397}{{\it H}} \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}} \DeclareUnicodeCharacter{0399}{{\it I}} \DeclareUnicodeCharacter{039A}{{\it K}} \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}} \DeclareUnicodeCharacter{039C}{{\it M}} \DeclareUnicodeCharacter{039D}{{\it N}} \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}} \DeclareUnicodeCharacter{039F}{{\it O}} \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}} \DeclareUnicodeCharacter{03A1}{{\it P}} %\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}} \DeclareUnicodeCharacter{03A4}{{\it T}} \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}} \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}} \DeclareUnicodeCharacter{03A7}{{\it X}} \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}} \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}} % % Vowels with accents \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}} \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}} \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}} \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}} \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}} \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}} % % Standalone accent \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}} % % Greek letters lower case \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha} \DeclareUnicodeCharacter{03B2}{\ensuremath\beta} \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma} \DeclareUnicodeCharacter{03B4}{\ensuremath\delta} \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon} \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta} \DeclareUnicodeCharacter{03B7}{\ensuremath\eta} \DeclareUnicodeCharacter{03B8}{\ensuremath\theta} \DeclareUnicodeCharacter{03B9}{\ensuremath\iota} \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa} \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda} \DeclareUnicodeCharacter{03BC}{\ensuremath\mu} \DeclareUnicodeCharacter{03BD}{\ensuremath\nu} \DeclareUnicodeCharacter{03BE}{\ensuremath\xi} \DeclareUnicodeCharacter{03BF}{{\it o}} % omicron \DeclareUnicodeCharacter{03C0}{\ensuremath\pi} \DeclareUnicodeCharacter{03C1}{\ensuremath\rho} \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma} \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma} \DeclareUnicodeCharacter{03C4}{\ensuremath\tau} \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon} \DeclareUnicodeCharacter{03C6}{\ensuremath\phi} \DeclareUnicodeCharacter{03C7}{\ensuremath\chi} \DeclareUnicodeCharacter{03C8}{\ensuremath\psi} \DeclareUnicodeCharacter{03C9}{\ensuremath\omega} % % More Greek vowels with accents \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}} \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}} \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}} \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}} \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}} % % Variant Greek letters \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta} \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi} \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho} % \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} % \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} % \DeclareUnicodeCharacter{1E20}{\=G} \DeclareUnicodeCharacter{1E21}{\=g} \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} \DeclareUnicodeCharacter{1E26}{\"H} \DeclareUnicodeCharacter{1E27}{\"h} % \DeclareUnicodeCharacter{1E30}{\'K} \DeclareUnicodeCharacter{1E31}{\'k} \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} \DeclareUnicodeCharacter{1E3E}{\'M} \DeclareUnicodeCharacter{1E3F}{\'m} % \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} % \DeclareUnicodeCharacter{1E54}{\'P} \DeclareUnicodeCharacter{1E55}{\'p} \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} % \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} % \DeclareUnicodeCharacter{1E7C}{\~V} \DeclareUnicodeCharacter{1E7D}{\~v} \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} % \DeclareUnicodeCharacter{1E80}{\`W} \DeclareUnicodeCharacter{1E81}{\`w} \DeclareUnicodeCharacter{1E82}{\'W} \DeclareUnicodeCharacter{1E83}{\'w} \DeclareUnicodeCharacter{1E84}{\"W} \DeclareUnicodeCharacter{1E85}{\"w} \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} \DeclareUnicodeCharacter{1E8C}{\"X} \DeclareUnicodeCharacter{1E8D}{\"x} \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} % \DeclareUnicodeCharacter{1E90}{\^Z} \DeclareUnicodeCharacter{1E91}{\^z} \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} \DeclareUnicodeCharacter{1E97}{\"t} \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} % \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} % \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} \DeclareUnicodeCharacter{1EBC}{\~E} \DeclareUnicodeCharacter{1EBD}{\~e} % \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} % \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} % \DeclareUnicodeCharacter{1EF2}{\`Y} \DeclareUnicodeCharacter{1EF3}{\`y} \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} % \DeclareUnicodeCharacter{1EF8}{\~Y} \DeclareUnicodeCharacter{1EF9}{\~y} % % Punctuation \DeclareUnicodeCharacter{2013}{--} \DeclareUnicodeCharacter{2014}{---} \DeclareUnicodeCharacter{2018}{\quoteleft} \DeclareUnicodeCharacter{2019}{\quoteright} \DeclareUnicodeCharacter{201A}{\quotesinglbase} \DeclareUnicodeCharacter{201C}{\quotedblleft} \DeclareUnicodeCharacter{201D}{\quotedblright} \DeclareUnicodeCharacter{201E}{\quotedblbase} \DeclareUnicodeCharacter{2020}{\ensuremath\dagger} \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger} \DeclareUnicodeCharacter{2022}{\bullet} \DeclareUnicodeCharacter{202F}{\thinspace} \DeclareUnicodeCharacter{2026}{\dots} \DeclareUnicodeCharacter{2039}{\guilsinglleft} \DeclareUnicodeCharacter{203A}{\guilsinglright} % \DeclareUnicodeCharacter{20AC}{\euro} % \DeclareUnicodeCharacter{2192}{\expansion} \DeclareUnicodeCharacter{21D2}{\result} % % Mathematical symbols \DeclareUnicodeCharacter{2200}{\ensuremath\forall} \DeclareUnicodeCharacter{2203}{\ensuremath\exists} \DeclareUnicodeCharacter{2208}{\ensuremath\in} \DeclareUnicodeCharacter{2212}{\minus} \DeclareUnicodeCharacter{2217}{\ast} \DeclareUnicodeCharacter{221E}{\ensuremath\infty} \DeclareUnicodeCharacter{2225}{\ensuremath\parallel} \DeclareUnicodeCharacter{2227}{\ensuremath\wedge} \DeclareUnicodeCharacter{2229}{\ensuremath\cap} \DeclareUnicodeCharacter{2261}{\equiv} \DeclareUnicodeCharacter{2264}{\ensuremath\leq} \DeclareUnicodeCharacter{2265}{\ensuremath\geq} \DeclareUnicodeCharacter{2282}{\ensuremath\subset} \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq} % \DeclareUnicodeCharacter{2016}{\ensuremath\Vert} \DeclareUnicodeCharacter{2032}{\ensuremath\prime} \DeclareUnicodeCharacter{210F}{\ensuremath\hbar} \DeclareUnicodeCharacter{2111}{\ensuremath\Im} \DeclareUnicodeCharacter{2113}{\ensuremath\ell} \DeclareUnicodeCharacter{2118}{\ensuremath\wp} \DeclareUnicodeCharacter{211C}{\ensuremath\Re} \DeclareUnicodeCharacter{2127}{\ensuremath\mho} \DeclareUnicodeCharacter{2135}{\ensuremath\aleph} \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow} \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow} \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow} \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow} \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow} \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow} \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow} \DeclareUnicodeCharacter{2198}{\ensuremath\searrow} \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow} \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto} \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow} \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow} \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup} \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown} \DeclareUnicodeCharacter{21BE}{\ensuremath\upharpoonright} \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup} \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown} \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons} \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow} \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow} \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow} \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow} \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow} \DeclareUnicodeCharacter{21DD}{\ensuremath\leadsto} \DeclareUnicodeCharacter{2201}{\ensuremath\complement} \DeclareUnicodeCharacter{2202}{\ensuremath\partial} \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset} \DeclareUnicodeCharacter{2207}{\ensuremath\nabla} \DeclareUnicodeCharacter{2209}{\ensuremath\notin} \DeclareUnicodeCharacter{220B}{\ensuremath\owns} \DeclareUnicodeCharacter{220F}{\ensuremath\prod} \DeclareUnicodeCharacter{2210}{\ensuremath\coprod} \DeclareUnicodeCharacter{2211}{\ensuremath\sum} \DeclareUnicodeCharacter{2213}{\ensuremath\mp} \DeclareUnicodeCharacter{2218}{\ensuremath\circ} \DeclareUnicodeCharacter{221A}{\ensuremath\surd} \DeclareUnicodeCharacter{221D}{\ensuremath\propto} \DeclareUnicodeCharacter{2220}{\ensuremath\angle} \DeclareUnicodeCharacter{2223}{\ensuremath\mid} \DeclareUnicodeCharacter{2228}{\ensuremath\vee} \DeclareUnicodeCharacter{222A}{\ensuremath\cup} \DeclareUnicodeCharacter{222B}{\ensuremath\smallint} \DeclareUnicodeCharacter{222E}{\ensuremath\oint} \DeclareUnicodeCharacter{223C}{\ensuremath\sim} \DeclareUnicodeCharacter{2240}{\ensuremath\wr} \DeclareUnicodeCharacter{2243}{\ensuremath\simeq} \DeclareUnicodeCharacter{2245}{\ensuremath\cong} \DeclareUnicodeCharacter{2248}{\ensuremath\approx} \DeclareUnicodeCharacter{224D}{\ensuremath\asymp} \DeclareUnicodeCharacter{2250}{\ensuremath\doteq} \DeclareUnicodeCharacter{2260}{\ensuremath\neq} \DeclareUnicodeCharacter{226A}{\ensuremath\ll} \DeclareUnicodeCharacter{226B}{\ensuremath\gg} \DeclareUnicodeCharacter{227A}{\ensuremath\prec} \DeclareUnicodeCharacter{227B}{\ensuremath\succ} \DeclareUnicodeCharacter{2283}{\ensuremath\supset} \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq} \DeclareUnicodeCharacter{228E}{\ensuremath\uplus} \DeclareUnicodeCharacter{228F}{\ensuremath\sqsubset} \DeclareUnicodeCharacter{2290}{\ensuremath\sqsupset} \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq} \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq} \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap} \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup} \DeclareUnicodeCharacter{2295}{\ensuremath\oplus} \DeclareUnicodeCharacter{2296}{\ensuremath\ominus} \DeclareUnicodeCharacter{2297}{\ensuremath\otimes} \DeclareUnicodeCharacter{2298}{\ensuremath\oslash} \DeclareUnicodeCharacter{2299}{\ensuremath\odot} \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash} \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv} \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop} \DeclareUnicodeCharacter{22A5}{\ensuremath\bot} \DeclareUnicodeCharacter{22A8}{\ensuremath\models} \DeclareUnicodeCharacter{22B4}{\ensuremath\unlhd} \DeclareUnicodeCharacter{22B5}{\ensuremath\unrhd} \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge} \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee} \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap} \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup} \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond} \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot} \DeclareUnicodeCharacter{22C6}{\ensuremath\star} \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie} \DeclareUnicodeCharacter{2308}{\ensuremath\lceil} \DeclareUnicodeCharacter{2309}{\ensuremath\rceil} \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor} \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor} \DeclareUnicodeCharacter{2322}{\ensuremath\frown} \DeclareUnicodeCharacter{2323}{\ensuremath\smile} % \DeclareUnicodeCharacter{25A1}{\ensuremath\Box} \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle} \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright} \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown} \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft} \DeclareUnicodeCharacter{25C7}{\ensuremath\Diamond} \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit} \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit} \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit} \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit} \DeclareUnicodeCharacter{266D}{\ensuremath\flat} \DeclareUnicodeCharacter{266E}{\ensuremath\natural} \DeclareUnicodeCharacter{266F}{\ensuremath\sharp} \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc} \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle} \DeclareUnicodeCharacter{27C2}{\ensuremath\perp} \DeclareUnicodeCharacter{27E8}{\ensuremath\langle} \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow} \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow} \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow} \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto} \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus} \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot} \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus} \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes} \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus} \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup} \DeclareUnicodeCharacter{2A1D}{\ensuremath\Join} \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg} \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq} \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq} % \global\mathchardef\checkmark="1370 % actually the square root sign \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark} }% end of \utfeightchardefs % US-ASCII character definitions. \def\asciichardefs{% nothing need be done \relax } % Latin1 (ISO-8859-1) character definitions. \def\nonasciistringdefs{% \setnonasciicharscatcode\active \def\defstringchar##1{\def##1{\string##1}}% % \defstringchar^^80\defstringchar^^81\defstringchar^^82\defstringchar^^83% \defstringchar^^84\defstringchar^^85\defstringchar^^86\defstringchar^^87% \defstringchar^^88\defstringchar^^89\defstringchar^^8a\defstringchar^^8b% \defstringchar^^8c\defstringchar^^8d\defstringchar^^8e\defstringchar^^8f% % \defstringchar^^90\defstringchar^^91\defstringchar^^92\defstringchar^^93% \defstringchar^^94\defstringchar^^95\defstringchar^^96\defstringchar^^97% \defstringchar^^98\defstringchar^^99\defstringchar^^9a\defstringchar^^9b% \defstringchar^^9c\defstringchar^^9d\defstringchar^^9e\defstringchar^^9f% % \defstringchar^^a0\defstringchar^^a1\defstringchar^^a2\defstringchar^^a3% \defstringchar^^a4\defstringchar^^a5\defstringchar^^a6\defstringchar^^a7% \defstringchar^^a8\defstringchar^^a9\defstringchar^^aa\defstringchar^^ab% \defstringchar^^ac\defstringchar^^ad\defstringchar^^ae\defstringchar^^af% % \defstringchar^^b0\defstringchar^^b1\defstringchar^^b2\defstringchar^^b3% \defstringchar^^b4\defstringchar^^b5\defstringchar^^b6\defstringchar^^b7% \defstringchar^^b8\defstringchar^^b9\defstringchar^^ba\defstringchar^^bb% \defstringchar^^bc\defstringchar^^bd\defstringchar^^be\defstringchar^^bf% % \defstringchar^^c0\defstringchar^^c1\defstringchar^^c2\defstringchar^^c3% \defstringchar^^c4\defstringchar^^c5\defstringchar^^c6\defstringchar^^c7% \defstringchar^^c8\defstringchar^^c9\defstringchar^^ca\defstringchar^^cb% \defstringchar^^cc\defstringchar^^cd\defstringchar^^ce\defstringchar^^cf% % \defstringchar^^d0\defstringchar^^d1\defstringchar^^d2\defstringchar^^d3% \defstringchar^^d4\defstringchar^^d5\defstringchar^^d6\defstringchar^^d7% \defstringchar^^d8\defstringchar^^d9\defstringchar^^da\defstringchar^^db% \defstringchar^^dc\defstringchar^^dd\defstringchar^^de\defstringchar^^df% % \defstringchar^^e0\defstringchar^^e1\defstringchar^^e2\defstringchar^^e3% \defstringchar^^e4\defstringchar^^e5\defstringchar^^e6\defstringchar^^e7% \defstringchar^^e8\defstringchar^^e9\defstringchar^^ea\defstringchar^^eb% \defstringchar^^ec\defstringchar^^ed\defstringchar^^ee\defstringchar^^ef% % \defstringchar^^f0\defstringchar^^f1\defstringchar^^f2\defstringchar^^f3% \defstringchar^^f4\defstringchar^^f5\defstringchar^^f6\defstringchar^^f7% \defstringchar^^f8\defstringchar^^f9\defstringchar^^fa\defstringchar^^fb% \defstringchar^^fc\defstringchar^^fd\defstringchar^^fe\defstringchar^^ff% } % define all the unicode characters we know about, for the sake of @U. \utfeightchardefs % Make non-ASCII characters printable again for compatibility with % existing Texinfo documents that may use them, even without declaring a % document encoding. % \setnonasciicharscatcode \other \message{formatting,} \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 very finicky about underfull hboxes, either. \hbadness = 6666 % Following George Bush, 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 = .15\hsize \fi } % Parameters in order: 1) textheight; 2) textwidth; % 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; % 7) physical page height; 8) physical page width. % % We also call \setleading{\textleading}, so the caller should define % \textleading. The caller should also set \parskip. % \def\internalpagesizes#1#2#3#4#5#6#7#8{% \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 % \ifpdf \pdfpageheight #7\relax \pdfpagewidth #8\relax % if we don't reset these, they will remain at "1 true in" of % whatever layout pdftex was dumped with. \pdfhorigin = 1 true in \pdfvorigin = 1 true in \fi % \setleading{\textleading} % \parindent = \defaultparindent \setemergencystretch } % @letterpaper (the default). \def\letterpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % If page is nothing but text, make it come out even. \internalpagesizes{607.2pt}{6in}% that's 46 lines {\voffset}{.25in}% {\bindingoffset}{36pt}% {11in}{8.5in}% }} % Use @smallbook to reset parameters for 7x9.25 trim size. \def\smallbook{{\globaldefs = 1 \parskip = 2pt plus 1pt \textleading = 12pt % \internalpagesizes{7.5in}{5in}% {-.2in}{0in}% {\bindingoffset}{16pt}% {9.25in}{7in}% % \lispnarrowing = 0.3in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .5cm }} % Use @smallerbook to reset parameters for 6x9 trim size. % (Just testing, parameters still in flux.) \def\smallerbook{{\globaldefs = 1 \parskip = 1.5pt plus 1pt \textleading = 12pt % \internalpagesizes{7.4in}{4.8in}% {-.2in}{-.4in}% {0pt}{14pt}% {9in}{6in}% % \lispnarrowing = 0.25in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .4cm }} % Use @afourpaper to print on European A4 paper. \def\afourpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % Double-side printing via postscript on Laserjet 4050 % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. % To change the settings for a different printer or situation, adjust % \normaloffset until the front-side and back-side texts align. Then % do the same for \bindingoffset. You can set these for testing in % your texinfo source file like this: % @tex % \global\normaloffset = -6mm % \global\bindingoffset = 10mm % @end tex \internalpagesizes{673.2pt}{160mm}% that's 51 lines {\voffset}{\hoffset}% {\bindingoffset}{44pt}% {297mm}{210mm}% % \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = 5mm }} % Use @afivepaper to print on European A5 paper. % From romildo@urano.iceb.ufop.br, 2 July 2000. % He also recommends making @example and @lisp be small. \def\afivepaper{{\globaldefs = 1 \parskip = 2pt plus 1pt minus 0.1pt \textleading = 12.5pt % \internalpagesizes{160mm}{120mm}% {\voffset}{\hoffset}% {\bindingoffset}{8pt}% {210mm}{148mm}% % \lispnarrowing = 0.2in \tolerance = 800 \hfuzz = 1.2pt \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm }} % A specific text layout, 24x15cm overall, intended for A4 paper. \def\afourlatex{{\globaldefs = 1 \afourpaper \internalpagesizes{237mm}{150mm}% {\voffset}{4.6mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% % % Must explicitly reset to 0 because we call \afourpaper. \globaldefs = 0 }} % Use @afourwide to print on A4 paper in landscape format. \def\afourwide{{\globaldefs = 1 \afourpaper \internalpagesizes{241mm}{165mm}% {\voffset}{-2.95mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% \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. % \parseargdef\pagesizes{\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{\textleading}% % \dimen0 = #1\relax \advance\dimen0 by \voffset % \dimen2 = \hsize \advance\dimen2 by \normaloffset % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% {\bindingoffset}{44pt}% {\dimen0}{\dimen2}% }} % Set default to letter. % \letterpaper \message{and turning on texinfo input format.} \def^^L{\par} % remove \outer, so ^L can appear in an @comment % DEL is a comment character, in case @c does not suffice. \catcode`\^^? = 14 % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \def\normaldoublequote{"} \catcode`\$=\other \def\normaldollar{$}%$ font-lock fix \catcode`\+=\other \def\normalplus{+} \catcode`\<=\other \def\normalless{<} \catcode`\>=\other \def\normalgreater{>} \catcode`\^=\other \def\normalcaret{^} \catcode`\_=\other \def\normalunderscore{_} \catcode`\|=\other \def\normalverticalbar{|} \catcode`\~=\other \def\normaltilde{~} % This macro is used to make a character print one way in \tt % (where it can probably be output as-is), 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\font=0pt #1\else #2\fi} % Same as above, but check for italic font. Actually this also catches % non-italic slanted fonts since it is impossible to distinguish them from % italic fonts. But since this is only used by $ and it uses \sl anyway % this is not a problem. \def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} % Set catcodes for Texinfo file % Active characters for printing the wanted glyph. % 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\activetilde{{\tt\char126}} \let~ = \activetilde \chardef\hatchar=`\^ \catcode`\^=\active \def\activehat{{\tt \hatchar}} \let^ = \activehat \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \let\realunder=_ \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def\activeless{{\tt \less}}\let< = \activeless \chardef \gtr=`\> \catcode`\>=\active \def\activegtr{{\tt \gtr}}\let> = \activegtr \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix \catcode`\-=\active \let-=\normaldash % used for headline/footline in the output routine, in case the page % breaks in the middle of an @tex block. \def\texinfochars{% \let< = \activeless \let> = \activegtr \let~ = \activetilde \let^ = \activehat \markupsetuplqdefault \markupsetuprqdefault \let\b = \strong \let\i = \smartitalic % in principle, all other definitions in \tex have to be undone too. } % Used sometimes to turn off (effectively) the active characters even after % parsing them. \def\turnoffactive{% \normalturnoffactive \otherbackslash } \catcode`\@=0 % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ \global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work % \realbackslash is an actual character `\' with catcode other, and % \doublebackslash is two of them (for the pdf outlines). {\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} % In Texinfo, backslash is an active character; it prints the backslash % in fixed width font. \catcode`\\=\active % @ for escape char from now on. % Print a typewriter backslash. For math mode, we can't simply use % \backslashcurfont: the story here is that in math mode, the \char % of \backslashcurfont ends up printing the roman \ from the math symbol % font (because \char in math mode uses the \mathcode, and plain.tex % sets \mathcode`\\="026E). Hence we use an explicit \mathchar, % which is the decimal equivalent of "715c (class 7, e.g., use \fam; % ignored family value; char position "5C). We can't use " for the % usual hex value because it has already been made active. @def@ttbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}} @let@backslashchar = @ttbackslash % @backslashchar{} is for user documents. % \rawbackslash defines an active \ to do \backslashcurfont. % \otherbackslash defines an active \ to be a literal `\' character with % catcode other. We switch back and forth between these. @gdef@rawbackslash{@let\=@backslashcurfont} @gdef@otherbackslash{@let\=@realbackslash} % Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of % the literal character `\'. % {@catcode`- = @active @gdef@normalturnoffactive{% @nonasciistringdefs @let-=@normaldash @let"=@normaldoublequote @let$=@normaldollar %$ font-lock fix @let+=@normalplus @let<=@normalless @let>=@normalgreater @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let~=@normaltilde @let\=@ttbackslash @markupsetuplqdefault @markupsetuprqdefault @unsepspaces } } % 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 @fixbackslash turn them back on. @catcode`+=@other @catcode`@_=@other % \enablebackslashhack - allow file to begin `\input texinfo' % % 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. % If the file did not have a `\input texinfo', then it is turned off after % the first line; otherwise the first `\' in the file would cause an error. % This is used on the very last line of this file, texinfo.tex. % We also use @c to call @fixbackslash, in case ends of lines are hidden. { @catcode`@^=7 @catcode`@^^M=13@gdef@enablebackslashhack{% @global@let\ = @eatinput% @catcode`@^^M=13% @def@c{@fixbackslash@c}% @def ^^M{@let^^M@secondlinenl}% @gdef @secondlinenl{@let^^M@thirdlinenl}% @gdef @thirdlinenl{@fixbackslash}% }} {@catcode`@^=7 @catcode`@^^M=13% @gdef@eatinput input texinfo#1^^M{@fixbackslash}} % Emergency active definition of newline, in case an active newline token % appears by mistake. {@catcode`@^=7 @catcode13=13% @gdef@enableemergencynewline{% @gdef^^M{% @par% %@par% }}} @gdef@fixbackslash{% @ifx\@eatinput @let\ = @ttbackslash @fi @catcode13=5 % regular end of line @enableemergencynewline @let@c=@texinfoc % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. @catcode`+=@active @catcode`@_=@active % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. This macro, @fixbackslash, gets % called at the beginning of every Texinfo file. Not opening texinfo.cnf % directly in this file, texinfo.tex, makes it possible to make a format % file for Texinfo. % @openin 1 texinfo.cnf @ifeof 1 @else @input texinfo.cnf @fi @closein 1 } % Say @foo, not \foo, in error messages. @escapechar = `@@ % These (along with & and #) are made active for url-breaking, so need % active definitions as the normal characters. @def@normaldot{.} @def@normalquest{?} @def@normalslash{/} % These look ok in all fonts, so just make them not special. % @hashchar{} gets its own user-level command, because of #line. @catcode`@& = @other @def@normalamp{&} @catcode`@# = @other @def@normalhash{#} @catcode`@% = @other @def@normalpercent{%} @let @hashchar = @normalhash @c Finally, make ` and ' active, so that txicodequoteundirected and @c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we @c don't make ` and ' active, @code will not get them as active chars. @c Do this last of all since we use ` in the previous @catcode assignments. @catcode`@'=@active @catcode`@`=@active @markupsetuplqdefault @markupsetuprqdefault @c Local variables: @c eval: (add-hook 'write-file-hooks 'time-stamp) @c page-delimiter: "^\\\\message\\|emacs-page" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @c time-stamp-end: "}" @c End: @c vim:sw=2: @ignore arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 @end ignore @enablebackslashhack quagga-1.2.4/doc/version.texi000066400000000000000000000001451325323223500161100ustar00rootroot00000000000000@set UPDATED 19 February 2018 @set UPDATED-MONTH February 2018 @set EDITION 1.2.4 @set VERSION 1.2.4 quagga-1.2.4/doc/vtysh.1000066400000000000000000000054511325323223500147740ustar00rootroot00000000000000.TH VTYSH 1 "27 July 2006" "Quagga VTY shell" "Version 0.96.5" .SH NAME vtysh \- a integrated shell for Quagga routing software .SH SYNOPSIS .B vtysh [ .B \-b ] .br .B vtysh [ .B \-E ] [ .B \-d .I daemon ] ] [ .B \-c .I command ] .SH DESCRIPTION .B vtysh is a integrated shell for .B Quagga routing engine. .SH OPTIONS Options available for the .B vtysh command: .IP "\fB\-b, \-\-boot\fP" Execute boot startup configuration. It makes sense only if integrated config file is in use (not default in Quagga). See Info file \fBQuagga\fR for more info. .IP "\fB\-c, \-\-command \fIcommand\fP" Specify command to be executed under batch mode. It behaves like -c option in any other shell - .I command is executed and .B vtysh exits. It's useful for gathering info from Quagga routing software or reconfiguring daemons from inside shell scripts, etc. Note that multiple commands may be executed by using more than one -c option and/or embedding linefeed characters inside the .I command string. .IP "\fB\-d, \-\-daemon \fIdaemon_name\fP" Specify which daemon to connect to. By default, .B vtysh attempts to connect to all Quagga daemons running on the system. With this flag, one can specify a single daemon to connect to instead. For example, specifying '-d ospfd' will connect only to ospfd. This can be particularly useful inside scripts with -c where the command is targeted for a single daemon. .IP "\fB\-e, \-\-execute \fIcommand\fP" Alias for -c. It's here only for compatibility with Zebra routing software and older Quagga versions. This will be removed in future. .IP "\fB\-E, \-\-echo\fP" When the -c option is being used, this flag will cause the standard .B vtysh prompt and command to be echoed prior to displaying the results. This is particularly useful to separate the results when executing multiple commands. .IP "\fB\-h, \-\-help\fP" Display a usage message on standard output and exit. .SH ENVIRONMENT VARIABLES .IP "\fBVTYSH_PAGER\fR" This should be the name of the pager to use. Default is \fBmore\fR. .SH FILES .TP .BI /usr/local/etc/vtysh.conf The default location of the .B vtysh config file. .TP .BI /usr/local/etc/Quagga.conf The default location of the integrated Quagga routing engine config file if integrated config file is in use (not default). .TP .BI ${HOME}/.history_quagga Location of history of commands entered via cli .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8) .SH BUGS .B vtysh eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-1.2.4/doc/vtysh.texi000066400000000000000000000045561325323223500156120ustar00rootroot00000000000000@node VTY shell @chapter VTY shell @command{vtysh} is integrated shell of Quagga 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 two commands. @menu * VTY shell username:: * VTY shell integrated configuration:: @end menu @node VTY shell username @section VTY shell username @deffn {Command} {username @var{username} nopassword} {} 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. vtysh requires read/write permission to the various daemons vty sockets, this can be accomplished through use of unix groups and the --enable-vty-group configure option. @end deffn @node VTY shell integrated configuration @section VTY shell integrated configuration @deffn {Command} {service integrated-vtysh-config} {} Write out integrated Quagga.conf file when 'write file' is issued. This command controls the behaviour of vtysh when it is told to write out the configuration. Per default, vtysh will instruct each daemon to write out their own config files when @command{write file} is issued. However, if @command{service integrated-vtysh-config} is set, when @command{write file} is issued, vtysh will instruct the daemons will write out a Quagga.conf with all daemons' commands integrated into it. Vtysh per default behaves as if @command{write-conf daemon} is set. Note that both may be set at same time if one wishes to have both Quagga.conf and daemon specific files written out. Further, note that the daemons are hard-coded to first look for the integrated Quagga.conf file before looking for their own file. We recommend you do not mix the use of the two types of files. Further, it is better not to use the integrated Quagga.conf file, as any syntax error in it can lead to /all/ of your daemons being unable to start up. Per daemon files are more robust as impact of errors in configuration are limited to the daemon in whose file the error is made. @end deffn quagga-1.2.4/doc/watchquagga.8000066400000000000000000000155001325323223500161160ustar00rootroot00000000000000.\" This file was originally generated by help2man 1.36. .TH WATCHQUAGGA 8 "July 2010" .SH NAME watchquagga \- a program to monitor the status of quagga daemons .SH SYNOPSIS .B watchquagga .RI [ option ...] .IR daemon ... .br .B watchquagga .BR \-h " | " \-v .SH DESCRIPTION .B watchquagga is a watchdog program that monitors the status of supplied quagga .IR daemon s and tries to restart them in case they become unresponsive or shut down. .PP To determine whether a daemon is running, it tries to connect to the daemon's VTY UNIX stream socket, and send echo commands to ensure the daemon responds. When the daemon crashes, EOF is received from the socket, so that watchquagga can react immediately. .PP This program can run in one of the following 5 modes: .TP .B Mode 0: monitor In this mode, the program serves as a monitor and reports status changes. .IP Example usage: watchquagga \-d zebra ospfd bgpd .TP .B Mode 1: global restart In this mode, whenever a daemon hangs or crashes, the given command is used to restart all watched daemons. .IP Example usage: watchquagga \-dz \e .br -R '/sbin/service zebra restart; /sbin/service ospfd restart' \e .br zebra ospfd .TP .B Mode 2: individual daemon restart In this mode, whenever a single daemon hangs or crashes, the given command is used to restart this daemon only. .IP Example usage: watchquagga \-dz \-r '/sbin/service %s restart' \e .br zebra ospfd bgpd .TP .B Mode 3: phased zebra restart In this mode, whenever a single daemon hangs or crashes, the given command is used to restart this daemon only. The only exception is the zebra daemon; in this case, the following steps are taken: (1) all other daemons are stopped, (2) zebra is restarted, and (3) other daemons are started again. .IP Example usage: watchquagga \-adz \-r '/sbin/service %s restart' \e .br \-s '/sbin/service %s start' \e .br \-k '/sbin/service %s stop' zebra ospfd bgpd .TP .B Mode 4: phased global restart for any failure In this mode, whenever a single daemon hangs or crashes, the following steps are taken: (1) all other daemons are stopped, (2) zebra is restarted, and (3) other daemons are started again. .IP Example usage: watchquagga \-Adz \-r '/sbin/service %s restart' \e .br \-s '/sbin/service %s start' \e .br \-k '/sbin/service %s stop' zebra ospfd bgpd .PP Important: It is believed that mode 2 (individual daemon restart) is not safe, and mode 3 (phased zebra restart) may not be safe with certain routing daemons. .PP In order to avoid restarting the daemons in quick succession, you can supply the .B \-m and .B \-M options to set the minimum and maximum delay between the restart commands. The minimum restart delay is recalculated each time a restart is attempted. If the time since the last restart attempt exceeds twice the value of .BR \-M , the restart delay is set to the value of .BR \-m , otherwise the interval is doubled (but capped at the value of .BR \-M ). .SH OPTIONS .TP .BR \-d ", " \-\-daemon Run in daemon mode. When supplied, error messages are sent to Syslog instead of standard output (stdout). .TP .BI \-S " directory" "\fR, \fB\-\-statedir " directory Set the VTY socket .I directory (the default value is "/var/run/quagga"). .TP .BR \-e ", " \-\-no\-echo Do not ping the daemons to test whether they respond. This option is necessary if one or more daemons do not support the echo command. .TP .BI \-l " level" "\fR, \fB\-\-loglevel " level Set the logging .I level (the default value is "6"). The value should range from 0 (LOG_EMERG) to 7 (LOG_DEBUG), but higher number can be supplied if extra debugging messages are required. .TP .BI \-m " number" "\fR, \fB\-\-min\-restart\-interval " number Set the minimum .I number of seconds to wait between invocations of the daemon restart commands (the default value is "60"). .TP .BI \-M " number" "\fR, \fB\-\-max\-restart\-interval " number Set the maximum .I number of seconds to wait between invocations of the daemon restart commands (the default value is "600"). .TP .BI \-i " number" "\fR, \fB\-\-interval " number Set the status polling interval in seconds (the default value is "5"). .TP .BI \-t " number" "\fR, \fB\-\-timeout " number Set the unresponsiveness timeout in seconds (the default value is "10"). .TP .BI \-T " number" "\fR, \fB\-\-restart\-timeout " number Set the restart (kill) timeout in seconds (the default value is "20"). If any background jobs are still running after this period has elapsed, they will be killed. .TP .BI \-r " command" "\fR, \fB\-\-restart " command Supply a Bourne shell .I command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. .IP Note that .B \-r and .B \-R options are not compatible. .TP .BI \-s " command" "\fR, \fB\-\-start\-command " command Supply a Bourne shell .I command to start a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. .TP .BI \-k " command" "\fR, \fB\-\-kill\-command " command Supply a Bourne shell .I command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. .TP .BR \-R ", " \-\-restart\-all When one or more daemons are shut down, try to restart them using the Bourne shell command supplied on the command line. .IP Note that .B \-r and .B \-R options are not compatible. .TP .BR \-z ", " \-\-unresponsive\-restart When a daemon is in an unresponsive state, treat it as being shut down for the restart purposes. .TP .BR \-a ", " \-\-all\-restart When zebra hangs or crashes, restart all daemons taking the following steps: (1) stop all other daemons, (2) restart zebra, and (3) start other daemons again. .IP Note that this option also requires .BR \-r , .BR \-s , and .B \-k options to be specified. .TP .BR \-A ", " \-\-always\-all\-restart When any daemon (i.e., not just zebra) hangs or crashes, restart all daemons taking the following steps: (1) stop all other daemons, (2) restart zebra, and (3) start other daemons again. .IP Note that this option also requires .BR \-r , .BR \-s , and .B \-k options to be specified. .TP .BI \-p " filename" "\fR, \fB\-\-pid\-file " filename Set the process identifier .I filename (the default value is "/var/run/quagga/watchquagga.pid"). .TP .BI \-b " string" "\fR, \fB\-\-blank\-string " string When the supplied .I string is found in any of the command line option arguments (i.e., .BR \-r , .BR \-s , .BR \-k , or .BR \-R ), replace it with a space. .IP This is an ugly hack to circumvent problems with passing the command line arguments containing embedded spaces. .TP .BR \-v ", " \-\-version Display the version information and exit. .TP .BR \-h ", " \-\-help Display the usage information and exit. .SH SEE ALSO .BR zebra (8), .BR bgpd (8), .BR isisd (8), .BR ospfd (8), .BR ospf6d (8), .BR ripd (8), .BR ripngd (8) .PP See the project homepage at . .SH AUTHORS Copyright 2004 Andrew J. Schorr quagga-1.2.4/doc/zebra.8000066400000000000000000000067371325323223500147410ustar00rootroot00000000000000.TH ZEBRA 8 "25 November 2004" "Zebra daemon" "Version 0.97.3" .SH NAME zebra \- a routing manager for use with associated Quagga components. .SH SYNOPSIS .B zebra [ .B \-bdhklrv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B zebra is a routing manager that implements the .B zebra route engine. .B zebra supports RIPv1, RIPv2, RIPng, OSPF, OSPF6, IS-IS, BGP4+, and BGP4-. .SH OPTIONS Options available for the .B zebra command: .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\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\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 identifier 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\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the zebra VTY will listen on. This defaults to 2601, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the zebra VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBzebra\fR. .TP \fB\-s\fR, \fB\-\-nl-bufsize \fR\fInetlink-buffer-size\fR Set netlink receive buffer size. There are cases where zebra daemon can't handle flood of netlink messages from kernel. If you ever see "recvmsg overrun" messages in zebra log, you are in trouble. Solution is to increase receive buffer of netlink socket. Note that kernel < 2.6.14 doesn't allow increasing it over the maximum value defined in \fI/proc/sys/net/core/rmem_max\fR. If you want to do it, you have to increase maximum before starting zebra. Note that this affects Linux only. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .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 to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\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. \fBzebra\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR nhrpd (8), .BR vtysh (1) .SH BUGS .B zebra eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-1.2.4/fpm/000077500000000000000000000000001325323223500135455ustar00rootroot00000000000000quagga-1.2.4/fpm/Makefile.am000066400000000000000000000011031325323223500155740ustar00rootroot00000000000000include ../common.am AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES) PROTOBUF_INCLUDES=-I$(top_srcdir) PROTOBUF_PACKAGE = fpm lib_LTLIBRARIES = libfpm_pb.la libfpm_pb_la_LDFLAGS = -version-info 0:0:0 if HAVE_PROTOBUF protobuf_srcs = protobuf_srcs_nodist = \ fpm.pb-c.c endif libfpm_pb_la_SOURCES = \ fpm.h \ fpm_pb.h \ fpm_pb.c \ $(protobuf_srcs) nodist_libfpm_pb_la_SOURCES = $(protobuf_srcs_nodist) CLEANFILES = $(Q_CLEANFILES) BUILT_SOURCES = $(Q_PROTOBUF_SRCS) EXTRA_DIST = fpm.proto quagga-1.2.4/fpm/Makefile.in000066400000000000000000000567341325323223500156310ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ # # Automake fragment intended to be shared by Makefile.am files in the # tree. # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = fpm ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libfpm_pb_la_LIBADD = am__objects_1 = am_libfpm_pb_la_OBJECTS = fpm_pb.lo $(am__objects_1) @HAVE_PROTOBUF_TRUE@am__objects_2 = fpm.pb-c.lo nodist_libfpm_pb_la_OBJECTS = $(am__objects_2) libfpm_pb_la_OBJECTS = $(am_libfpm_pb_la_OBJECTS) \ $(nodist_libfpm_pb_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libfpm_pb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libfpm_pb_la_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libfpm_pb_la_SOURCES) $(nodist_libfpm_pb_la_SOURCES) DIST_SOURCES = $(libfpm_pb_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/../common.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # Uncomment to use an non-system version of libprotobuf-c. # # Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src # Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_INCLUDES = @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_LDOPTS = -lprotobuf-c @HAVE_PROTOBUF_TRUE@Q_PROTOC = protoc @HAVE_PROTOBUF_TRUE@Q_PROTOC_C = protoc-c @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_CFILES = $(filter %.pb-c.c,$(SOURCES)) @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_SRCS = $(Q_PROTOBUF_CFILES) $(Q_PROTOBUF_HFILES) # # Information about how to link to various libraries. # @HAVE_PROTOBUF_TRUE@Q_QUAGGA_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libquagga_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS) @HAVE_PROTOBUF_TRUE@Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfpm_pb.la $(Q_QUAGGA_PB_CLIENT_LDOPTS) Q_CLEANFILES = $(Q_PROTOBUF_SRCS) Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS) AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES) PROTOBUF_INCLUDES = -I$(top_srcdir) PROTOBUF_PACKAGE = fpm lib_LTLIBRARIES = libfpm_pb.la libfpm_pb_la_LDFLAGS = -version-info 0:0:0 @HAVE_PROTOBUF_TRUE@protobuf_srcs = @HAVE_PROTOBUF_TRUE@protobuf_srcs_nodist = \ @HAVE_PROTOBUF_TRUE@ fpm.pb-c.c libfpm_pb_la_SOURCES = \ fpm.h \ fpm_pb.h \ fpm_pb.c \ $(protobuf_srcs) nodist_libfpm_pb_la_SOURCES = $(protobuf_srcs_nodist) CLEANFILES = $(Q_CLEANFILES) BUILT_SOURCES = $(Q_PROTOBUF_SRCS) EXTRA_DIST = fpm.proto all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../common.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu fpm/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu fpm/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(srcdir)/../common.am $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libfpm_pb.la: $(libfpm_pb_la_OBJECTS) $(libfpm_pb_la_DEPENDENCIES) $(EXTRA_libfpm_pb_la_DEPENDENCIES) $(AM_V_CCLD)$(libfpm_pb_la_LINK) -rpath $(libdir) $(libfpm_pb_la_OBJECTS) $(libfpm_pb_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fpm.pb-c.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fpm_pb.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES .PRECIOUS: Makefile # Rules @HAVE_PROTOBUF_TRUE@%.pb.h: %.proto @HAVE_PROTOBUF_TRUE@ $(Q_PROTOC) $(PROTOBUF_INCLUDES) --cpp_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ @HAVE_PROTOBUF_TRUE@%.pb-c.c %.pb-c.h: %.proto @HAVE_PROTOBUF_TRUE@ $(Q_PROTOC_C) $(PROTOBUF_INCLUDES) --c_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ # 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: quagga-1.2.4/fpm/fpm.h000066400000000000000000000173471325323223500145140ustar00rootroot00000000000000/* * Public definitions pertaining to the Forwarding Plane Manager component. * * Permission is granted to use, copy, modify and/or distribute this * software under either one of the licenses below. * * Note that if you use other files from the Quagga tree directly or * indirectly, then the licenses in those files still apply. * * Please retain both licenses below when modifying this code in the * Quagga tree. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") */ /* * License Option 1: GPL * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * License Option 2: ISC License * * Permission to use, copy, modify, and/or distribute this software * for any purpose with or without fee is hereby granted, provided * that the above copyright notice and this permission notice appear * in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _FPM_H #define _FPM_H /* * The Forwarding Plane Manager (FPM) is an optional component that * may be used in scenarios where the router has a forwarding path * that is distinct from the kernel, commonly a hardware-based fast * path. It is responsible for programming forwarding information * (such as routes and nexthops) in the fast path. * * In Quagga, the Routing Information Base is maintained in the * 'zebra' infrastructure daemon. Routing protocols communicate their * best routes to zebra, and zebra computes the best route across * protocols for each prefix. This latter information comprises the * bulk of the Forwarding Information Base. * * This header file defines a point-to-point interface using which * zebra can update the FPM about changes in routes. The communication * takes place over a stream socket. The FPM listens on a well-known * TCP port, and zebra initiates the connection. * * All messages sent over the connection start with a short FPM * header, fpm_msg_hdr_t. In the case of route add/delete messages, * the header is followed by a netlink message. Zebra should send a * complete copy of the forwarding table(s) to the FPM, including * routes that it may have picked up from the kernel. * * The FPM interface uses replace semantics. That is, if a 'route add' * message for a prefix is followed by another 'route add' message, the * information in the second message is complete by itself, and replaces * the information sent in the first message. * * If the connection to the FPM goes down for some reason, the client * (zebra) should send the FPM a complete copy of the forwarding * table(s) when it reconnects. */ /* * Local host as a default server for fpm connection */ #define FPM_DEFAULT_IP (htonl (INADDR_LOOPBACK)) /* * default port for fpm connections */ #define FPM_DEFAULT_PORT 2620 /* * Largest message that can be sent to or received from the FPM. */ #define FPM_MAX_MSG_LEN 4096 #ifdef __SUNPRO_C #pragma pack(1) #endif /* * Header that precedes each fpm message to/from the FPM. */ typedef struct fpm_msg_hdr_t_ { /* * Protocol version. */ uint8_t version; /* * Type of message, see below. */ uint8_t msg_type; /* * Length of entire message, including the header, in network byte * order. */ uint16_t msg_len; } __attribute__ ((packed)) fpm_msg_hdr_t; #ifdef __SUNPRO_C #pragma pack() #endif /* * The current version of the FPM protocol is 1. */ #define FPM_PROTO_VERSION 1 typedef enum fpm_msg_type_e_ { FPM_MSG_TYPE_NONE = 0, /* * Indicates that the payload is a completely formed netlink * message. * * XXX Netlink cares about the alignment of messages. When any * FPM_MSG_TYPE_NETLINK messages are sent over a channel, then all * messages should be sized such that netlink alignment is * maintained. */ FPM_MSG_TYPE_NETLINK = 1, FPM_MSG_TYPE_PROTOBUF = 2, } fpm_msg_type_e; /* * The FPM message header is aligned to the same boundary as netlink * messages (4). This means that a netlink message does not need * padding when encapsulated in an FPM message. */ #define FPM_MSG_ALIGNTO 4 /* * fpm_msg_align * * Round up the given length to the desired alignment. * * **NB**: Alignment is required only when netlink messages are used. */ static inline size_t fpm_msg_align (size_t len) { return (len + FPM_MSG_ALIGNTO - 1) & ~(FPM_MSG_ALIGNTO - 1); } /* * The (rounded up) size of the FPM message header. This ensures that * the message payload always starts at an aligned address. */ #define FPM_MSG_HDR_LEN (sizeof (fpm_msg_hdr_t)) #ifndef COMPILE_ASSERT #define COMPILE_ASSERT(x) extern int __dummy[2 * !!(x) - 1] #endif COMPILE_ASSERT(FPM_MSG_ALIGNTO == FPM_MSG_HDR_LEN); /* * fpm_data_len_to_msg_len * * The length value that should be placed in the msg_len field of the * header for a *payload* of size 'data_len'. */ static inline size_t fpm_data_len_to_msg_len (size_t data_len) { return data_len + FPM_MSG_HDR_LEN; } /* * fpm_msg_data * * Pointer to the payload of the given fpm header. */ static inline void * fpm_msg_data (fpm_msg_hdr_t *hdr) { return ((char*) hdr) + FPM_MSG_HDR_LEN; } /* * fpm_msg_len */ static inline size_t fpm_msg_len (const fpm_msg_hdr_t *hdr) { return ntohs (hdr->msg_len); } /* * fpm_msg_data_len */ static inline size_t fpm_msg_data_len (const fpm_msg_hdr_t *hdr) { return (fpm_msg_len (hdr) - FPM_MSG_HDR_LEN); } /* * fpm_msg_next * * Move to the next message in a buffer. */ static inline fpm_msg_hdr_t * fpm_msg_next (fpm_msg_hdr_t *hdr, size_t *len) { size_t msg_len; msg_len = fpm_msg_len (hdr); if (len) { if (*len < msg_len) { assert(0); return NULL; } *len -= msg_len; } return (fpm_msg_hdr_t *) (((char*) hdr) + msg_len); } /* * fpm_msg_hdr_ok * * Returns TRUE if a message header looks well-formed. */ static inline int fpm_msg_hdr_ok (const fpm_msg_hdr_t *hdr) { size_t msg_len; if (hdr->msg_type == FPM_MSG_TYPE_NONE) return 0; msg_len = fpm_msg_len (hdr); if (msg_len < FPM_MSG_HDR_LEN || msg_len > FPM_MAX_MSG_LEN) return 0; /* * Netlink messages must be aligned properly. */ if (hdr->msg_type == FPM_MSG_TYPE_NETLINK && fpm_msg_align (msg_len) != msg_len) return 0; return 1; } /* * fpm_msg_ok * * Returns TRUE if a message looks well-formed. * * @param len The length in bytes from 'hdr' to the end of the buffer. */ static inline int fpm_msg_ok (const fpm_msg_hdr_t *hdr, size_t len) { if (len < FPM_MSG_HDR_LEN) return 0; if (!fpm_msg_hdr_ok (hdr)) return 0; if (fpm_msg_len (hdr) > len) return 0; return 1; } // tcp maximum range #define TCP_MAX_PORT 65535 // tcp minimum range #define TCP_MIN_PORT 1 #endif /* _FPM_H */ quagga-1.2.4/fpm/fpm.proto000066400000000000000000000041721325323223500154200ustar00rootroot00000000000000// // fpm.proto // // @copyright Copyright (C) 2016 Sproute Networks, Inc. // // @author Avneesh Sachdev // // Permission to use, copy, modify, and/or distribute this software // for any purpose with or without fee is hereby granted, provided // that the above copyright notice and this permission notice appear // in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR // CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS // OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, // NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // // Protobuf definitions pertaining to the Forwarding Plane Manager component. // package fpm; import "qpb/qpb.proto"; // // A Nexthop for a route. It indicates how packets to a given prefix // should be forwarded (for instance, send them out of a specified // interface to a specified address). // message Nexthop { optional qpb.IfIdentifier if_id = 2; optional qpb.L3Address address = 3; } message RouteKey { optional qpb.L3Prefix prefix = 1; } message DeleteRoute { required uint32 vrf_id = 1; required qpb.AddressFamily address_family = 2; required qpb.SubAddressFamily sub_address_family = 3; required RouteKey key = 4; } enum RouteType { UNKNOWN = 0; NORMAL = 1; UNREACHABLE = 2; BLACKHOLE = 3; } message AddRoute { required uint32 vrf_id = 1; required qpb.AddressFamily address_family = 2; required qpb.SubAddressFamily sub_address_family = 3; required RouteKey key = 4; optional RouteType route_type = 5; required qpb.Protocol protocol = 6; required int32 metric = 8; repeated Nexthop nexthops = 9; } // // Any message from the FPM. // message Message { enum Type { UNKNOWN_MSG = 0; ADD_ROUTE = 1; DELETE_ROUTE = 2; }; optional Type type = 1; optional AddRoute add_route = 2; optional DeleteRoute delete_route = 3; } quagga-1.2.4/fpm/fpm_pb.c000066400000000000000000000016301325323223500151540ustar00rootroot00000000000000/* * fpm_pb.c * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Main file for the fpm_pb library. */ quagga-1.2.4/fpm/fpm_pb.h000066400000000000000000000027561325323223500151730ustar00rootroot00000000000000/* * fpm_pb.h * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Public header file for fpm protobuf definitions. */ #ifndef _FPM_PB_H #define _FPM_PB_H #include "route_types.h" #include "qpb/qpb.h" #include "fpm/fpm.pb-c.h" /* * fpm__route_key__create */ #define fpm_route_key_create fpm__route_key__create static inline Fpm__RouteKey * fpm__route_key__create (qpb_allocator_t *allocator, struct prefix *prefix) { Fpm__RouteKey *key; key = QPB_ALLOC (allocator, typeof (*key)); if (!key) { return NULL; } fpm__route_key__init (key); key->prefix = qpb__l3_prefix__create (allocator, prefix); if (!key->prefix) { return NULL; } return key; } #endif quagga-1.2.4/install-sh000077500000000000000000000345231325323223500147760ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2013-12-25.23; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # 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. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # 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 $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: quagga-1.2.4/isisd/000077500000000000000000000000001325323223500140765ustar00rootroot00000000000000quagga-1.2.4/isisd/AUTHORS000066400000000000000000000003041325323223500151430ustar00rootroot00000000000000Sampo Saaristo Ofer Wald Hannes Gredler Subbaiah Venkata Olivier Dugeon quagga-1.2.4/isisd/Makefile.am000066400000000000000000000023621325323223500161350ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \ @ISIS_TOPOLOGY_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libisis.a sbin_PROGRAMS = isisd SUBDIRS = topology libisis_a_SOURCES = \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \ isis_vty.c noinst_HEADERS = \ isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \ isis_route.h isis_routemap.h isis_te.h \ include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h isisd_SOURCES = \ isis_main.c $(libisis_a_SOURCES) \ isis_bpf.c isis_dlpi.c isis_pfpacket.c isisd_LDADD = @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = isisd.conf.sample quagga-1.2.4/isisd/Makefile.in000066400000000000000000000764331325323223500161600ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = isisd$(EXEEXT) subdir = isisd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libisis_a_AR = $(AR) $(ARFLAGS) libisis_a_LIBADD = am_libisis_a_OBJECTS = isis_adjacency.$(OBJEXT) isis_lsp.$(OBJEXT) \ dict.$(OBJEXT) isis_circuit.$(OBJEXT) isis_pdu.$(OBJEXT) \ isis_tlv.$(OBJEXT) isisd.$(OBJEXT) isis_misc.$(OBJEXT) \ isis_zebra.$(OBJEXT) isis_dr.$(OBJEXT) isis_flags.$(OBJEXT) \ isis_dynhn.$(OBJEXT) iso_checksum.$(OBJEXT) isis_csm.$(OBJEXT) \ isis_events.$(OBJEXT) isis_spf.$(OBJEXT) isis_redist.$(OBJEXT) \ isis_route.$(OBJEXT) isis_routemap.$(OBJEXT) isis_te.$(OBJEXT) \ isis_vty.$(OBJEXT) libisis_a_OBJECTS = $(am_libisis_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = isis_adjacency.$(OBJEXT) isis_lsp.$(OBJEXT) \ dict.$(OBJEXT) isis_circuit.$(OBJEXT) isis_pdu.$(OBJEXT) \ isis_tlv.$(OBJEXT) isisd.$(OBJEXT) isis_misc.$(OBJEXT) \ isis_zebra.$(OBJEXT) isis_dr.$(OBJEXT) isis_flags.$(OBJEXT) \ isis_dynhn.$(OBJEXT) iso_checksum.$(OBJEXT) isis_csm.$(OBJEXT) \ isis_events.$(OBJEXT) isis_spf.$(OBJEXT) isis_redist.$(OBJEXT) \ isis_route.$(OBJEXT) isis_routemap.$(OBJEXT) isis_te.$(OBJEXT) \ isis_vty.$(OBJEXT) am_isisd_OBJECTS = isis_main.$(OBJEXT) $(am__objects_1) \ isis_bpf.$(OBJEXT) isis_dlpi.$(OBJEXT) isis_pfpacket.$(OBJEXT) isisd_OBJECTS = $(am_isisd_OBJECTS) isisd_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES) DIST_SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp AUTHORS \ README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \ @ISIS_TOPOLOGY_INCLUDES@ INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libisis.a SUBDIRS = topology libisis_a_SOURCES = \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \ isis_vty.c noinst_HEADERS = \ isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \ isis_route.h isis_routemap.h isis_te.h \ include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h isisd_SOURCES = \ isis_main.c $(libisis_a_SOURCES) \ isis_bpf.c isis_dlpi.c isis_pfpacket.c isisd_LDADD = @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = isisd.conf.sample all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu isisd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu isisd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libisis.a: $(libisis_a_OBJECTS) $(libisis_a_DEPENDENCIES) $(EXTRA_libisis_a_DEPENDENCIES) $(AM_V_at)-rm -f libisis.a $(AM_V_AR)$(libisis_a_AR) libisis.a $(libisis_a_OBJECTS) $(libisis_a_LIBADD) $(AM_V_at)$(RANLIB) libisis.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list isisd$(EXEEXT): $(isisd_OBJECTS) $(isisd_DEPENDENCIES) $(EXTRA_isisd_DEPENDENCIES) @rm -f isisd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(isisd_OBJECTS) $(isisd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_adjacency.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_bpf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_circuit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_csm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_dlpi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_dr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_dynhn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_events.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_flags.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_lsp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_misc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_pdu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_pfpacket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_redist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_route.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_routemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_spf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_te.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_tlv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_vty.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isisd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iso_checksum.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) # 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. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 clean-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dist_examplesDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/isisd/README000066400000000000000000000000621325323223500147540ustar00rootroot00000000000000Constraints o Maximum number of interfaces 255 quagga-1.2.4/isisd/dict.c000066400000000000000000001047321325323223500151740ustar00rootroot00000000000000/* * Dictionary Abstract Data Type * Copyright (C) 1997 Kaz Kylheku * * Free Software License: * * All rights are reserved by the author, with the following exceptions: * Permission is granted to freely reproduce and distribute this software, * possibly in exchange for a fee, provided that this copyright notice appears * intact. Permission is also granted to adapt this software to produce * derivative works, as long as the modified versions carry this copyright * notice and additional notices stating that the work has been modified. * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. */ #include "zebra.h" #include "zassert.h" #include "memory.h" #include "dict.h" /* * These macros provide short convenient names for structure members, * which are embellished with dict_ prefixes so that they are * properly confined to the documented namespace. It's legal for a * program which uses dict to define, for instance, a macro called ``parent''. * Such a macro would interfere with the dnode_t struct definition. * In general, highly portable and reusable C modules which expose their * structures need to confine structure member names to well-defined spaces. * The resulting identifiers aren't necessarily convenient to use, nor * readable, in the implementation, however! */ #define left dict_left #define right dict_right #define parent dict_parent #define color dict_color #define key dict_key #define data dict_data #define nilnode dict_nilnode #define nodecount dict_nodecount #define maxcount dict_maxcount #define compare dict_compare #define allocnode dict_allocnode #define freenode dict_freenode #define context dict_context #define dupes dict_dupes #define dictptr dict_dictptr #define dict_root(D) ((D)->nilnode.left) #define dict_nil(D) (&(D)->nilnode) #define DICT_DEPTH_MAX 64 static dnode_t *dnode_alloc(void *context); static void dnode_free(dnode_t *node, void *context); /* * Perform a ``left rotation'' adjustment on the tree. The given node P and * its right child C are rearranged so that the P instead becomes the left * child of C. The left subtree of C is inherited as the new right subtree * for P. The ordering of the keys within the tree is thus preserved. */ static void rotate_left(dnode_t *upper) { dnode_t *lower, *lowleft, *upparent; lower = upper->right; upper->right = lowleft = lower->left; lowleft->parent = upper; lower->parent = upparent = upper->parent; /* don't need to check for root node here because root->parent is the sentinel nil node, and root->parent->left points back to root */ if (upper == upparent->left) { upparent->left = lower; } else { assert (upper == upparent->right); upparent->right = lower; } lower->left = upper; upper->parent = lower; } /* * This operation is the ``mirror'' image of rotate_left. It is * the same procedure, but with left and right interchanged. */ static void rotate_right(dnode_t *upper) { dnode_t *lower, *lowright, *upparent; lower = upper->left; upper->left = lowright = lower->right; lowright->parent = upper; lower->parent = upparent = upper->parent; if (upper == upparent->right) { upparent->right = lower; } else { assert (upper == upparent->left); upparent->left = lower; } lower->right = upper; upper->parent = lower; } /* * Do a postorder traversal of the tree rooted at the specified * node and free everything under it. Used by dict_free(). */ static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) { if (node == nil) return; free_nodes(dict, node->left, nil); free_nodes(dict, node->right, nil); dict->freenode(node, dict->context); } /* * This procedure performs a verification that the given subtree is a binary * search tree. It performs an inorder traversal of the tree using the * dict_next() successor function, verifying that the key of each node is * strictly lower than that of its successor, if duplicates are not allowed, * or lower or equal if duplicates are allowed. This function is used for * debugging purposes. */ static int verify_bintree(dict_t *dict) { dnode_t *first, *next; first = dict_first(dict); if (dict->dupes) { while (first && (next = dict_next(dict, first))) { if (dict->compare(first->key, next->key) > 0) return 0; first = next; } } else { while (first && (next = dict_next(dict, first))) { if (dict->compare(first->key, next->key) >= 0) return 0; first = next; } } return 1; } /* * This function recursively verifies that the given binary subtree satisfies * three of the red black properties. It checks that every red node has only * black children. It makes sure that each node is either red or black. And it * checks that every path has the same count of black nodes from root to leaf. * It returns the blackheight of the given subtree; this allows blackheights to * be computed recursively and compared for left and right siblings for * mismatches. It does not check for every nil node being black, because there * is only one sentinel nil node. The return value of this function is the * black height of the subtree rooted at the node ``root'', or zero if the * subtree is not red-black. */ static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) { unsigned height_left, height_right; if (root != nil) { height_left = verify_redblack(nil, root->left); height_right = verify_redblack(nil, root->right); if (height_left == 0 || height_right == 0) return 0; if (height_left != height_right) return 0; if (root->color == dnode_red) { if (root->left->color != dnode_black) return 0; if (root->right->color != dnode_black) return 0; return height_left; } if (root->color != dnode_black) return 0; return height_left + 1; } return 1; } /* * Compute the actual count of nodes by traversing the tree and * return it. This could be compared against the stored count to * detect a mismatch. */ static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) { if (root == nil) return 0; else return 1 + verify_node_count(nil, root->left) + verify_node_count(nil, root->right); } /* * Verify that the tree contains the given node. This is done by * traversing all of the nodes and comparing their pointers to the * given pointer. Returns 1 if the node is found, otherwise * returns zero. It is intended for debugging purposes. */ static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) { if (root != nil) { return root == node || verify_dict_has_node(nil, root->left, node) || verify_dict_has_node(nil, root->right, node); } return 0; } /* * Dynamically allocate and initialize a dictionary object. */ dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) { dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t)); if (new) { new->compare = comp; new->allocnode = dnode_alloc; new->freenode = dnode_free; new->context = NULL; new->nodecount = 0; new->maxcount = maxcount; new->nilnode.left = &new->nilnode; new->nilnode.right = &new->nilnode; new->nilnode.parent = &new->nilnode; new->nilnode.color = dnode_black; new->dupes = 0; } return new; } /* * Select a different set of node allocator routines. */ void dict_set_allocator(dict_t *dict, dnode_alloc_t al, dnode_free_t fr, void *context) { assert (dict_count(dict) == 0); assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); dict->allocnode = al ? al : dnode_alloc; dict->freenode = fr ? fr : dnode_free; dict->context = context; } /* * Free a dynamically allocated dictionary object. Removing the nodes * from the tree before deleting it is required. */ void dict_destroy(dict_t *dict) { assert (dict_isempty(dict)); XFREE(MTYPE_ISIS_DICT, dict); } /* * Free all the nodes in the dictionary by using the dictionary's * installed free routine. The dictionary is emptied. */ void dict_free_nodes(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict); free_nodes(dict, root, nil); dict->nodecount = 0; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; } /* * Obsolescent function, equivalent to dict_free_nodes */ void dict_free(dict_t *dict) { dict_free_nodes(dict); } /* * Initialize a user-supplied dictionary object. */ dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) { dict->compare = comp; dict->allocnode = dnode_alloc; dict->freenode = dnode_free; dict->context = NULL; dict->nodecount = 0; dict->maxcount = maxcount; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; dict->nilnode.color = dnode_black; dict->dupes = 0; return dict; } /* * Initialize a dictionary in the likeness of another dictionary */ void dict_init_like(dict_t *dict, const dict_t *template) { dict->compare = template->compare; dict->allocnode = template->allocnode; dict->freenode = template->freenode; dict->context = template->context; dict->nodecount = 0; dict->maxcount = template->maxcount; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; dict->nilnode.color = dnode_black; dict->dupes = template->dupes; assert (dict_similar(dict, template)); } /* * Remove all nodes from the dictionary (without freeing them in any way). */ static void dict_clear(dict_t *dict) { dict->nodecount = 0; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; assert (dict->nilnode.color == dnode_black); } /* * Verify the integrity of the dictionary structure. This is provided for * debugging purposes, and should be placed in assert statements. Just because * this function succeeds doesn't mean that the tree is not corrupt. Certain * corruptions in the tree may simply cause undefined behavior. */ int dict_verify(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict); /* check that the sentinel node and root node are black */ if (root->color != dnode_black) return 0; if (nil->color != dnode_black) return 0; if (nil->right != nil) return 0; /* nil->left is the root node; check that its parent pointer is nil */ if (nil->left->parent != nil) return 0; /* perform a weak test that the tree is a binary search tree */ if (!verify_bintree(dict)) return 0; /* verify that the tree is a red-black tree */ if (!verify_redblack(nil, root)) return 0; if (verify_node_count(nil, root) != dict_count(dict)) return 0; return 1; } /* * Determine whether two dictionaries are similar: have the same comparison and * allocator functions, and same status as to whether duplicates are allowed. */ int dict_similar(const dict_t *left, const dict_t *right) { if (left->compare != right->compare) return 0; if (left->allocnode != right->allocnode) return 0; if (left->freenode != right->freenode) return 0; if (left->context != right->context) return 0; if (left->dupes != right->dupes) return 0; return 1; } /* * Locate a node in the dictionary having the given key. * If the node is not found, a null a pointer is returned (rather than * a pointer that dictionary's nil sentinel node), otherwise a pointer to the * located node is returned. */ dnode_t *dict_lookup(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *saved; int result; /* simple binary search adapted for trees that contain duplicate keys */ while (root != nil) { result = dict->compare(key, root->key); if (result < 0) root = root->left; else if (result > 0) root = root->right; else { if (!dict->dupes) { /* no duplicates, return match */ return root; } else { /* could be dupes, find leftmost one */ do { saved = root; root = root->left; while (root != nil && dict->compare(key, root->key)) root = root->right; } while (root != nil); return saved; } } } return NULL; } /* * Look for the node corresponding to the lowest key that is equal to or * greater than the given key. If there is no such node, return null. */ dnode_t *dict_lower_bound(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *tentative = 0; while (root != nil) { int result = dict->compare(key, root->key); if (result > 0) { root = root->right; } else if (result < 0) { tentative = root; root = root->left; } else { if (!dict->dupes) { return root; } else { tentative = root; root = root->left; } } } return tentative; } /* * Look for the node corresponding to the greatest key that is equal to or * lower than the given key. If there is no such node, return null. */ dnode_t *dict_upper_bound(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *tentative = 0; while (root != nil) { int result = dict->compare(key, root->key); if (result < 0) { root = root->left; } else if (result > 0) { tentative = root; root = root->right; } else { if (!dict->dupes) { return root; } else { tentative = root; root = root->right; } } } return tentative; } /* * Insert a node into the dictionary. The node should have been * initialized with a data field. All other fields are ignored. * The behavior is undefined if the user attempts to insert into * a dictionary that is already full (for which the dict_isfull() * function returns true). */ void dict_insert(dict_t *dict, dnode_t *node, const void *key) { dnode_t *where = dict_root(dict), *nil = dict_nil(dict); dnode_t *parent = nil, *uncle, *grandpa; int result = -1; node->key = key; assert (!dict_isfull(dict)); assert (!dict_contains(dict, node)); assert (!dnode_is_in_a_dict(node)); /* basic binary tree insert */ while (where != nil) { parent = where; result = dict->compare(key, where->key); /* trap attempts at duplicate key insertion unless it's explicitly allowed */ assert (dict->dupes || result != 0); if (result < 0) where = where->left; else where = where->right; } assert (where == nil); if (result < 0) parent->left = node; else parent->right = node; node->parent = parent; node->left = nil; node->right = nil; dict->nodecount++; /* red black adjustments */ node->color = dnode_red; while (parent->color == dnode_red) { grandpa = parent->parent; if (parent == grandpa->left) { uncle = grandpa->right; if (uncle->color == dnode_red) { /* red parent, red uncle */ parent->color = dnode_black; uncle->color = dnode_black; grandpa->color = dnode_red; node = grandpa; parent = grandpa->parent; } else { /* red parent, black uncle */ if (node == parent->right) { rotate_left(parent); parent = node; assert (grandpa == parent->parent); /* rotation between parent and child preserves grandpa */ } parent->color = dnode_black; grandpa->color = dnode_red; rotate_right(grandpa); break; } } else { /* symmetric cases: parent == parent->parent->right */ uncle = grandpa->left; if (uncle->color == dnode_red) { parent->color = dnode_black; uncle->color = dnode_black; grandpa->color = dnode_red; node = grandpa; parent = grandpa->parent; } else { if (node == parent->left) { rotate_right(parent); parent = node; assert (grandpa == parent->parent); } parent->color = dnode_black; grandpa->color = dnode_red; rotate_left(grandpa); break; } } } dict_root(dict)->color = dnode_black; assert (dict_verify(dict)); } /* * Delete the given node from the dictionary. If the given node does not belong * to the given dictionary, undefined behavior results. A pointer to the * deleted node is returned. */ dnode_t *dict_delete(dict_t *dict, dnode_t *delete) { dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; /* basic deletion */ assert (!dict_isempty(dict)); assert (dict_contains(dict, delete)); /* * If the node being deleted has two children, then we replace it with its * successor (i.e. the leftmost node in the right subtree.) By doing this, * we avoid the traditional algorithm under which the successor's key and * value *only* move to the deleted node and the successor is spliced out * from the tree. We cannot use this approach because the user may hold * pointers to the successor, or nodes may be inextricably tied to some * other structures by way of embedding, etc. So we must splice out the * node we are given, not some other node, and must not move contents from * one node to another behind the user's back. */ if (delete->left != nil && delete->right != nil) { dnode_t *next = dict_next(dict, delete); dnode_t *nextparent = next->parent; dnode_color_t nextcolor = next->color; assert (next != nil); assert (next->parent != nil); assert (next->left == nil); /* * First, splice out the successor from the tree completely, by * moving up its right child into its place. */ child = next->right; child->parent = nextparent; if (nextparent->left == next) { nextparent->left = child; } else { assert (nextparent->right == next); nextparent->right = child; } /* * Now that the successor has been extricated from the tree, install it * in place of the node that we want deleted. */ next->parent = delparent; next->left = delete->left; next->right = delete->right; next->left->parent = next; next->right->parent = next; next->color = delete->color; delete->color = nextcolor; if (delparent->left == delete) { delparent->left = next; } else { assert (delparent->right == delete); delparent->right = next; } } else { assert (delete != nil); assert (delete->left == nil || delete->right == nil); child = (delete->left != nil) ? delete->left : delete->right; child->parent = delparent = delete->parent; if (delete == delparent->left) { delparent->left = child; } else { assert (delete == delparent->right); delparent->right = child; } } delete->parent = NULL; delete->right = NULL; delete->left = NULL; dict->nodecount--; assert (verify_bintree(dict)); /* red-black adjustments */ if (delete->color == dnode_black) { dnode_t *parent, *sister; dict_root(dict)->color = dnode_red; while (child->color == dnode_black) { parent = child->parent; if (child == parent->left) { sister = parent->right; assert (sister != nil); if (sister->color == dnode_red) { sister->color = dnode_black; parent->color = dnode_red; rotate_left(parent); sister = parent->right; assert (sister != nil); } if (sister->left->color == dnode_black && sister->right->color == dnode_black) { sister->color = dnode_red; child = parent; } else { if (sister->right->color == dnode_black) { assert (sister->left->color == dnode_red); sister->left->color = dnode_black; sister->color = dnode_red; rotate_right(sister); sister = parent->right; assert (sister != nil); } sister->color = parent->color; sister->right->color = dnode_black; parent->color = dnode_black; rotate_left(parent); break; } } else { /* symmetric case: child == child->parent->right */ assert (child == parent->right); sister = parent->left; assert (sister != nil); if (sister->color == dnode_red) { sister->color = dnode_black; parent->color = dnode_red; rotate_right(parent); sister = parent->left; assert (sister != nil); } if (sister->right->color == dnode_black && sister->left->color == dnode_black) { sister->color = dnode_red; child = parent; } else { if (sister->left->color == dnode_black) { assert (sister->right->color == dnode_red); sister->right->color = dnode_black; sister->color = dnode_red; rotate_left(sister); sister = parent->left; assert (sister != nil); } sister->color = parent->color; sister->left->color = dnode_black; parent->color = dnode_black; rotate_right(parent); break; } } } child->color = dnode_black; dict_root(dict)->color = dnode_black; } assert (dict_verify(dict)); return delete; } /* * Allocate a node using the dictionary's allocator routine, give it * the data item. */ int dict_alloc_insert(dict_t *dict, const void *key, void *data) { dnode_t *node = dict->allocnode (dict->context); if (node) { dnode_init(node, data); dict_insert(dict, node, key); return 1; } return 0; } void dict_delete_free(dict_t *dict, dnode_t *node) { dict_delete(dict, node); dict->freenode(node, dict->context); } /* * Return the node with the lowest (leftmost) key. If the dictionary is empty * (that is, dict_isempty(dict) returns 1) a null pointer is returned. */ dnode_t *dict_first(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; if (root != nil) while ((left = root->left) != nil) root = left; return (root == nil) ? NULL : root; } /* * Return the node with the highest (rightmost) key. If the dictionary is empty * (that is, dict_isempty(dict) returns 1) a null pointer is returned. */ dnode_t *dict_last(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; if (root != nil) while ((right = root->right) != nil) root = right; return (root == nil) ? NULL : root; } /* * Return the given node's successor node---the node which has the * next key in the the left to right ordering. If the node has * no successor, a null pointer is returned rather than a pointer to * the nil node. */ dnode_t *dict_next(dict_t *dict, dnode_t *curr) { dnode_t *nil = dict_nil(dict), *parent, *left; if (curr->right != nil) { curr = curr->right; while ((left = curr->left) != nil) curr = left; return curr; } parent = curr->parent; while (parent != nil && curr == parent->right) { curr = parent; parent = curr->parent; } return (parent == nil) ? NULL : parent; } /* * Return the given node's predecessor, in the key order. * The nil sentinel node is returned if there is no predecessor. */ dnode_t *dict_prev(dict_t *dict, dnode_t *curr) { dnode_t *nil = dict_nil(dict), *parent, *right; if (curr->left != nil) { curr = curr->left; while ((right = curr->right) != nil) curr = right; return curr; } parent = curr->parent; while (parent != nil && curr == parent->left) { curr = parent; parent = curr->parent; } return (parent == nil) ? NULL : parent; } void dict_allow_dupes(dict_t *dict) { dict->dupes = 1; } #undef dict_count #undef dict_isempty #undef dict_isfull #undef dnode_get #undef dnode_put #undef dnode_getkey dictcount_t dict_count(dict_t *dict) { return dict->nodecount; } int dict_isempty(dict_t *dict) { return dict->nodecount == 0; } int dict_isfull(dict_t *dict) { return dict->nodecount == dict->maxcount; } int dict_contains(dict_t *dict, dnode_t *node) { return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); } static dnode_t *dnode_alloc(void *context) { return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t)); } static void dnode_free(dnode_t *node, void *context) { XFREE(MTYPE_ISIS_DICT_NODE, node); } dnode_t *dnode_create(void *data) { dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t)); if (new) { new->data = data; new->parent = NULL; new->left = NULL; new->right = NULL; } return new; } dnode_t *dnode_init(dnode_t *dnode, void *data) { dnode->data = data; dnode->parent = NULL; dnode->left = NULL; dnode->right = NULL; return dnode; } void dnode_destroy(dnode_t *dnode) { assert (!dnode_is_in_a_dict(dnode)); XFREE(MTYPE_ISIS_DICT_NODE, dnode); } void *dnode_get(dnode_t *dnode) { return dnode->data; } const void *dnode_getkey(dnode_t *dnode) { return dnode->key; } void dnode_put(dnode_t *dnode, void *data) { dnode->data = data; } int dnode_is_in_a_dict(dnode_t *dnode) { return (dnode->parent && dnode->left && dnode->right); } void dict_process(dict_t *dict, void *context, dnode_process_t function) { dnode_t *node = dict_first(dict), *next; while (node != NULL) { /* check for callback function deleting */ /* the next node from under us */ assert (dict_contains(dict, node)); next = dict_next(dict, node); function(dict, node, context); node = next; } } static void load_begin_internal(dict_load_t *load, dict_t *dict) { load->dictptr = dict; load->nilnode.left = &load->nilnode; load->nilnode.right = &load->nilnode; } void dict_load_begin(dict_load_t *load, dict_t *dict) { assert (dict_isempty(dict)); load_begin_internal(load, dict); } void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) { dict_t *dict = load->dictptr; dnode_t *nil = &load->nilnode; assert (!dnode_is_in_a_dict(newnode)); assert (dict->nodecount < dict->maxcount); #ifndef NDEBUG if (dict->nodecount > 0) { if (dict->dupes) assert (dict->compare(nil->left->key, key) <= 0); else assert (dict->compare(nil->left->key, key) < 0); } #endif newnode->key = key; nil->right->left = newnode; nil->right = newnode; newnode->left = nil; dict->nodecount++; } void dict_load_end(dict_load_t *load) { dict_t *dict = load->dictptr; dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; dnode_t *complete = 0; dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; dictcount_t botrowcount; unsigned baselevel = 0, level = 0, i; assert (dnode_red == 0 && dnode_black == 1); while (fullcount >= nodecount && fullcount) fullcount >>= 1; botrowcount = nodecount - fullcount; for (curr = loadnil->left; curr != loadnil; curr = next) { next = curr->left; if (complete == NULL && botrowcount-- == 0) { assert (baselevel == 0); assert (level == 0); baselevel = level = 1; complete = tree[0]; if (complete != 0) { tree[0] = 0; complete->right = dictnil; while (tree[level] != 0) { tree[level]->right = complete; complete->parent = tree[level]; complete = tree[level]; tree[level++] = 0; } } } if (complete == NULL) { curr->left = dictnil; curr->right = dictnil; curr->color = level % 2; complete = curr; assert (level == baselevel); while (tree[level] != 0) { tree[level]->right = complete; complete->parent = tree[level]; complete = tree[level]; tree[level++] = 0; } } else { curr->left = complete; curr->color = (level + 1) % 2; complete->parent = curr; tree[level] = curr; complete = 0; level = baselevel; } } if (complete == NULL) complete = dictnil; for (i = 0; i < DICT_DEPTH_MAX; i++) { if (tree[i] != 0) { tree[i]->right = complete; complete->parent = tree[i]; complete = tree[i]; } } dictnil->color = dnode_black; dictnil->right = dictnil; complete->parent = dictnil; complete->color = dnode_black; dict_root(dict) = complete; assert (dict_verify(dict)); } void dict_merge(dict_t *dest, dict_t *source) { dict_load_t load; dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); assert (dict_similar(dest, source)); if (source == dest) return; dest->nodecount = 0; load_begin_internal(&load, dest); for (;;) { if (leftnode != NULL && rightnode != NULL) { if (dest->compare(leftnode->key, rightnode->key) < 0) goto copyleft; else goto copyright; } else if (leftnode != NULL) { goto copyleft; } else if (rightnode != NULL) { goto copyright; } else { assert (leftnode == NULL && rightnode == NULL); break; } copyleft: { dnode_t *next = dict_next(dest, leftnode); #ifndef NDEBUG leftnode->left = NULL; /* suppress assertion in dict_load_next */ #endif dict_load_next(&load, leftnode, leftnode->key); leftnode = next; continue; } copyright: { dnode_t *next = dict_next(source, rightnode); #ifndef NDEBUG rightnode->left = NULL; #endif dict_load_next(&load, rightnode, rightnode->key); rightnode = next; continue; } } dict_clear(source); dict_load_end(&load); } #ifdef KAZLIB_TEST_MAIN #include #include #include #include typedef char input_t[256]; static int tokenize(char *string, ...) { char **tokptr; va_list arglist; int tokcount = 0; va_start(arglist, string); tokptr = va_arg(arglist, char **); while (tokptr) { while (*string && isspace((unsigned char) *string)) string++; if (!*string) break; *tokptr = string; while (*string && !isspace((unsigned char) *string)) string++; tokptr = va_arg(arglist, char **); tokcount++; if (!*string) break; *string++ = 0; } va_end(arglist); return tokcount; } static int comparef(const void *key1, const void *key2) { return strcmp(key1, key2); } static char *dupstring(char *str) { int sz = strlen(str) + 1; char *new = XCALLOC(MTYPE_ISIS_TMP, sz); if (new) memcpy(new, str, sz); return new; } static dnode_t *new_node(void *c) { static dnode_t few[5]; static int count; if (count < 5) return few + count++; return NULL; } static void del_node(dnode_t *n, void *c) { } static int prompt = 0; static void construct(dict_t *d) { input_t in; int done = 0; dict_load_t dl; dnode_t *dn; char *tok1, *tok2, *val; const char *key; char *help = "p turn prompt on\n" "q finish construction\n" "a add new entry\n"; if (!dict_isempty(d)) puts("warning: dictionary not empty!"); dict_load_begin(&dl, d); while (!done) { if (prompt) putchar('>'); fflush(stdout); if (!fgets(in, sizeof(input_t), stdin)) break; switch (in[0]) { case '?': puts(help); break; case 'p': prompt = 1; break; case 'q': done = 1; break; case 'a': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } key = dupstring(tok1); val = dupstring(tok2); dn = dnode_create(val); if (!key || !val || !dn) { puts("out of memory"); free((void *) key); free(val); if (dn) dnode_destroy(dn); } dict_load_next(&dl, dn, key); break; default: putchar('?'); putchar('\n'); break; } } dict_load_end(&dl); } int main(void) { input_t in; dict_t darray[10]; dict_t *d = &darray[0]; dnode_t *dn; int i; char *tok1, *tok2, *val; const char *key; char *help = "a add value to dictionary\n" "d delete value from dictionary\n" "l lookup value in dictionary\n" "( lookup lower bound\n" ") lookup upper bound\n" "# switch to alternate dictionary (0-9)\n" "j merge two dictionaries\n" "f free the whole dictionary\n" "k allow duplicate keys\n" "c show number of entries\n" "t dump whole dictionary in sort order\n" "m make dictionary out of sorted items\n" "p turn prompt on\n" "s switch to non-functioning allocator\n" "q quit"; for (i = 0; i < 10; i++) dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); for (;;) { if (prompt) putchar('>'); fflush(stdout); if (!fgets(in, sizeof(input_t), stdin)) break; switch(in[0]) { case '?': puts(help); break; case 'a': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } key = dupstring(tok1); val = dupstring(tok2); if (!key || !val) { puts("out of memory"); free((void *) key); free(val); } if (!dict_alloc_insert(d, key, val)) { puts("dict_alloc_insert failed"); free((void *) key); free(val); break; } break; case 'd': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } dn = dict_lookup(d, tok1); if (!dn) { puts("dict_lookup failed"); break; } val = dnode_get(dn); key = dnode_getkey(dn); dict_delete_free(d, dn); free(val); free((void *) key); break; case 'f': dict_free(d); break; case 'l': case '(': case ')': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } dn = 0; switch (in[0]) { case 'l': dn = dict_lookup(d, tok1); break; case '(': dn = dict_lower_bound(d, tok1); break; case ')': dn = dict_upper_bound(d, tok1); break; } if (!dn) { puts("lookup failed"); break; } val = dnode_get(dn); puts(val); break; case 'm': construct(d); break; case 'k': dict_allow_dupes(d); break; case 'c': printf("%lu\n", (unsigned long) dict_count(d)); break; case 't': for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { printf("%s\t%s\n", (char *) dnode_getkey(dn), (char *) dnode_get(dn)); } break; case 'q': exit(0); break; case '\0': break; case 'p': prompt = 1; break; case 's': dict_set_allocator(d, new_node, del_node, NULL); break; case '#': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } else { int dictnum = atoi(tok1); if (dictnum < 0 || dictnum > 9) { puts("invalid number"); break; } d = &darray[dictnum]; } break; case 'j': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } else { int dict1 = atoi(tok1), dict2 = atoi(tok2); if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { puts("invalid number"); break; } dict_merge(&darray[dict1], &darray[dict2]); } break; default: putchar('?'); putchar('\n'); break; } } return 0; } #endif quagga-1.2.4/isisd/dict.h000066400000000000000000000077371325323223500152100ustar00rootroot00000000000000/* * Dictionary Abstract Data Type * Copyright (C) 1997 Kaz Kylheku * * Free Software License: * * All rights are reserved by the author, with the following exceptions: * Permission is granted to freely reproduce and distribute this software, * possibly in exchange for a fee, provided that this copyright notice appears * intact. Permission is also granted to adapt this software to produce * derivative works, as long as the modified versions carry this copyright * notice and additional notices stating that the work has been modified. * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. * * $Id: dict.h,v 1.3 2005/09/25 12:04:25 hasso Exp $ * $Name: $ */ #ifndef DICT_H #define DICT_H #include /* * Blurb for inclusion into C++ translation units */ #ifdef __cplusplus extern "C" { #endif typedef unsigned long dictcount_t; #define DICTCOUNT_T_MAX ULONG_MAX /* * The dictionary is implemented as a red-black tree */ typedef enum { dnode_red, dnode_black } dnode_color_t; typedef struct dnode_t { struct dnode_t *dict_left; struct dnode_t *dict_right; struct dnode_t *dict_parent; dnode_color_t dict_color; const void *dict_key; void *dict_data; } dnode_t; typedef int (*dict_comp_t)(const void *, const void *); typedef dnode_t *(*dnode_alloc_t)(void *); typedef void (*dnode_free_t)(dnode_t *, void *); typedef struct dict_t { dnode_t dict_nilnode; dictcount_t dict_nodecount; dictcount_t dict_maxcount; dict_comp_t dict_compare; dnode_alloc_t dict_allocnode; dnode_free_t dict_freenode; void *dict_context; int dict_dupes; } dict_t; typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); typedef struct dict_load_t { dict_t *dict_dictptr; dnode_t dict_nilnode; } dict_load_t; extern dict_t *dict_create(dictcount_t, dict_comp_t); extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); extern void dict_destroy(dict_t *); extern void dict_free_nodes(dict_t *); extern void dict_free(dict_t *); extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t); extern void dict_init_like(dict_t *, const dict_t *); extern int dict_verify(dict_t *); extern int dict_similar(const dict_t *, const dict_t *); extern dnode_t *dict_lookup(dict_t *, const void *); extern dnode_t *dict_lower_bound(dict_t *, const void *); extern dnode_t *dict_upper_bound(dict_t *, const void *); extern void dict_insert(dict_t *, dnode_t *, const void *); extern dnode_t *dict_delete(dict_t *, dnode_t *); extern int dict_alloc_insert(dict_t *, const void *, void *); extern void dict_delete_free(dict_t *, dnode_t *); extern dnode_t *dict_first(dict_t *); extern dnode_t *dict_last(dict_t *); extern dnode_t *dict_next(dict_t *, dnode_t *); extern dnode_t *dict_prev(dict_t *, dnode_t *); extern dictcount_t dict_count(dict_t *); extern int dict_isempty(dict_t *); extern int dict_isfull(dict_t *); extern int dict_contains(dict_t *, dnode_t *); extern void dict_allow_dupes(dict_t *); extern int dnode_is_in_a_dict(dnode_t *); extern dnode_t *dnode_create(void *); extern dnode_t *dnode_init(dnode_t *, void *); extern void dnode_destroy(dnode_t *); extern void *dnode_get(dnode_t *); extern const void *dnode_getkey(dnode_t *); extern void dnode_put(dnode_t *, void *); extern void dict_process(dict_t *, void *, dnode_process_t); extern void dict_load_begin(dict_load_t *, dict_t *); extern void dict_load_next(dict_load_t *, dnode_t *, const void *); extern void dict_load_end(dict_load_t *); extern void dict_merge(dict_t *, dict_t *); #define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) #define dict_count(D) ((D)->dict_nodecount) #define dict_isempty(D) ((D)->dict_nodecount == 0) #define dnode_get(N) ((N)->dict_data) #define dnode_getkey(N) ((N)->dict_key) #define dnode_put(N, X) ((N)->dict_data = (X)) #ifdef __cplusplus } #endif #endif quagga-1.2.4/isisd/include-netbsd/000077500000000000000000000000001325323223500167765ustar00rootroot00000000000000quagga-1.2.4/isisd/include-netbsd/clnp.h000066400000000000000000000505151325323223500201110ustar00rootroot00000000000000/* $NetBSD: clnp.h,v 1.13 2001/08/20 12:00:54 wiz Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)clnp.h 8.2 (Berkeley) 4/16/94 */ /*********************************************************** Copyright IBM Corporation 1987 All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, 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 IBM not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison */ /* should be config option but cpp breaks with too many #defines */ #define DECBIT /* * Return true if the mbuf is a cluster mbuf */ #define IS_CLUSTER(m) ((m)->m_flags & M_EXT) /* * Move the halfword into the two characters */ #define HTOC(msb, lsb, hword)\ (msb) = (u_char)((hword) >> 8);\ (lsb) = (u_char)((hword) & 0xff) /* * Move the two charcters into the halfword */ #define CTOH(msb, lsb, hword)\ (hword) = ((msb) << 8) | (lsb) /* * Return true if the checksum has been set - ie. the checksum is * not zero */ #define CKSUM_REQUIRED(clnp)\ (((clnp)->cnf_cksum_msb != 0) || ((clnp)->cnf_cksum_lsb != 0)) /* * Fixed part of clnp header */ struct clnp_fixed { u_char cnf_proto_id; /* network layer protocol identifier */ u_char cnf_hdr_len; /* length indicator (octets) */ u_char cnf_vers; /* version/protocol identifier * extension */ u_char cnf_ttl;/* lifetime (500 milliseconds) */ u_char cnf_type; /* type code */ /* Includes err_ok, more_segs, and seg_ok */ u_char cnf_seglen_msb; /* pdu segment length (octets) high * byte */ u_char cnf_seglen_lsb; /* pdu segment length (octets) low * byte */ u_char cnf_cksum_msb; /* checksum high byte */ u_char cnf_cksum_lsb; /* checksum low byte */ } __attribute__((packed)); #define CNF_TYPE 0x1f #define CNF_ERR_OK 0x20 #define CNF_MORE_SEGS 0x40 #define CNF_SEG_OK 0x80 #define CLNP_CKSUM_OFF 0x07 /* offset of checksum */ #define clnl_fixed clnp_fixed /* * Segmentation part of clnp header */ struct clnp_segment { u_short cng_id; /* data unit identifier */ u_short cng_off;/* segment offset */ u_short cng_tot_len; /* total length */ }; /* * Clnp fragment reassembly structures: * * All packets undergoing reassembly are linked together in * clnp_fragl structures. Each clnp_fragl structure contains a * pointer to the original clnp packet header, as well as a * list of packet fragments. Each packet fragment * is headed by a clnp_frag structure. This structure contains the * offset of the first and last byte of the fragment, as well as * a pointer to the data (an mbuf chain) of the fragment. */ /* * NOTE: * The clnp_frag structure is stored in an mbuf immedately * preceding the fragment data. Since there are words in * this struct, it must be word aligned. * * NOTE: * All the fragment code assumes that the entire clnp header is * contained in the first mbuf. */ struct clnp_frag { u_int cfr_first; /* offset of first byte of this frag */ u_int cfr_last; /* offset of last byte of this frag */ u_int cfr_bytes; /* bytes to shave to get to data */ struct mbuf *cfr_data; /* ptr to data for this frag */ struct clnp_frag *cfr_next; /* next fragment in list */ }; struct clnp_fragl { struct iso_addr cfl_src;/* source of the pkt */ struct iso_addr cfl_dst;/* destination of the pkt */ u_short cfl_id; /* id of the pkt */ u_char cfl_ttl;/* current ttl of pkt */ u_short cfl_last; /* offset of last byte of packet */ struct mbuf *cfl_orighdr; /* ptr to original header */ struct clnp_frag *cfl_frags; /* linked list of fragments for pkt */ struct clnp_fragl *cfl_next; /* next pkt being reassembled */ }; /* * The following structure is used to index into an options section * of a clnp datagram. These values can be used without worry that * offset or length fields are invalid or too big, etc. That is, * the consistancy of the options will be guaranteed before this * structure is filled in. Any pointer (field ending in p) is * actually the offset from the beginning of the mbuf the option * is contained in. A value of NULL for any pointer * means that the option is not present. The length any option * does not include the option code or option length fields. */ struct clnp_optidx { u_short cni_securep; /* ptr to start of security option */ char cni_secure_len; /* length of entire security option */ u_short cni_srcrt_s; /* offset of start of src rt option */ u_short cni_srcrt_len; /* length of entire src rt option */ u_short cni_recrtp; /* ptr to beginning of recrt option */ char cni_recrt_len; /* length of entire recrt option */ char cni_priorp; /* ptr to priority option */ u_short cni_qos_formatp; /* ptr to format of qos * option */ char cni_qos_len; /* length of entire qos option */ u_char cni_er_reason; /* reason from ER pdu option */ /* ESIS options */ u_short cni_esct; /* value from ISH ESCT option */ u_short cni_netmaskp; /* ptr to beginning of netmask option */ char cni_netmask_len; /* length of entire netmask * option */ u_short cni_snpamaskp; /* ptr to start of snpamask option */ char cni_snpamask_len; /* length of entire snpamask * option */ }; #define ER_INVALREAS 0xff /* code for invalid ER pdu discard reason */ /* given an mbuf and addr of option, return offset from data of mbuf */ #define CLNP_OPTTOOFF(m, opt) ((u_short) (opt - mtod(m, caddr_t))) /* given an mbuf and offset of option, return address of option */ #define CLNP_OFFTOOPT(m, off) ((caddr_t) (mtod(m, caddr_t) + off)) /* return true iff src route is valid */ #define CLNPSRCRT_VALID(oidx) ((oidx) && (oidx->cni_srcrt_s)) /* return the offset field of the src rt */ #define CLNPSRCRT_OFF(oidx, options)\ (*((u_char *)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + 1))) /* return the type field of the src rt */ #define CLNPSRCRT_TYPE(oidx, options)\ ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s)))) /* return the length of the current address */ #define CLNPSRCRT_CLEN(oidx, options)\ ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options) - 1))) /* return the address of the current address */ #define CLNPSRCRT_CADDR(oidx, options)\ ((caddr_t)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options))) /* * return true if the src route has run out of routes this is true if the * offset of next route is greater than the end of the rt */ #define CLNPSRCRT_TERM(oidx, options)\ (CLNPSRCRT_OFF(oidx, options) > oidx->cni_srcrt_len) /* * Options a user can set/get */ #define CLNPOPT_FLAGS 0x01 /* flags: seg permitted, no er xmit, etc */ #define CLNPOPT_OPTS 0x02 /* datagram options */ /* * Values for particular datagram options */ #define CLNPOVAL_PAD 0xcc /* padding */ #define CLNPOVAL_SECURE 0xc5 /* security */ #define CLNPOVAL_SRCRT 0xc8 /* source routing */ #define CLNPOVAL_RECRT 0xcb /* record route */ #define CLNPOVAL_QOS 0xc3 /* quality of service */ #define CLNPOVAL_PRIOR 0xcd /* priority */ #define CLNPOVAL_ERREAS 0xc1 /* ER PDU ONLY: reason for discard */ #define CLNPOVAL_SRCSPEC 0x40 /* source address specific */ #define CLNPOVAL_DSTSPEC 0x80 /* destination address specific */ #define CLNPOVAL_GLOBAL 0xc0 /* globally unique */ /* Globally Unique QOS */ #define CLNPOVAL_SEQUENCING 0x10 /* sequencing preferred */ #define CLNPOVAL_CONGESTED 0x08 /* congestion experienced */ #define CLNPOVAL_LOWDELAY 0x04 /* low transit delay */ #define CLNPOVAL_PARTRT 0x00 /* partial source routing */ #define CLNPOVAL_COMPRT 0x01 /* complete source routing */ /* * Clnp flags used in a control block flags field. * NOTE: these must be out of the range of bits defined in ../net/raw_cb.h */ #define CLNP_NO_SEG 0x010 /* segmentation not permitted */ #define CLNP_NO_ER 0x020 /* do not generate ERs */ #define CLNP_SEND_RAW 0x080 /* send pkt as RAW DT not TP DT */ #define CLNP_NO_CKSUM 0x100 /* don't use clnp checksum */ #define CLNP_ECHO 0x200 /* send echo request */ #define CLNP_NOCACHE 0x400 /* don't store cache information */ #define CLNP_ECHOR 0x800 /* send echo reply */ /* valid clnp flags */ #define CLNP_VFLAGS \ (CLNP_SEND_RAW|CLNP_NO_SEG|CLNP_NO_ER|CLNP_NO_CKSUM|\ CLNP_ECHO|CLNP_NOCACHE|CLNP_ECHOR) /* * Constants used by clnp */ #define CLNP_HDR_MIN (sizeof (struct clnp_fixed)) #define CLNP_HDR_MAX (254) #define CLNP_TTL_UNITS 2 /* 500 milliseconds */ #define CLNP_TTL 15*CLNP_TTL_UNITS /* time to live (seconds) */ #define ISO8473_V1 0x01 /* * Clnp packet types * In order to test raw clnp and tp/clnp simultaneously, a third type of * packet has been defined: CLNP_RAW. This is done so that the input * routine can switch to the correct input routine (rclnp_input or * tpclnp_input) based on the type field. If clnp had a higher level * protocol field, this would not be necessary. */ #define CLNP_DT 0x1C /* normal data */ #define CLNP_ER 0x01 /* error report */ #define CLNP_RAW 0x1D /* debug only */ #define CLNP_EC 0x1E /* echo packet */ #define CLNP_ECR 0x1F /* echo reply */ /* * ER pdu error codes */ #define GEN_NOREAS 0x00 /* reason not specified */ #define GEN_PROTOERR 0x01 /* protocol procedure error */ #define GEN_BADCSUM 0x02 /* incorrect checksum */ #define GEN_CONGEST 0x03 /* pdu discarded due to congestion */ #define GEN_HDRSYNTAX 0x04 /* header syntax error */ #define GEN_SEGNEEDED 0x05 /* need segmentation but not allowed */ #define GEN_INCOMPLETE 0x06 /* incomplete pdu received */ #define GEN_DUPOPT 0x07 /* duplicate option */ /* address errors */ #define ADDR_DESTUNREACH 0x80 /* destination address unreachable */ #define ADDR_DESTUNKNOWN 0x81 /* destination address unknown */ /* source routing */ #define SRCRT_UNSPECERR 0x90 /* unspecified src rt error */ #define SRCRT_SYNTAX 0x91 /* syntax error in src rt field */ #define SRCRT_UNKNOWNADDR 0x92 /* unknown addr in src rt field */ #define SRCRT_BADPATH 0x93 /* path not acceptable */ /* lifetime */ #define TTL_EXPTRANSIT 0xa0 /* lifetime expired during transit */ #define TTL_EXPREASS 0xa1 /* lifetime expired during reassembly */ /* pdu discarded */ #define DISC_UNSUPPOPT 0xb0 /* unsupported option not specified? */ #define DISC_UNSUPPVERS 0xb1 /* unsupported protocol version */ #define DISC_UNSUPPSECURE 0xb2 /* unsupported security option */ #define DISC_UNSUPPSRCRT 0xb3 /* unsupported src rt option */ #define DISC_UNSUPPRECRT 0xb4 /* unsupported rec rt option */ /* reassembly */ #define REASS_INTERFERE 0xc0 /* reassembly interference */ #define CLNP_ERRORS 22 #ifdef CLNP_ER_CODES u_char clnp_er_codes[CLNP_ERRORS] = { GEN_NOREAS, GEN_PROTOERR, GEN_BADCSUM, GEN_CONGEST, GEN_HDRSYNTAX, GEN_SEGNEEDED, GEN_INCOMPLETE, GEN_DUPOPT, ADDR_DESTUNREACH, ADDR_DESTUNKNOWN, SRCRT_UNSPECERR, SRCRT_SYNTAX, SRCRT_UNKNOWNADDR, SRCRT_BADPATH, TTL_EXPTRANSIT, TTL_EXPREASS, DISC_UNSUPPOPT, DISC_UNSUPPVERS, DISC_UNSUPPSECURE, DISC_UNSUPPSRCRT, DISC_UNSUPPRECRT, REASS_INTERFERE }; #endif #ifdef TROLL #define TR_DUPEND 0x01 /* duplicate end of fragment */ #define TR_DUPPKT 0x02 /* duplicate entire packet */ #define TR_DROPPKT 0x04 /* drop packet on output */ #define TR_TRIM 0x08 /* trim bytes from packet */ #define TR_CHANGE 0x10 /* change bytes in packet */ #define TR_MTU 0x20 /* delta to change device mtu */ #define TR_CHUCK 0x40 /* drop packet in rclnp_input */ #define TR_BLAST 0x80 /* force rclnp_output to blast many * packet */ #define TR_RAWLOOP 0x100 /* make if_loop call clnpintr * directly */ struct troll { int tr_ops; /* operations to perform */ float tr_dup_size; /* % to duplicate */ float tr_dup_freq; /* frequency to duplicate packets */ float tr_drop_freq; /* frequence to drop packets */ int tr_mtu_adj; /* delta to adjust if mtu */ int tr_blast_cnt; /* # of pkts to blast out */ }; #define SN_OUTPUT(clcp, m)\ troll_output(clcp->clc_ifp, m, clcp->clc_firsthop, clcp->clc_rt) #define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\ rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))\ - trollctl.tr_mtu_adj) #ifdef _KERNEL extern float troll_random; #endif #else /* NO TROLL */ #define SN_OUTPUT(clcp, m)\ (*clcp->clc_ifp->if_output)(clcp->clc_ifp, m, clcp->clc_firsthop, \ clcp->clc_rt) #define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\ rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))) #endif /* TROLL */ /* * Macro to remove an address from a clnp header */ #define CLNP_EXTRACT_ADDR(isoa, hoff, hend)\ {\ isoa.isoa_len = (u_char)*hoff;\ if ((((++hoff) + isoa.isoa_len) > hend) ||\ (isoa.isoa_len > 20) || (isoa.isoa_len == 0)) {\ hoff = (caddr_t)0;\ } else {\ (void) bcopy(hoff, (caddr_t)isoa.isoa_genaddr, \ isoa.isoa_len);\ hoff += isoa.isoa_len;\ }\ } /* * Macro to insert an address into a clnp header */ #define CLNP_INSERT_ADDR(hoff, isoa)\ *hoff++ = (isoa).isoa_len;\ (void) bcopy((caddr_t)((isoa).isoa_genaddr), hoff, (isoa).isoa_len);\ hoff += (isoa).isoa_len; /* * Clnp hdr cache. Whenever a clnp packet is sent, a copy of the * header is made and kept in this cache. In addition to a copy of * the cached clnp hdr, the cache contains * information necessary to determine whether the new packet * to send requires a new header to be built. */ struct clnp_cache { /* these fields are used to check the validity of the cache */ struct iso_addr clc_dst;/* destination of packet */ struct mbuf *clc_options; /* ptr to options mbuf */ int clc_flags; /* flags passed to clnp_output */ /* these fields are state that clnp_output requires to finish the pkt */ int clc_segoff; /* offset of seg part of header */ struct rtentry *clc_rt; /* ptr to rtentry (points into the route * structure) */ struct sockaddr *clc_firsthop; /* first hop of packet */ struct ifnet *clc_ifp;/* ptr to interface structure */ struct iso_ifaddr *clc_ifa;/* ptr to interface address */ struct mbuf *clc_hdr;/* cached pkt hdr (finally)! */ }; #ifdef _KERNEL struct iso_addr; struct sockaddr_iso; struct mbuf; struct clnp_segment; struct sockaddr; struct rt_entry; struct clnp_fragl; struct clnp_optidx; struct isopcb; struct snpa_hdr; struct iso_ifaddr; struct route_iso; /* clnp_debug.c */ char *clnp_hexp __P((char *, int, char *)); char *clnp_iso_addrp __P((struct iso_addr *)); char *clnp_saddr_isop __P((struct sockaddr_iso *)); /* clnp_er.c */ void clnp_er_input __P((struct mbuf *, struct iso_addr *, u_int)); void clnp_discard __P((struct mbuf *, u_int)); void clnp_emit_er __P((struct mbuf *, u_int)); int clnp_er_index __P((u_int)); int clnp_fragment __P((struct ifnet *, struct mbuf *, struct sockaddr *, int, int, int, struct rtentry *)); struct mbuf *clnp_reass __P((struct mbuf *, struct iso_addr *, struct iso_addr *, struct clnp_segment *)); int clnp_newpkt __P((struct mbuf *, struct iso_addr *, struct iso_addr *, struct clnp_segment *)); void clnp_insert_frag __P((struct clnp_fragl *, struct mbuf *, struct clnp_segment *)); struct mbuf *clnp_comp_pdu __P((struct clnp_fragl *)); #ifdef TROLL float troll_random __P((void)); int troll_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); #endif /* clnp_input.c */ void clnp_init __P((void)); void clnlintr __P((void)); void clnp_input __P((struct mbuf *, ...)); /* clnp_options.c */ void clnp_update_srcrt __P((struct mbuf *, struct clnp_optidx *)); void clnp_dooptions __P((struct mbuf *, struct clnp_optidx *, struct ifnet *, struct iso_addr *)); int clnp_set_opts __P((struct mbuf **, struct mbuf **)); int clnp_opt_sanity __P((struct mbuf *, caddr_t, int, struct clnp_optidx *)); /* clnp_output.c */ int clnp_output __P((struct mbuf *, ...)); void clnp_ctloutput __P((void)); /* clnp_raw.c */ void rclnp_input __P((struct mbuf *, ...)); int rclnp_output __P((struct mbuf *, ...)); int rclnp_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); int clnp_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); /* clnp_subr.c */ struct mbuf *clnp_data_ck __P((struct mbuf *, int)); caddr_t clnp_extract_addr __P((caddr_t, int, struct iso_addr *, struct iso_addr *)); int clnp_ours __P((struct iso_addr *)); void clnp_forward __P((struct mbuf *, int, struct iso_addr *, struct clnp_optidx *, int, struct snpa_hdr *)); caddr_t clnp_insert_addr __P((caddr_t, struct iso_addr *, struct iso_addr *)); int clnp_route __P((struct iso_addr *, struct route_iso *, int, struct sockaddr **, struct iso_ifaddr **)); int clnp_srcroute __P((struct mbuf *, struct clnp_optidx *, struct route_iso *, struct sockaddr **, struct iso_ifaddr **, struct iso_addr *)); int clnp_echoreply __P((struct mbuf *, int, struct sockaddr_iso *, struct sockaddr_iso *, struct clnp_optidx *)); int clnp_badmtu __P((struct ifnet *, struct rtentry *, int, char *)); void clnp_ypocb __P((caddr_t, caddr_t, u_int)); /* clnp_timer.c */ struct clnp_fragl *clnp_freefrags __P((struct clnp_fragl *)); void clnp_slowtimo __P((void)); void clnp_drain __P((void)); #ifdef TROLL struct troll trollctl; #endif /* TROLL */ #endif /* _KERNEL */ quagga-1.2.4/isisd/include-netbsd/esis.h000066400000000000000000000141211325323223500201110ustar00rootroot00000000000000/* $NetBSD: esis.h,v 1.11 1997/11/03 15:01:19 is Exp $ */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)esis.h 8.1 (Berkeley) 6/10/93 */ /*********************************************************** Copyright IBM Corporation 1987 All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, 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 IBM not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison */ #include #define SNPAC_AGE 60 /* seconds */ #define ESIS_CONFIG 60 /* seconds */ #define ESIS_HT (ESIS_CONFIG * 2) /* * Fixed part of an ESIS header */ struct esis_fixed { u_char esis_proto_id; /* network layer protocol identifier */ u_char esis_hdr_len; /* length indicator (octets) */ u_char esis_vers; /* version/protocol identifier * extension */ u_char esis_res1; /* reserved */ u_char esis_type; /* type code */ /* technically, type should be &='d 0x1f */ #define ESIS_ESH 0x02 /* End System Hello */ #define ESIS_ISH 0x04 /* Intermediate System Hello */ #define ESIS_RD 0x06 /* Redirect */ u_char esis_ht_msb; /* holding time (seconds) high byte */ u_char esis_ht_lsb; /* holding time (seconds) low byte */ u_char esis_cksum_msb; /* checksum high byte */ u_char esis_cksum_lsb; /* checksum low byte */ } __attribute__((packed)); /* * Values for ESIS datagram options */ #define ESISOVAL_NETMASK 0xe1 /* address mask option, RD PDU only */ #define ESISOVAL_SNPAMASK 0xe2 /* snpa mask option, RD PDU only */ #define ESISOVAL_ESCT 0xc6 /* end system conf. timer, ISH PDU * only */ #define ESIS_CKSUM_OFF 0x07 #define ESIS_CKSUM_REQUIRED(pdu)\ ((pdu->esis_cksum_msb != 0) || (pdu->esis_cksum_lsb != 0)) #define ESIS_VERSION 1 struct esis_stat { u_short es_nomem; /* insufficient memory to send hello */ u_short es_badcsum; /* incorrect checksum */ u_short es_badvers; /* incorrect version number */ u_short es_badtype; /* unknown pdu type field */ u_short es_toosmall; /* packet too small */ u_short es_eshsent; /* ESH sent */ u_short es_eshrcvd; /* ESH rcvd */ u_short es_ishsent; /* ISH sent */ u_short es_ishrcvd; /* ISH rcvd */ u_short es_rdsent; /* RD sent */ u_short es_rdrcvd; /* RD rcvd */ }; #ifdef _KERNEL struct esis_stat esis_stat; struct socket; struct mbuf; struct snpa_hdr; struct clnp_optidx; struct iso_addr; struct rtentry; struct sockaddr_dl; void esis_init __P((void)); int esis_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); void esis_input __P((struct mbuf *, ...)); void esis_rdoutput __P((struct snpa_hdr *, struct mbuf *, struct clnp_optidx *, struct iso_addr *, struct rtentry *)); int esis_insert_addr __P((caddr_t *, int *, struct iso_addr *, struct mbuf *, int)); void esis_eshinput __P((struct mbuf *, struct snpa_hdr *)); void esis_ishinput __P((struct mbuf *, struct snpa_hdr *)); void esis_rdinput __P((struct mbuf *, struct snpa_hdr *)); void esis_config __P((void *)); void esis_shoutput __P((struct ifnet *, int, int, caddr_t, int, struct iso_addr *)); void isis_input __P((struct mbuf *, ...)); int isis_output __P((struct mbuf *, ...)); void *esis_ctlinput __P((int, struct sockaddr *, void *)); #endif /* _KERNEL */ quagga-1.2.4/isisd/include-netbsd/iso.h000066400000000000000000000162001325323223500177400ustar00rootroot00000000000000/* $NetBSD: iso.h,v 1.13 2000/07/28 12:13:34 kleink Exp $ */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)iso.h 8.1 (Berkeley) 6/10/93 */ /*********************************************************** Copyright IBM Corporation 1987 All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, 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 IBM not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison */ #ifndef _NETISO_ISO_H_ #define _NETISO_ISO_H_ #if 0 #include #endif #if 0 #ifndef sa_family_t typedef __sa_family_t sa_family_t; #define sa_family_t __sa_family_t #endif #endif /* * Return true if this is a multicast address * This assumes that the bit transmission is lsb first. This * assumption is valid for 802.3 but not 802.5. There is a * kludge to get around this for 802.5 -- see if_lan.c * where subnetwork header is setup. */ #define IS_MULTICAST(snpa)\ ((snpa)[0] & 0x01) /* * Protocols */ #define ISOPROTO_TCP 6 /* IETF experiment */ #define ISOPROTO_UDP 17 /* IETF experiment */ #define ISOPROTO_TP0 25 /* connection oriented transport protocol */ #define ISOPROTO_TP1 26 /* not implemented */ #define ISOPROTO_TP2 27 /* not implemented */ #define ISOPROTO_TP3 28 /* not implemented */ #define ISOPROTO_TP4 29 /* connection oriented transport protocol */ #define ISOPROTO_TP ISOPROTO_TP4 /* tp-4 with negotiation */ #define ISOPROTO_CLTP 30 /* connectionless transport (not yet impl.) */ #define ISOPROTO_CLNP 31 /* connectionless internetworking protocol */ #define ISOPROTO_X25 32 /* cons */ #define ISOPROTO_INACT_NL 33 /* inactive network layer! */ #define ISOPROTO_ESIS 34 /* ES-IS protocol */ #define ISOPROTO_INTRAISIS 35 /* IS-IS protocol */ #define ISOPROTO_IDRP 36 /* Interdomain Routing Protocol */ #define ISOPROTO_RAW 255 /* raw clnp */ #define ISOPROTO_MAX 256 #define ISO_PORT_RESERVED 1024 #define ISO_PORT_USERRESERVED 5000 /* * Port/socket numbers: standard network functions * NOT PRESENTLY USED */ #define ISO_PORT_MAINT 501 #define ISO_PORT_ECHO 507 #define ISO_PORT_DISCARD 509 #define ISO_PORT_SYSTAT 511 #define ISO_PORT_NETSTAT 515 /* * Port/socket numbers: non-standard application functions */ #define ISO_PORT_LOGIN 513 /* * Port/socket numbers: public use */ #define ISO_PORT_PUBLIC 1024 /* high bit set --> public */ /* * Network layer protocol identifiers */ #define ISO8473_CLNP 0x81 #define ISO9542_ESIS 0x82 #define ISO9542X25_ESIS 0x8a #define ISO10589_ISIS 0x83 #define ISO8878A_CONS 0x84 #define ISO10747_IDRP 0x85 #ifndef IN_CLASSA_NET #include #endif /* IN_CLASSA_NET */ /* * The following looks like a sockaddr to facilitate using tree lookup * routines */ struct iso_addr { u_char isoa_len; /* length (in bytes) */ char isoa_genaddr[20]; /* general opaque address */ }; struct sockaddr_iso { u_char siso_len; /* length */ sa_family_t siso_family; /* family */ u_char siso_plen; /* presentation selector length */ u_char siso_slen; /* session selector length */ u_char siso_tlen; /* transport selector length */ struct iso_addr siso_addr; /* network address */ u_char siso_pad[6]; /* space for gosip v2 sels */ /* makes struct 32 bytes long */ }; #define siso_nlen siso_addr.isoa_len #define siso_data siso_addr.isoa_genaddr #define TSEL(s) ((caddr_t)((s)->siso_data + (s)->siso_nlen)) #define SAME_ISOADDR(a, b) \ (bcmp((a)->siso_data, (b)->siso_data, (unsigned)(a)->siso_nlen)==0) #define SAME_ISOIFADDR(a, b) (bcmp((a)->siso_data, (b)->siso_data, \ (unsigned)((b)->siso_nlen - (b)->siso_tlen)) == 0) /* * The following are specific values for siso->siso_data[0], * otherwise known as the AFI: */ #define AFI_37 0x37 /* bcd of "37" */ #define AFI_OSINET 0x47 /* bcd of "47" */ #define AFI_RFC986 0x47 /* bcd of "47" */ #define AFI_SNA 0x00 /* SubNetwork Address; invalid really... */ #ifdef _KERNEL extern struct domain isodomain; extern struct protosw isosw[]; #define satosiso(sa) ((struct sockaddr_iso *)(sa)) #define sisotosa(siso) ((struct sockaddr *)(siso)) #else /* user utilities definitions from the iso library */ #ifndef HAVE_SYS_CDEFS_H #define __P(x) x #define __BEGIN_DECLS #define __END_DECLS #else #include #endif __BEGIN_DECLS struct iso_addr *iso_addr __P((const char *)); char *iso_ntoa __P((const struct iso_addr *)); /* THESE DON'T EXIST YET */ struct hostent *iso_gethostbyname __P((const char *)); struct hostent *iso_gethostbyaddr __P((const char *, int, int)); __END_DECLS #endif /* _KERNEL */ #endif /* _NETISO_ISO_H_ */ quagga-1.2.4/isisd/isis_adjacency.c000066400000000000000000000342741325323223500172240ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_adjacency.c * handling of IS-IS adjacencies * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "log.h" #include "memory.h" #include "hash.h" #include "vty.h" #include "linklist.h" #include "thread.h" #include "if.h" #include "stream.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_circuit.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_misc.h" #include "isisd/isis_dr.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_pdu.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_spf.h" #include "isisd/isis_events.h" extern struct isis *isis; static struct isis_adjacency * adj_alloc (const u_char *id) { struct isis_adjacency *adj; adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency)); memcpy (adj->sysid, id, ISIS_SYS_ID_LEN); return adj; } struct isis_adjacency * isis_new_adj (const u_char * id, const u_char * snpa, int level, struct isis_circuit *circuit) { struct isis_adjacency *adj; int i; adj = adj_alloc (id); /* P2P kludge */ if (adj == NULL) { zlog_err ("Out of memory!"); return NULL; } if (snpa) { memcpy (adj->snpa, snpa, ETH_ALEN); } else { memset (adj->snpa, ' ', ETH_ALEN); } adj->circuit = circuit; adj->level = level; adj->flaps = 0; adj->last_flap = time (NULL); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { listnode_add (circuit->u.bc.adjdb[level - 1], adj); adj->dischanges[level - 1] = 0; for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */ { adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis = ISIS_UNKNOWN_DIS; adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change = time (NULL); } } return adj; } struct isis_adjacency * isis_adj_lookup (const u_char * sysid, struct list *adjdb) { struct isis_adjacency *adj; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0) return adj; return NULL; } struct isis_adjacency * isis_adj_lookup_snpa (const u_char * ssnpa, struct list *adjdb) { struct listnode *node; struct isis_adjacency *adj; for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0) return adj; return NULL; } void isis_delete_adj (void *arg) { struct isis_adjacency *adj = arg; if (!adj) return; THREAD_TIMER_OFF (adj->t_expire); /* remove from SPF trees */ spftree_area_adj_del (adj->circuit->area, adj); if (adj->area_addrs) list_delete (adj->area_addrs); if (adj->ipv4_addrs) list_delete (adj->ipv4_addrs); #ifdef HAVE_IPV6 if (adj->ipv6_addrs) list_delete (adj->ipv6_addrs); #endif XFREE (MTYPE_ISIS_ADJACENCY, adj); return; } static const char * adj_state2string (int state) { switch (state) { case ISIS_ADJ_INITIALIZING: return "Initializing"; case ISIS_ADJ_UP: return "Up"; case ISIS_ADJ_DOWN: return "Down"; default: return "Unknown"; } return NULL; /* not reached */ } void isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state, const char *reason) { int old_state; int level; struct isis_circuit *circuit; old_state = adj->adj_state; adj->adj_state = new_state; circuit = adj->circuit; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s", circuit->area->area_tag, old_state, new_state, reason ? reason : "unspecified"); } if (circuit->area->log_adj_changes) { const char *adj_name; struct isis_dynhn *dyn; dyn = dynhn_find_by_id (adj->sysid); if (dyn) adj_name = (const char *)dyn->name.name; else adj_name = sysid_print (adj->sysid); zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s", adj_name, adj->circuit->interface->name, adj_state2string (old_state), adj_state2string (new_state), reason ? reason : "unspecified"); } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { if ((adj->level & level) == 0) continue; if (new_state == ISIS_ADJ_UP) { circuit->upadjcount[level - 1]++; isis_event_adjacency_state_change (adj, new_state); /* update counter & timers for debugging purposes */ adj->last_flap = time (NULL); adj->flaps++; } else if (new_state == ISIS_ADJ_DOWN) { listnode_delete (circuit->u.bc.adjdb[level - 1], adj); circuit->upadjcount[level - 1]--; if (circuit->upadjcount[level - 1] == 0) { /* Clean lsp_queue when no adj is up. */ if (circuit->lsp_queue) list_delete_all_node (circuit->lsp_queue); } isis_event_adjacency_state_change (adj, new_state); isis_delete_adj (adj); } if (circuit->u.bc.lan_neighs[level - 1]) { list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], circuit->u.bc.lan_neighs[level - 1]); } /* On adjacency state change send new pseudo LSP if we are the DR */ if (circuit->u.bc.is_dr[level - 1]) lsp_regenerate_schedule_pseudo (circuit, level); } } else if (circuit->circ_type == CIRCUIT_T_P2P) { for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { if ((adj->level & level) == 0) continue; if (new_state == ISIS_ADJ_UP) { circuit->upadjcount[level - 1]++; isis_event_adjacency_state_change (adj, new_state); if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) send_hello (circuit, level); /* update counter & timers for debugging purposes */ adj->last_flap = time (NULL); adj->flaps++; /* 7.3.17 - going up on P2P -> send CSNP */ /* FIXME: yup, I know its wrong... but i will do it! (for now) */ send_csnp (circuit, level); } else if (new_state == ISIS_ADJ_DOWN) { if (adj->circuit->u.p2p.neighbor == adj) adj->circuit->u.p2p.neighbor = NULL; circuit->upadjcount[level - 1]--; if (circuit->upadjcount[level - 1] == 0) { /* Clean lsp_queue when no adj is up. */ if (circuit->lsp_queue) list_delete_all_node (circuit->lsp_queue); } isis_event_adjacency_state_change (adj, new_state); isis_delete_adj (adj); } } } return; } void isis_adj_print (struct isis_adjacency *adj) { struct isis_dynhn *dyn; struct listnode *node; struct in_addr *ipv4_addr; #ifdef HAVE_IPV6 struct in6_addr *ipv6_addr; u_char ip6[INET6_ADDRSTRLEN]; #endif /* HAVE_IPV6 */ if (!adj) return; dyn = dynhn_find_by_id (adj->sysid); if (dyn) zlog_debug ("%s", dyn->name.name); zlog_debug ("SystemId %20s SNPA %s, level %d\nHolding Time %d", sysid_print (adj->sysid), snpa_print (adj->snpa), adj->level, adj->hold_time); if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { zlog_debug ("IPv4 Address(es):"); for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr)) zlog_debug ("%s", inet_ntoa (*ipv4_addr)); } #ifdef HAVE_IPV6 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { zlog_debug ("IPv6 Address(es):"); for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr)) { inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN); zlog_debug ("%s", ip6); } } #endif /* HAVE_IPV6 */ zlog_debug ("Speaks: %s", nlpid2string (&adj->nlpids)); return; } int isis_adj_expire (struct thread *thread) { struct isis_adjacency *adj; /* * Get the adjacency */ adj = THREAD_ARG (thread); assert (adj); adj->t_expire = NULL; /* trigger the adj expire event */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired"); return 0; } /* * show isis neighbor [detail] */ void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail) { #ifdef HAVE_IPV6 struct in6_addr *ipv6_addr; u_char ip6[INET6_ADDRSTRLEN]; #endif /* HAVE_IPV6 */ struct in_addr *ip_addr; time_t now; struct isis_dynhn *dyn; int level; struct listnode *node; dyn = dynhn_find_by_id (adj->sysid); if (dyn) vty_out (vty, " %-20s", dyn->name.name); else vty_out (vty, " %-20s", sysid_print (adj->sysid)); if (detail == ISIS_UI_LEVEL_BRIEF) { if (adj->circuit) vty_out (vty, "%-12s", adj->circuit->interface->name); else vty_out (vty, "NULL circuit!"); vty_out (vty, "%-3u", adj->level); /* level */ vty_out (vty, "%-13s", adj_state2string (adj->adj_state)); now = time (NULL); if (adj->last_upd) vty_out (vty, "%-9llu", (unsigned long long)adj->last_upd + adj->hold_time - now); else vty_out (vty, "- "); vty_out (vty, "%-10s", snpa_print (adj->snpa)); vty_out (vty, "%s", VTY_NEWLINE); } if (detail == ISIS_UI_LEVEL_DETAIL) { level = adj->level; vty_out (vty, "%s", VTY_NEWLINE); if (adj->circuit) vty_out (vty, " Interface: %s", adj->circuit->interface->name); else vty_out (vty, " Interface: NULL circuit"); vty_out (vty, ", Level: %u", adj->level); /* level */ vty_out (vty, ", State: %s", adj_state2string (adj->adj_state)); now = time (NULL); if (adj->last_upd) vty_out (vty, ", Expires in %s", time2string (adj->last_upd + adj->hold_time - now)); else vty_out (vty, ", Expires in %s", time2string (adj->hold_time)); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Adjacency flaps: %u", adj->flaps); vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap)); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t)); vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids)); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " SNPA: %s", snpa_print (adj->snpa)); if (adj->circuit && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) { dyn = dynhn_find_by_id (adj->lanid); if (dyn) vty_out (vty, ", LAN id: %s.%02x", dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]); else vty_out (vty, ", LAN id: %s.%02x", sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]); vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago", isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1]. dis), adj->dischanges[level - 1], time2string (now - (adj->dis_record[ISIS_LEVELS + level - 1]. last_dis_change))); } vty_out (vty, "%s", VTY_NEWLINE); if (adj->area_addrs && listcount (adj->area_addrs) > 0) { struct area_addr *area_addr; vty_out (vty, " Area Address(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr)) vty_out (vty, " %s%s", isonet_print (area_addr->area_addr, area_addr->addr_len), VTY_NEWLINE); } if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr)) vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE); } #ifdef HAVE_IPV6 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr)) { inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN); vty_out (vty, " %s%s", ip6, VTY_NEWLINE); } } #endif /* HAVE_IPV6 */ vty_out (vty, "%s", VTY_NEWLINE); } return; } void isis_adj_build_neigh_list (struct list *adjdb, struct list *list) { struct isis_adjacency *adj; struct listnode *node; if (!list) { zlog_warn ("isis_adj_build_neigh_list(): NULL list"); return; } for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) { if (!adj) { zlog_warn ("isis_adj_build_neigh_list(): NULL adj"); return; } if ((adj->adj_state == ISIS_ADJ_UP || adj->adj_state == ISIS_ADJ_INITIALIZING)) listnode_add (list, adj->snpa); } return; } void isis_adj_build_up_list (struct list *adjdb, struct list *list) { struct isis_adjacency *adj; struct listnode *node; if (adjdb == NULL) { zlog_warn ("isis_adj_build_up_list(): adjacency DB is empty"); return; } if (!list) { zlog_warn ("isis_adj_build_up_list(): NULL list"); return; } for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) { if (!adj) { zlog_warn ("isis_adj_build_up_list(): NULL adj"); return; } if (adj->adj_state == ISIS_ADJ_UP) listnode_add (list, adj); } return; } quagga-1.2.4/isisd/isis_adjacency.h000066400000000000000000000076271325323223500172330ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_adjacency.h * IS-IS adjacency handling * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_ADJACENCY_H #define _ZEBRA_ISIS_ADJACENCY_H enum isis_adj_usage { ISIS_ADJ_NONE, ISIS_ADJ_LEVEL1, ISIS_ADJ_LEVEL2, ISIS_ADJ_LEVEL1AND2 }; enum isis_system_type { ISIS_SYSTYPE_UNKNOWN, ISIS_SYSTYPE_ES, ISIS_SYSTYPE_IS, ISIS_SYSTYPE_L1_IS, ISIS_SYSTYPE_L2_IS }; enum isis_adj_state { ISIS_ADJ_UNKNOWN, ISIS_ADJ_INITIALIZING, ISIS_ADJ_UP, ISIS_ADJ_DOWN }; /* * we use the following codes to give an indication _why_ * a specific adjacency is up or down */ enum isis_adj_updown_reason { ISIS_ADJ_REASON_SEENSELF, ISIS_ADJ_REASON_AREA_MISMATCH, ISIS_ADJ_REASON_HOLDTIMER_EXPIRED, ISIS_ADJ_REASON_AUTH_FAILED, ISIS_ADJ_REASON_CHECKSUM_FAILED }; #define DIS_RECORDS 8 /* keep the last 8 DIS state changes on record */ struct isis_dis_record { int dis; /* is our neighbor the DIS ? */ time_t last_dis_change; /* timestamp for last dis change */ }; struct isis_adjacency { u_char snpa[ETH_ALEN]; /* NeighbourSNPAAddress */ u_char sysid[ISIS_SYS_ID_LEN]; /* neighbourSystemIdentifier */ u_char lanid[ISIS_SYS_ID_LEN + 1]; /* LAN id on bcast circuits */ int dischanges[ISIS_LEVELS]; /* how many DIS changes ? */ /* an array of N levels for M records */ struct isis_dis_record dis_record[DIS_RECORDS * ISIS_LEVELS]; enum isis_adj_state adj_state; /* adjacencyState */ enum isis_adj_usage adj_usage; /* adjacencyUsage */ struct list *area_addrs; /* areaAdressesOfNeighbour */ struct nlpids nlpids; /* protocols spoken ... */ struct list *ipv4_addrs; struct in_addr router_address; #ifdef HAVE_IPV6 struct list *ipv6_addrs; struct in6_addr router_address6; #endif /* HAVE_IPV6 */ u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */ int circuit_t; /* from hello PDU hdr */ int level; /* level (1 or 2) */ enum isis_system_type sys_type; /* neighbourSystemType */ u_int16_t hold_time; /* entryRemainingTime */ u_int32_t last_upd; u_int32_t last_flap; /* last time the adj flapped */ int flaps; /* number of adjacency flaps */ struct thread *t_expire; /* expire after hold_time */ struct isis_circuit *circuit; /* back pointer */ }; struct isis_adjacency *isis_adj_lookup (const u_char * sysid, struct list *adjdb); struct isis_adjacency *isis_adj_lookup_snpa (const u_char * ssnpa, struct list *adjdb); struct isis_adjacency *isis_new_adj (const u_char * id, const u_char * snpa, int level, struct isis_circuit *circuit); void isis_delete_adj (void *adj); void isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state, const char *reason); void isis_adj_print (struct isis_adjacency *adj); int isis_adj_expire (struct thread *thread); void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail); void isis_adj_build_neigh_list (struct list *adjdb, struct list *list); void isis_adj_build_up_list (struct list *adjdb, struct list *list); #endif /* ISIS_ADJACENCY_H */ quagga-1.2.4/isisd/isis_bpf.c000066400000000000000000000223401325323223500160410ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_bpf.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #if ISIS_METHOD == ISIS_METHOD_BPF #include #include #include #include #include #include "log.h" #include "network.h" #include "stream.h" #include "if.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_circuit.h" #include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_constants.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" #include "privs.h" extern struct zebra_privs_t isisd_privs; struct bpf_insn llcfilter[] = { BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN), /* check first byte */ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5), BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3), /* check second byte */ BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1), /* check third byte */ BPF_STMT (BPF_RET + BPF_K, (u_int) - 1), BPF_STMT (BPF_RET + BPF_K, 0) }; u_int readblen = 0; u_char *readbuff = NULL; /* * Table 9 - Architectural constants for use with ISO 8802 subnetworks * ISO 10589 - 8.4.8 */ u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 }; u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 }; u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 }; u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 }; static char sock_buff[8192]; static int open_bpf_dev (struct isis_circuit *circuit) { int i = 0, fd; char bpfdev[128]; struct ifreq ifr; u_int blen, immediate, seesent; struct timeval timeout; struct bpf_program bpf_prog; do { (void) snprintf (bpfdev, sizeof (bpfdev), "/dev/bpf%d", i++); fd = open (bpfdev, O_RDWR); } while (fd < 0 && errno == EBUSY); if (fd < 0) { zlog_warn ("open_bpf_dev(): failed to create bpf socket: %s", safe_strerror (errno)); return ISIS_WARNING; } zlog_debug ("Opened BPF device %s", bpfdev); memcpy (ifr.ifr_name, circuit->interface->name, sizeof (ifr.ifr_name)); if (ioctl (fd, BIOCSETIF, (caddr_t) & ifr) < 0) { zlog_warn ("open_bpf_dev(): failed to bind to interface: %s", safe_strerror (errno)); return ISIS_WARNING; } if (ioctl (fd, BIOCGBLEN, (caddr_t) & blen) < 0) { zlog_warn ("failed to get BPF buffer len"); blen = circuit->interface->mtu; } readblen = blen; if (readbuff == NULL) readbuff = malloc (blen); zlog_debug ("BPF buffer len = %u", blen); /* BPF(4): reads return immediately upon packet reception. * Otherwise, a read will block until either the kernel * buffer becomes full or a timeout occurs. */ immediate = 1; if (ioctl (fd, BIOCIMMEDIATE, (caddr_t) & immediate) < 0) { zlog_warn ("failed to set BPF dev to immediate mode"); } #ifdef BIOCSSEESENT /* * We want to see only incoming packets */ seesent = 0; if (ioctl (fd, BIOCSSEESENT, (caddr_t) & seesent) < 0) { zlog_warn ("failed to set BPF dev to incoming only mode"); } #endif /* * ...but all of them */ if (ioctl (fd, BIOCPROMISC) < 0) { zlog_warn ("failed to set BPF dev to promiscuous mode"); } /* * If the buffer length is smaller than our mtu, lets try to increase it */ if (blen < circuit->interface->mtu) { if (ioctl (fd, BIOCSBLEN, &circuit->interface->mtu) < 0) { zlog_warn ("failed to set BPF buffer len (%u to %u)", blen, circuit->interface->mtu); } } /* * Set a timeout parameter - hope this helps select() */ timeout.tv_sec = 600; timeout.tv_usec = 0; if (ioctl (fd, BIOCSRTIMEOUT, (caddr_t) & timeout) < 0) { zlog_warn ("failed to set BPF device timeout"); } /* * And set the filter */ memset (&bpf_prog, 0, sizeof (struct bpf_program)); bpf_prog.bf_len = 8; bpf_prog.bf_insns = &(llcfilter[0]); if (ioctl (fd, BIOCSETF, (caddr_t) & bpf_prog) < 0) { zlog_warn ("open_bpf_dev(): failed to install filter: %s", safe_strerror (errno)); return ISIS_WARNING; } assert (fd > 0); circuit->fd = fd; return ISIS_OK; } /* * Create the socket and set the tx/rx funcs */ int isis_sock_init (struct isis_circuit *circuit) { int retval = ISIS_OK; if (isisd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno)); retval = open_bpf_dev (circuit); if (retval != ISIS_OK) { zlog_warn ("%s: could not initialize the socket", __func__); goto end; } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { circuit->tx = isis_send_pdu_bcast; circuit->rx = isis_recv_pdu_bcast; } else if (circuit->circ_type == CIRCUIT_T_P2P) { circuit->tx = isis_send_pdu_p2p; circuit->rx = isis_recv_pdu_p2p; } else { zlog_warn ("isis_sock_init(): unknown circuit type"); retval = ISIS_WARNING; goto end; } end: if (isisd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno)); return retval; } int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) { int bytesread = 0, bytestoread, offset, one = 1; struct bpf_hdr *bpf_hdr; assert (circuit->fd > 0); if (ioctl (circuit->fd, FIONREAD, (caddr_t) & bytestoread) < 0) { zlog_warn ("ioctl() FIONREAD failed: %s", safe_strerror (errno)); } if (bytestoread) { bytesread = read (circuit->fd, readbuff, readblen); } if (bytesread < 0) { zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s", safe_strerror (errno)); return ISIS_WARNING; } if (bytesread == 0) return ISIS_WARNING; bpf_hdr = (struct bpf_hdr *) readbuff; assert (bpf_hdr->bh_caplen == bpf_hdr->bh_datalen); offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN; /* then we lose the BPF, LLC and ethernet headers */ stream_write (circuit->rcv_stream, readbuff + offset, bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN); stream_set_getp (circuit->rcv_stream, 0); memcpy (ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN, ETHER_ADDR_LEN); if (ioctl (circuit->fd, BIOCFLUSH, &one) < 0) zlog_warn ("Flushing failed: %s", safe_strerror (errno)); return ISIS_OK; } int isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa) { int bytesread; bytesread = stream_read (circuit->rcv_stream, circuit->fd, circuit->interface->mtu); if (bytesread < 0) { zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno)); return ISIS_WARNING; } return ISIS_OK; } int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { struct ether_header *eth; ssize_t written; size_t buflen; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN; if (buflen > sizeof (sock_buff)) { zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than " "output pdu size %zu on circuit %s", sizeof (sock_buff), buflen, circuit->interface->name); return ISIS_WARNING; } stream_set_getp (circuit->snd_stream, 0); /* * First the eth header */ eth = (struct ether_header *) sock_buff; if (level == 1) memcpy (eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN); else memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN); memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN); eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); /* * Then the LLC */ sock_buff[ETHER_HDR_LEN] = ISO_SAP; sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP; sock_buff[ETHER_HDR_LEN + 2] = 0x03; /* then we copy the data */ memcpy (sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data, stream_get_endp (circuit->snd_stream)); /* now we can send this */ written = write (circuit->fd, sock_buff, buflen); if (written < 0) { zlog_warn("IS-IS bpf: could not transmit packet on %s: %s", circuit->interface->name, safe_strerror(errno)); if (ERRNO_IO_RETRY(errno)) return ISIS_WARNING; return ISIS_ERROR; } return ISIS_OK; } int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_BPF */ quagga-1.2.4/isisd/isis_circuit.c000066400000000000000000001177071325323223500167500ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_circuit.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #ifdef GNU_LINUX #include #else #include #endif #ifndef ETHER_ADDR_LEN #define ETHER_ADDR_LEN ETHERADDRL #endif #include "log.h" #include "memory.h" #include "if.h" #include "linklist.h" #include "command.h" #include "thread.h" #include "vty.h" #include "hash.h" #include "prefix.h" #include "stream.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" #include "isisd/isis_te.h" /* * Prototypes. */ int isis_interface_config_write(struct vty *); int isis_if_new_hook(struct interface *); int isis_if_delete_hook(struct interface *); struct isis_circuit * isis_circuit_new () { struct isis_circuit *circuit; int i; circuit = XCALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit)); if (circuit == NULL) { zlog_err ("Can't malloc isis circuit"); return NULL; } /* * Default values */ circuit->is_type = IS_LEVEL_1_AND_2; circuit->flags = 0; circuit->pad_hellos = 1; for (i = 0; i < 2; i++) { circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL; circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER; circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL; circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL; circuit->priority[i] = DEFAULT_PRIORITY; circuit->metric[i] = DEFAULT_CIRCUIT_METRIC; circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; } circuit->mtc = mpls_te_circuit_new(); return circuit; } void isis_circuit_del (struct isis_circuit *circuit) { if (!circuit) return; isis_circuit_if_unbind (circuit, circuit->interface); /* and lastly the circuit itself */ XFREE (MTYPE_ISIS_CIRCUIT, circuit); return; } void isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area) { assert (area); circuit->area = area; /* * Whenever the is-type of an area is changed, the is-type of each circuit * in that area is updated to a non-empty subset of the area is-type. * Inversely, when configuring a new circuit, this property should be * ensured as well. */ if (area->is_type != IS_LEVEL_1_AND_2) circuit->is_type = area->is_type; /* * Add the circuit into area */ listnode_add (area->circuit_list, circuit); circuit->idx = flags_get_index (&area->flags); return; } void isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area) { /* Free the index of SRM and SSN flags */ flags_free_index (&area->flags, circuit->idx); circuit->idx = 0; /* Remove circuit from area */ assert (circuit->area == area); listnode_delete (area->circuit_list, circuit); circuit->area = NULL; return; } struct isis_circuit * circuit_lookup_by_ifp (struct interface *ifp, struct list *list) { struct isis_circuit *circuit = NULL; struct listnode *node; if (!list) return NULL; for (ALL_LIST_ELEMENTS_RO (list, node, circuit)) if (circuit->interface == ifp) { assert (ifp->info == circuit); return circuit; } return NULL; } struct isis_circuit * circuit_scan_by_ifp (struct interface *ifp) { struct isis_area *area; struct listnode *node; struct isis_circuit *circuit; if (ifp->info) return (struct isis_circuit *)ifp->info; if (isis->area_list) { for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); if (circuit) return circuit; } } return circuit_lookup_by_ifp (ifp, isis->init_circ_list); } void isis_circuit_add_addr (struct isis_circuit *circuit, struct connected *connected) { struct listnode *node; struct prefix_ipv4 *ipv4; u_char buf[BUFSIZ]; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6; #endif /* HAVE_IPV6 */ memset (&buf, 0, BUFSIZ); if (connected->address->family == AF_INET) { u_int32_t addr = connected->address->u.prefix4.s_addr; addr = ntohl (addr); if (IPV4_NET0(addr) || IPV4_NET127(addr) || IN_CLASSD(addr) || IPV4_LINKLOCAL(addr)) return; for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ipv4)) if (prefix_same ((struct prefix *) ipv4, connected->address)) return; ipv4 = prefix_ipv4_new (); ipv4->prefixlen = connected->address->prefixlen; ipv4->prefix = connected->address->u.prefix4; listnode_add (circuit->ip_addrs, ipv4); /* Update MPLS TE Local IP address parameter */ set_circuitparams_local_ipaddr (circuit->mtc, ipv4->prefix); if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); #ifdef EXTREME_DEBUG prefix2str (connected->address, buf, BUFSIZ); zlog_debug ("Added IP address %s to circuit %d", buf, circuit->circuit_id); #endif /* EXTREME_DEBUG */ } #ifdef HAVE_IPV6 if (connected->address->family == AF_INET6) { if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6)) return; for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ipv6)) if (prefix_same ((struct prefix *) ipv6, connected->address)) return; for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ipv6)) if (prefix_same ((struct prefix *) ipv6, connected->address)) return; ipv6 = prefix_ipv6_new (); ipv6->prefixlen = connected->address->prefixlen; ipv6->prefix = connected->address->u.prefix6; if (IN6_IS_ADDR_LINKLOCAL (&ipv6->prefix)) listnode_add (circuit->ipv6_link, ipv6); else listnode_add (circuit->ipv6_non_link, ipv6); if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); #ifdef EXTREME_DEBUG prefix2str (connected->address, buf, BUFSIZ); zlog_debug ("Added IPv6 address %s to circuit %d", buf, circuit->circuit_id); #endif /* EXTREME_DEBUG */ } #endif /* HAVE_IPV6 */ return; } void isis_circuit_del_addr (struct isis_circuit *circuit, struct connected *connected) { struct prefix_ipv4 *ipv4, *ip = NULL; struct listnode *node; u_char buf[BUFSIZ]; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6, *ip6 = NULL; int found = 0; #endif /* HAVE_IPV6 */ memset (&buf, 0, BUFSIZ); if (connected->address->family == AF_INET) { ipv4 = prefix_ipv4_new (); ipv4->prefixlen = connected->address->prefixlen; ipv4->prefix = connected->address->u.prefix4; for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip)) if (prefix_same ((struct prefix *) ip, (struct prefix *) ipv4)) break; if (ip) { listnode_delete (circuit->ip_addrs, ip); if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); } else { prefix2str (connected->address, (char *)buf, BUFSIZ); zlog_warn ("Nonexitant ip address %s removal attempt from \ circuit %d", buf, circuit->circuit_id); zlog_warn ("Current ip addresses on %s:", circuit->interface->name); for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip)) { prefix2str((struct prefix*)ip, (char *)buf, BUFSIZ); zlog_warn(" %s", buf); } zlog_warn("End of addresses"); } prefix_ipv4_free (ipv4); } #ifdef HAVE_IPV6 if (connected->address->family == AF_INET6) { ipv6 = prefix_ipv6_new (); ipv6->prefixlen = connected->address->prefixlen; ipv6->prefix = connected->address->u.prefix6; if (IN6_IS_ADDR_LINKLOCAL (&ipv6->prefix)) { for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ip6)) { if (prefix_same ((struct prefix *) ip6, (struct prefix *) ipv6)) break; } if (ip6) { listnode_delete (circuit->ipv6_link, ip6); found = 1; } } else { for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ip6)) { if (prefix_same ((struct prefix *) ip6, (struct prefix *) ipv6)) break; } if (ip6) { listnode_delete (circuit->ipv6_non_link, ip6); found = 1; } } if (!found) { prefix2str (connected->address, (char *)buf, BUFSIZ); zlog_warn ("Nonexitant ip address %s removal attempt from \ circuit %d", buf, circuit->circuit_id); zlog_warn ("Current ip addresses on %s:", circuit->interface->name); for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip6)) { prefix2str((struct prefix*)ip6, (char *)buf, BUFSIZ); zlog_warn(" %s", buf); } zlog_warn(" -----"); for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip6)) { prefix2str((struct prefix*)ip6, (char *)buf, BUFSIZ); zlog_warn(" %s", buf); } zlog_warn("End of addresses"); } else if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); prefix_ipv6_free (ipv6); } #endif /* HAVE_IPV6 */ return; } static u_char isis_circuit_id_gen (struct interface *ifp) { u_char id = 0; char ifname[16]; unsigned int i; int start = -1, end = -1; /* * Get a stable circuit id from ifname. This makes * the ifindex from flapping when netdevs are created * and deleted on the fly. Note that this circuit id * is used in pseudo lsps so it is better to be stable. * The following code works on any reasonanle ifname * like: eth1 or trk-1.1 etc. */ for (i = 0; i < strlen (ifp->name); i++) { if (isdigit((unsigned char)ifp->name[i])) { if (start < 0) { start = i; end = i + 1; } else { end = i + 1; } } else if (start >= 0) break; } if ((start >= 0) && (end >= start) && (end - start) < 16) { memset (ifname, 0, 16); strncpy (ifname, &ifp->name[start], end - start); id = (u_char)atoi(ifname); } /* Try to be unique. */ if (!id) id = (u_char)((ifp->ifindex & 0xff) | 0x80); return id; } void isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp) { struct listnode *node, *nnode; struct connected *conn; circuit->circuit_id = isis_circuit_id_gen (ifp); isis_circuit_if_bind (circuit, ifp); /* isis_circuit_update_addrs (circuit, ifp); */ if (if_is_broadcast (ifp)) { if (circuit->circ_type_config == CIRCUIT_T_P2P) circuit->circ_type = CIRCUIT_T_P2P; else circuit->circ_type = CIRCUIT_T_BROADCAST; } else if (if_is_pointopoint (ifp)) { circuit->circ_type = CIRCUIT_T_P2P; } else if (if_is_loopback (ifp)) { circuit->circ_type = CIRCUIT_T_LOOPBACK; circuit->is_passive = 1; } else { /* It's normal in case of loopback etc. */ if (isis->debugs & DEBUG_EVENTS) zlog_debug ("isis_circuit_if_add: unsupported media"); circuit->circ_type = CIRCUIT_T_UNKNOWN; } circuit->ip_addrs = list_new (); #ifdef HAVE_IPV6 circuit->ipv6_link = list_new (); circuit->ipv6_non_link = list_new (); #endif /* HAVE_IPV6 */ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn)) isis_circuit_add_addr (circuit, conn); return; } void isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp) { struct listnode *node, *nnode; struct connected *conn; assert (circuit->interface == ifp); /* destroy addresses */ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn)) isis_circuit_del_addr (circuit, conn); if (circuit->ip_addrs) { assert (listcount(circuit->ip_addrs) == 0); list_delete (circuit->ip_addrs); circuit->ip_addrs = NULL; } #ifdef HAVE_IPV6 if (circuit->ipv6_link) { assert (listcount(circuit->ipv6_link) == 0); list_delete (circuit->ipv6_link); circuit->ipv6_link = NULL; } if (circuit->ipv6_non_link) { assert (listcount(circuit->ipv6_non_link) == 0); list_delete (circuit->ipv6_non_link); circuit->ipv6_non_link = NULL; } #endif /* HAVE_IPV6 */ circuit->circ_type = CIRCUIT_T_UNKNOWN; circuit->circuit_id = 0; return; } void isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp) { assert (circuit != NULL); assert (ifp != NULL); if (circuit->interface) assert (circuit->interface == ifp); else circuit->interface = ifp; if (ifp->info) assert (ifp->info == circuit); else ifp->info = circuit; isis_link_params_update (circuit, ifp); } void isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp) { assert (circuit != NULL); assert (ifp != NULL); assert (circuit->interface == ifp); assert (ifp->info == circuit); circuit->interface = NULL; ifp->info = NULL; } static void isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set) { struct isis_area *area; struct isis_lsp *lsp; dnode_t *dnode, *dnode_next; int level; assert (circuit); area = circuit->area; assert (area); for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { if (level & circuit->is_type) { if (area->lspdb[level - 1] && dict_count (area->lspdb[level - 1]) > 0) { for (dnode = dict_first (area->lspdb[level - 1]); dnode != NULL; dnode = dnode_next) { dnode_next = dict_next (area->lspdb[level - 1], dnode); lsp = dnode_get (dnode); if (is_set) { ISIS_SET_FLAG (lsp->SRMflags, circuit); } else { ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } } } } } } size_t isis_circuit_pdu_size(struct isis_circuit *circuit) { return ISO_MTU(circuit); } void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream) { size_t stream_size = isis_circuit_pdu_size(circuit); if (!*stream) { *stream = stream_new(stream_size); } else { if (STREAM_SIZE(*stream) != stream_size) stream_resize(*stream, stream_size); stream_reset(*stream); } } int isis_circuit_up (struct isis_circuit *circuit) { int retv; /* Set the flags for all the lsps of the circuit. */ isis_circuit_update_all_srmflags (circuit, 1); if (circuit->state == C_STATE_UP) return ISIS_OK; if (circuit->is_passive) return ISIS_OK; if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) { zlog_err("Interface MTU %zu on %s is too low to support area lsp mtu %u!", isis_circuit_pdu_size(circuit), circuit->interface->name, circuit->area->lsp_mtu); isis_circuit_update_all_srmflags(circuit, 0); return ISIS_ERROR; } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { /* * Get the Hardware Address */ if (circuit->interface->hw_addr_len != ETH_ALEN) { zlog_warn ("unsupported link layer"); } else { memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN); } #ifdef EXTREME_DEGUG zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s", circuit->interface->ifindex, ISO_MTU (circuit), snpa_print (circuit->u.bc.snpa)); #endif /* EXTREME_DEBUG */ circuit->u.bc.adjdb[0] = list_new (); circuit->u.bc.adjdb[1] = list_new (); /* * ISO 10589 - 8.4.1 Enabling of broadcast circuits */ /* initilizing the hello sending threads * for a broadcast IF */ /* 8.4.1 a) commence sending of IIH PDUs */ if (circuit->is_type & IS_LEVEL_1) { thread_add_event (master, send_lan_l1_hello, circuit, 0); circuit->u.bc.lan_neighs[0] = list_new (); } if (circuit->is_type & IS_LEVEL_2) { thread_add_event (master, send_lan_l2_hello, circuit, 0); circuit->u.bc.lan_neighs[1] = list_new (); } /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */ /* 8.4.1 c) FIXME: listen for ESH PDUs */ /* 8.4.1 d) */ /* dr election will commence in... */ if (circuit->is_type & IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); if (circuit->is_type & IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); } else { /* initializing the hello send threads * for a ptp IF */ circuit->u.p2p.neighbor = NULL; thread_add_event (master, send_p2p_hello, circuit, 0); } /* initializing PSNP timers */ if (circuit->is_type & IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); if (circuit->is_type & IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); /* unified init for circuits; ignore warnings below this level */ retv = isis_sock_init (circuit); if (retv != ISIS_OK) { isis_circuit_down (circuit); return retv; } /* initialize the circuit streams after opening connection */ isis_circuit_stream(circuit, &circuit->rcv_stream); isis_circuit_stream(circuit, &circuit->snd_stream); #ifdef GNU_LINUX THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit, circuit->fd); #else THREAD_TIMER_ON (master, circuit->t_read, isis_receive, circuit, circuit->fd); #endif circuit->lsp_queue = list_new (); circuit->lsp_queue_last_cleared = time (NULL); return ISIS_OK; } void isis_circuit_down (struct isis_circuit *circuit) { if (circuit->state != C_STATE_UP) return; /* Clear the flags for all the lsps of the circuit. */ isis_circuit_update_all_srmflags (circuit, 0); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { /* destroy neighbour lists */ if (circuit->u.bc.lan_neighs[0]) { list_delete (circuit->u.bc.lan_neighs[0]); circuit->u.bc.lan_neighs[0] = NULL; } if (circuit->u.bc.lan_neighs[1]) { list_delete (circuit->u.bc.lan_neighs[1]); circuit->u.bc.lan_neighs[1] = NULL; } /* destroy adjacency databases */ if (circuit->u.bc.adjdb[0]) { circuit->u.bc.adjdb[0]->del = isis_delete_adj; list_delete (circuit->u.bc.adjdb[0]); circuit->u.bc.adjdb[0] = NULL; } if (circuit->u.bc.adjdb[1]) { circuit->u.bc.adjdb[1]->del = isis_delete_adj; list_delete (circuit->u.bc.adjdb[1]); circuit->u.bc.adjdb[1] = NULL; } if (circuit->u.bc.is_dr[0]) { isis_dr_resign (circuit, 1); circuit->u.bc.is_dr[0] = 0; } memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1); if (circuit->u.bc.is_dr[1]) { isis_dr_resign (circuit, 2); circuit->u.bc.is_dr[1] = 0; } memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1); memset (circuit->u.bc.snpa, 0, ETH_ALEN); THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]); THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]); circuit->lsp_regenerate_pending[0] = 0; circuit->lsp_regenerate_pending[1] = 0; } else if (circuit->circ_type == CIRCUIT_T_P2P) { isis_delete_adj (circuit->u.p2p.neighbor); circuit->u.p2p.neighbor = NULL; THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello); } /* Cancel all active threads */ THREAD_TIMER_OFF (circuit->t_send_csnp[0]); THREAD_TIMER_OFF (circuit->t_send_csnp[1]); THREAD_TIMER_OFF (circuit->t_send_psnp[0]); THREAD_TIMER_OFF (circuit->t_send_psnp[1]); THREAD_OFF (circuit->t_read); if (circuit->lsp_queue) { circuit->lsp_queue->del = NULL; list_delete (circuit->lsp_queue); circuit->lsp_queue = NULL; } /* send one gratuitous hello to spead up convergence */ if (circuit->is_type & IS_LEVEL_1) send_hello (circuit, IS_LEVEL_1); if (circuit->is_type & IS_LEVEL_2) send_hello (circuit, IS_LEVEL_2); circuit->upadjcount[0] = 0; circuit->upadjcount[1] = 0; /* close the socket */ if (circuit->fd) { close (circuit->fd); circuit->fd = 0; } if (circuit->rcv_stream != NULL) { stream_free (circuit->rcv_stream); circuit->rcv_stream = NULL; } if (circuit->snd_stream != NULL) { stream_free (circuit->snd_stream); circuit->snd_stream = NULL; } thread_cancel_event (master, circuit); return; } void circuit_update_nlpids (struct isis_circuit *circuit) { circuit->nlpids.count = 0; if (circuit->ip_router) { circuit->nlpids.nlpids[0] = NLPID_IP; circuit->nlpids.count++; } #ifdef HAVE_IPV6 if (circuit->ipv6_router) { circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6; circuit->nlpids.count++; } #endif /* HAVE_IPV6 */ return; } void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, char detail) { if (detail == ISIS_UI_LEVEL_BRIEF) { vty_out (vty, " %-12s", circuit->interface->name); vty_out (vty, "0x%-7x", circuit->circuit_id); vty_out (vty, "%-9s", circuit_state2string (circuit->state)); vty_out (vty, "%-9s", circuit_type2string (circuit->circ_type)); vty_out (vty, "%-9s", circuit_t2string (circuit->is_type)); vty_out (vty, "%s", VTY_NEWLINE); } if (detail == ISIS_UI_LEVEL_DETAIL) { struct listnode *node; struct prefix *ip_addr; u_char buf[BUFSIZ]; vty_out (vty, " Interface: %s", circuit->interface->name); vty_out (vty, ", State: %s", circuit_state2string (circuit->state)); if (circuit->is_passive) vty_out (vty, ", Passive"); else vty_out (vty, ", Active"); vty_out (vty, ", Circuit Id: 0x%x", circuit->circuit_id); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Type: %s", circuit_type2string (circuit->circ_type)); vty_out (vty, ", Level: %s", circuit_t2string (circuit->is_type)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) vty_out (vty, ", SNPA: %-10s", snpa_print (circuit->u.bc.snpa)); vty_out (vty, "%s", VTY_NEWLINE); if (circuit->is_type & IS_LEVEL_1) { vty_out (vty, " Level-1 Information:%s", VTY_NEWLINE); if (circuit->area->newmetric) vty_out (vty, " Metric: %d", circuit->te_metric[0]); else vty_out (vty, " Metric: %d", circuit->metric[0]); if (!circuit->is_passive) { vty_out (vty, ", Active neighbors: %u%s", circuit->upadjcount[0], VTY_NEWLINE); vty_out (vty, " Hello interval: %u, " "Holddown count: %u %s%s", circuit->hello_interval[0], circuit->hello_multiplier[0], (circuit->pad_hellos ? "(pad)" : "(no-pad)"), VTY_NEWLINE); vty_out (vty, " CNSP interval: %u, " "PSNP interval: %u%s", circuit->csnp_interval[0], circuit->psnp_interval[0], VTY_NEWLINE); if (circuit->circ_type == CIRCUIT_T_BROADCAST) vty_out (vty, " LAN Priority: %u, %s%s", circuit->priority[0], (circuit->u.bc.is_dr[0] ? \ "is DIS" : "is not DIS"), VTY_NEWLINE); } else { vty_out (vty, "%s", VTY_NEWLINE); } } if (circuit->is_type & IS_LEVEL_2) { vty_out (vty, " Level-2 Information:%s", VTY_NEWLINE); if (circuit->area->newmetric) vty_out (vty, " Metric: %d", circuit->te_metric[1]); else vty_out (vty, " Metric: %d", circuit->metric[1]); if (!circuit->is_passive) { vty_out (vty, ", Active neighbors: %u%s", circuit->upadjcount[1], VTY_NEWLINE); vty_out (vty, " Hello interval: %u, " "Holddown count: %u %s%s", circuit->hello_interval[1], circuit->hello_multiplier[1], (circuit->pad_hellos ? "(pad)" : "(no-pad)"), VTY_NEWLINE); vty_out (vty, " CNSP interval: %u, " "PSNP interval: %u%s", circuit->csnp_interval[1], circuit->psnp_interval[1], VTY_NEWLINE); if (circuit->circ_type == CIRCUIT_T_BROADCAST) vty_out (vty, " LAN Priority: %u, %s%s", circuit->priority[1], (circuit->u.bc.is_dr[1] ? \ "is DIS" : "is not DIS"), VTY_NEWLINE); } else { vty_out (vty, "%s", VTY_NEWLINE); } } if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0) { vty_out (vty, " IP Prefix(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr)) { prefix2str (ip_addr, (char*)buf, BUFSIZ), vty_out (vty, " %s%s", buf, VTY_NEWLINE); } } if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0) { vty_out(vty, " IPv6 Link-Locals:%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip_addr)) { prefix2str(ip_addr, (char*)buf, BUFSIZ), vty_out(vty, " %s%s", buf, VTY_NEWLINE); } } if (circuit->ipv6_non_link && listcount(circuit->ipv6_non_link) > 0) { vty_out(vty, " IPv6 Prefixes:%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip_addr)) { prefix2str(ip_addr, (char*)buf, BUFSIZ), vty_out(vty, " %s%s", buf, VTY_NEWLINE); } } vty_out (vty, "%s", VTY_NEWLINE); } return; } int isis_interface_config_write (struct vty *vty) { int write = 0; struct listnode *node, *node2; struct interface *ifp; struct isis_area *area; struct isis_circuit *circuit; int i; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { /* IF name */ vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); write++; /* IF desc */ if (ifp->desc) { vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); write++; } /* ISIS Circuit */ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area)) { circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); if (circuit == NULL) continue; if (circuit->ip_router) { vty_out (vty, " ip router isis %s%s", area->area_tag, VTY_NEWLINE); write++; } if (circuit->is_passive) { vty_out (vty, " isis passive%s", VTY_NEWLINE); write++; } if (circuit->circ_type_config == CIRCUIT_T_P2P) { vty_out (vty, " isis network point-to-point%s", VTY_NEWLINE); write++; } #ifdef HAVE_IPV6 if (circuit->ipv6_router) { vty_out (vty, " ipv6 router isis %s%s", area->area_tag, VTY_NEWLINE); write++; } #endif /* HAVE_IPV6 */ /* ISIS - circuit type */ if (circuit->is_type == IS_LEVEL_1) { vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE); write++; } else { if (circuit->is_type == IS_LEVEL_2) { vty_out (vty, " isis circuit-type level-2-only%s", VTY_NEWLINE); write++; } } /* ISIS - CSNP interval */ if (circuit->csnp_interval[0] == circuit->csnp_interval[1]) { if (circuit->csnp_interval[0] != DEFAULT_CSNP_INTERVAL) { vty_out (vty, " isis csnp-interval %d%s", circuit->csnp_interval[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->csnp_interval[i] != DEFAULT_CSNP_INTERVAL) { vty_out (vty, " isis csnp-interval %d level-%d%s", circuit->csnp_interval[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - PSNP interval */ if (circuit->psnp_interval[0] == circuit->psnp_interval[1]) { if (circuit->psnp_interval[0] != DEFAULT_PSNP_INTERVAL) { vty_out (vty, " isis psnp-interval %d%s", circuit->psnp_interval[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->psnp_interval[i] != DEFAULT_PSNP_INTERVAL) { vty_out (vty, " isis psnp-interval %d level-%d%s", circuit->psnp_interval[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - Hello padding - Defaults to true so only display if false */ if (circuit->pad_hellos == 0) { vty_out (vty, " no isis hello padding%s", VTY_NEWLINE); write++; } /* ISIS - Hello interval */ if (circuit->hello_interval[0] == circuit->hello_interval[1]) { if (circuit->hello_interval[0] != DEFAULT_HELLO_INTERVAL) { vty_out (vty, " isis hello-interval %d%s", circuit->hello_interval[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->hello_interval[i] != DEFAULT_HELLO_INTERVAL) { vty_out (vty, " isis hello-interval %d level-%d%s", circuit->hello_interval[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - Hello Multiplier */ if (circuit->hello_multiplier[0] == circuit->hello_multiplier[1]) { if (circuit->hello_multiplier[0] != DEFAULT_HELLO_MULTIPLIER) { vty_out (vty, " isis hello-multiplier %d%s", circuit->hello_multiplier[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->hello_multiplier[i] != DEFAULT_HELLO_MULTIPLIER) { vty_out (vty, " isis hello-multiplier %d level-%d%s", circuit->hello_multiplier[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - Priority */ if (circuit->priority[0] == circuit->priority[1]) { if (circuit->priority[0] != DEFAULT_PRIORITY) { vty_out (vty, " isis priority %d%s", circuit->priority[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->priority[i] != DEFAULT_PRIORITY) { vty_out (vty, " isis priority %d level-%d%s", circuit->priority[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - Metric */ if (circuit->te_metric[0] == circuit->te_metric[1]) { if (circuit->te_metric[0] != DEFAULT_CIRCUIT_METRIC) { vty_out (vty, " isis metric %d%s", circuit->te_metric[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->te_metric[i] != DEFAULT_CIRCUIT_METRIC) { vty_out (vty, " isis metric %d level-%d%s", circuit->te_metric[i], i + 1, VTY_NEWLINE); write++; } } } if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { vty_out (vty, " isis password md5 %s%s", circuit->passwd.passwd, VTY_NEWLINE); write++; } else if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) { vty_out (vty, " isis password clear %s%s", circuit->passwd.passwd, VTY_NEWLINE); write++; } } vty_out (vty, "!%s", VTY_NEWLINE); } return write; } struct isis_circuit * isis_circuit_create (struct isis_area *area, struct interface *ifp) { struct isis_circuit *circuit = circuit_scan_by_ifp (ifp); if (circuit && circuit->area) return NULL; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) return circuit; isis_circuit_if_bind (circuit, ifp); return circuit; } void isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router) { struct isis_area *area = circuit->area; bool change = circuit->ip_router != ip_router || circuit->ipv6_router != ipv6_router; bool was_enabled = !!circuit->area; area->ip_circuits += ip_router - circuit->ip_router; area->ipv6_circuits += ipv6_router - circuit->ipv6_router; circuit->ip_router = ip_router; circuit->ipv6_router = ipv6_router; if (!change) return; circuit_update_nlpids (circuit); if (!ip_router && !ipv6_router) isis_csm_state_change (ISIS_DISABLE, circuit, area); else if (!was_enabled) isis_csm_state_change (ISIS_ENABLE, circuit, area); else lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); } int isis_circuit_passive_set (struct isis_circuit *circuit, bool passive) { if (circuit->is_passive == passive) return 0; if (if_is_loopback (circuit->interface) && !passive) return -1; if (circuit->state != C_STATE_UP) { circuit->is_passive = passive; } else { struct isis_area *area = circuit->area; isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->is_passive = passive; isis_csm_state_change (ISIS_ENABLE, circuit, area); } return 0; } int isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric) { assert (level == IS_LEVEL_1 || level == IS_LEVEL_2); if (metric > MAX_WIDE_LINK_METRIC) return -1; if (circuit->area && circuit->area->oldmetric && metric > MAX_NARROW_LINK_METRIC) return -1; circuit->te_metric[level - 1] = metric; circuit->metric[level - 1] = metric; if (circuit->area) lsp_regenerate_schedule (circuit->area, level, 0); return 0; } int isis_circuit_passwd_unset (struct isis_circuit *circuit) { memset(&circuit->passwd, 0, sizeof(circuit->passwd)); return 0; } static int isis_circuit_passwd_set (struct isis_circuit *circuit, u_char passwd_type, const char *passwd) { int len; if (!passwd) return -1; len = strlen(passwd); if (len > 254) return -1; circuit->passwd.len = len; strncpy((char *)circuit->passwd.passwd, passwd, 255); circuit->passwd.type = passwd_type; return 0; } int isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd) { return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_CLEARTXT, passwd); } int isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd) { return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_HMAC_MD5, passwd); } struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1, }; int isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) { /* Changing the network type to/of loopback or unknown interfaces * is not supported. */ if (circ_type == CIRCUIT_T_UNKNOWN || circ_type == CIRCUIT_T_LOOPBACK || circuit->circ_type == CIRCUIT_T_LOOPBACK) { if (circuit->circ_type != circ_type) return -1; else return 0; } if (circuit->circ_type == circ_type) return 0; if (circuit->state != C_STATE_UP) { circuit->circ_type = circ_type; circuit->circ_type_config = circ_type; } else { struct isis_area *area = circuit->area; if (circ_type == CIRCUIT_T_BROADCAST && !if_is_broadcast(circuit->interface)) return -1; isis_csm_state_change(ISIS_DISABLE, circuit, area); circuit->circ_type = circ_type; circuit->circ_type_config = circ_type; isis_csm_state_change(ISIS_ENABLE, circuit, area); } return 0; } int isis_if_new_hook (struct interface *ifp) { return 0; } int isis_if_delete_hook (struct interface *ifp) { struct isis_circuit *circuit; /* Clean up the circuit data */ if (ifp && ifp->info) { circuit = ifp->info; isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area); isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area); } return 0; } void isis_circuit_init () { /* Initialize Zebra interface data structure */ if_add_hook (IF_NEW_HOOK, isis_if_new_hook); if_add_hook (IF_DELETE_HOOK, isis_if_delete_hook); /* Install interface node */ install_node (&interface_node, isis_interface_config_write); install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); isis_vty_init (); } quagga-1.2.4/isisd/isis_circuit.h000066400000000000000000000163021325323223500167420ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_circuit.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef ISIS_CIRCUIT_H #define ISIS_CIRCUIT_H #include "vty.h" #include "if.h" #include "isis_constants.h" #include "isis_common.h" #define CIRCUIT_MAX 255 struct password { struct password *next; int len; u_char *pass; }; struct metric { u_char metric_default; u_char metric_error; u_char metric_expense; u_char metric_delay; }; struct isis_bcast_info { u_char snpa[ETH_ALEN]; /* SNPA of this circuit */ char run_dr_elect[2]; /* Should we run dr election ? */ struct thread *t_run_dr[2]; /* DR election thread */ struct thread *t_send_lan_hello[2]; /* send LAN IIHs in this thread */ struct list *adjdb[2]; /* adjacency dbs */ struct list *lan_neighs[2]; /* list of lx neigh snpa */ char is_dr[2]; /* Are we level x DR ? */ u_char l1_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-1 DR */ u_char l2_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-2 DR */ struct thread *t_refresh_pseudo_lsp[2]; /* refresh pseudo-node LSPs */ }; struct isis_p2p_info { struct isis_adjacency *neighbor; struct thread *t_send_p2p_hello; /* send P2P IIHs in this thread */ }; struct isis_circuit { int state; u_char circuit_id; /* l1/l2 p2p/bcast CircuitID */ struct isis_area *area; /* back pointer to the area */ struct interface *interface; /* interface info from z */ int fd; /* IS-IS l1/2 socket */ int sap_length; /* SAP length for DLPI */ struct nlpids nlpids; /* * Threads */ struct thread *t_read; struct thread *t_send_csnp[2]; struct thread *t_send_psnp[2]; struct list *lsp_queue; /* LSPs to be txed (both levels) */ time_t lsp_queue_last_cleared;/* timestamp used to enforce transmit interval; * for scalability, use one timestamp per * circuit, instead of one per lsp per circuit */ /* there is no real point in two streams, just for programming kicker */ int (*rx) (struct isis_circuit * circuit, u_char * ssnpa); struct stream *rcv_stream; /* Stream for receiving */ int (*tx) (struct isis_circuit * circuit, int level); struct stream *snd_stream; /* Stream for sending */ int idx; /* idx in S[RM|SN] flags */ #define CIRCUIT_T_UNKNOWN 0 #define CIRCUIT_T_BROADCAST 1 #define CIRCUIT_T_P2P 2 #define CIRCUIT_T_LOOPBACK 3 int circ_type; /* type of the physical interface */ int circ_type_config; /* config type of the physical interface */ union { struct isis_bcast_info bc; struct isis_p2p_info p2p; } u; u_char priority[2]; /* l1/2 IS configured priority */ int pad_hellos; /* add padding to Hello PDUs ? */ char ext_domain; /* externalDomain (boolean) */ int lsp_regenerate_pending[ISIS_LEVELS]; /* * Configurables */ struct isis_passwd passwd; /* Circuit rx/tx password */ int is_type; /* circuit is type == level of circuit * differentiated from circuit type (media) */ u_int32_t hello_interval[2]; /* l1HelloInterval in msecs */ u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */ u_int16_t csnp_interval[2]; /* level-1 csnp-interval in seconds */ u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */ u_int8_t metric[2]; u_int32_t te_metric[2]; struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */ int ip_router; /* Route IP ? */ int is_passive; /* Is Passive ? */ struct list *ip_addrs; /* our IP addresses */ #ifdef HAVE_IPV6 int ipv6_router; /* Route IPv6 ? */ struct list *ipv6_link; /* our link local IPv6 addresses */ struct list *ipv6_non_link; /* our non-link local IPv6 addresses */ #endif /* HAVE_IPV6 */ u_int16_t upadjcount[2]; #define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01 u_char flags; /* * Counters as in 10589--11.2.5.9 */ u_int32_t adj_state_changes; /* changesInAdjacencyState */ u_int32_t init_failures; /* intialisationFailures */ u_int32_t ctrl_pdus_rxed; /* controlPDUsReceived */ u_int32_t ctrl_pdus_txed; /* controlPDUsSent */ u_int32_t desig_changes[2]; /* lanLxDesignatedIntermediateSystemChanges */ u_int32_t rej_adjacencies; /* rejectedAdjacencies */ }; void isis_circuit_init (void); struct isis_circuit *isis_circuit_new (void); void isis_circuit_del (struct isis_circuit *circuit); struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp, struct list *list); struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp); void isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area); void isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area); void isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp); void isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp); void isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp); void isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp); void isis_circuit_add_addr (struct isis_circuit *circuit, struct connected *conn); void isis_circuit_del_addr (struct isis_circuit *circuit, struct connected *conn); int isis_circuit_up (struct isis_circuit *circuit); void isis_circuit_down (struct isis_circuit *); void circuit_update_nlpids (struct isis_circuit *circuit); void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, char detail); size_t isis_circuit_pdu_size(struct isis_circuit *circuit); void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream); struct isis_circuit *isis_circuit_create (struct isis_area *area, struct interface *ifp); void isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router); int isis_circuit_passive_set (struct isis_circuit *circuit, bool passive); void isis_circuit_is_type_set (struct isis_circuit *circuit, int is_type); int isis_circuit_circ_type_set (struct isis_circuit *circuit, int circ_type); int isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric); int isis_circuit_passwd_unset (struct isis_circuit *circuit); int isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd); int isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd); #endif /* _ZEBRA_ISIS_CIRCUIT_H */ quagga-1.2.4/isisd/isis_common.h000066400000000000000000000033201325323223500165640ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_common.h * some common data structures * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef ISIS_COMMON_H #define ISIS_COMMON_H /* * Area Address */ struct area_addr { u_char addr_len; u_char area_addr[20]; }; struct isis_passwd { u_char len; #define ISIS_PASSWD_TYPE_UNUSED 0 #define ISIS_PASSWD_TYPE_CLEARTXT 1 #define ISIS_PASSWD_TYPE_HMAC_MD5 54 #define ISIS_PASSWD_TYPE_PRIVATE 255 u_char type; /* Authenticate SNPs? */ #define SNP_AUTH_SEND 0x01 #define SNP_AUTH_RECV 0x02 u_char snp_auth; u_char passwd[255]; }; /* * (Dynamic) Hostname * one struct for cache list * one struct for LSP TLV */ struct hostname { u_char namelen; u_char name[255]; }; /* * Supported Protocol IDs */ struct nlpids { u_char count; u_char nlpids[4]; /* FIXME: enough ? */ }; #endif quagga-1.2.4/isisd/isis_constants.h000066400000000000000000000113671325323223500173220ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_constants.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef ISIS_CONSTANTS_H #define ISIS_CONSTANTS_H /* * Architectural constant values from p. 35 of ISO/IEC 10589 */ #define MAX_NARROW_LINK_METRIC 63 #define MAX_NARROW_PATH_METRIC 1023 #define MAX_WIDE_LINK_METRIC 0x00FFFFFF /* RFC4444 */ #define MAX_WIDE_PATH_METRIC 0xFE000000 /* RFC3787 */ #define ISO_SAP 0xFE #define INTRADOMAIN_ROUTEING_SELECTOR 0 #define SEQUENCE_MODULUS 4294967296 /* * implementation specific jitter values */ #define IIH_JITTER 10 /* % */ #define MAX_AGE_JITTER 5 /* % */ #define MAX_LSP_GEN_JITTER 5 /* % */ #define CSNP_JITTER 10 /* % */ #define PSNP_JITTER 10 /* % */ #define RANDOM_SPREAD 100000.0 #define ISIS_LEVELS 2 #define ISIS_LEVEL1 1 #define ISIS_LEVEL2 2 /* * Default values * ISO - 10589 Section 7.3.21 - Parameters * RFC 4444 */ #define MAX_AGE 1200 #define ZERO_AGE_LIFETIME 60 #define MIN_LSP_LIFETIME 350 #define MAX_LSP_LIFETIME 65535 #define DEFAULT_LSP_LIFETIME 1200 #define MIN_MAX_LSP_GEN_INTERVAL 1 #define MAX_MAX_LSP_GEN_INTERVAL 65235 #define DEFAULT_MAX_LSP_GEN_INTERVAL 900 #define MIN_MIN_LSP_GEN_INTERVAL 1 #define MAX_MIN_LSP_GEN_INTERVAL 120 /* RFC 4444 says 65535 */ #define DEFAULT_MIN_LSP_GEN_INTERVAL 30 #define MIN_LSP_TRANS_INTERVAL 5 #define MIN_CSNP_INTERVAL 1 #define MAX_CSNP_INTERVAL 600 #define DEFAULT_CSNP_INTERVAL 10 #define MIN_PSNP_INTERVAL 1 #define MAX_PSNP_INTERVAL 120 #define DEFAULT_PSNP_INTERVAL 2 #define MIN_HELLO_INTERVAL 1 #define MAX_HELLO_INTERVAL 600 #define DEFAULT_HELLO_INTERVAL 3 #define MIN_HELLO_MULTIPLIER 2 #define MAX_HELLO_MULTIPLIER 100 #define DEFAULT_HELLO_MULTIPLIER 10 #define MIN_PRIORITY 0 #define MAX_PRIORITY 127 #define DEFAULT_PRIORITY 64 /* min and max metric varies by new vs old metric types */ #define DEFAULT_CIRCUIT_METRIC 10 #define METRICS_UNSUPPORTED 0x80 #define MINIMUM_SPF_INTERVAL 1 #define ISIS_MAX_PATH_SPLITS 64 /* * NLPID values */ #define NLPID_IP 204 #define NLPID_IPV6 142 #define NLPID_SNAP 128 #define NLPID_CLNP 129 #define NLPID_ESIS 130 /* * Return values for functions */ #define ISIS_OK 0 #define ISIS_WARNING 1 #define ISIS_ERROR 2 #define ISIS_CRITICAL 3 /* * IS-IS Circuit Types */ #define IS_LEVEL_1 1 #define IS_LEVEL_2 2 #define IS_LEVEL_1_AND_2 3 #define SNPA_ADDRSTRLEN 18 #define ISIS_SYS_ID_LEN 6 #define ISIS_NSEL_LEN 1 #define SYSID_STRLEN 24 /* * LSP bit masks */ #define LSPBIT_P 0x80 #define LSPBIT_ATT 0x78 #define LSPBIT_OL 0x04 #define LSPBIT_IST 0x03 /* * LSP bit masking macros * taken from tcpdumps * print-isoclns.c */ #define ISIS_MASK_LSP_OL_BIT(x) ((x)&0x4) #define ISIS_MASK_LSP_IS_L1_BIT(x) ((x)&0x1) #define ISIS_MASK_LSP_IS_L2_BIT(x) ((x)&0x2) #define ISIS_MASK_LSP_PARTITION_BIT(x) ((x)&0x80) #define ISIS_MASK_LSP_ATT_BITS(x) ((x)&0x78) #define ISIS_MASK_LSP_ATT_ERROR_BIT(x) ((x)&0x40) #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x) ((x)&0x20) #define ISIS_MASK_LSP_ATT_DELAY_BIT(x) ((x)&0x10) #define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x) ((x)&0x8) #define LLC_LEN 3 /* we need to be aware of the fact we are using ISO sized * packets, using isomtu = mtu - LLC_LEN */ #define ISO_MTU(C) \ ((if_is_broadcast ((C)->interface)) ? \ (C->interface->mtu - LLC_LEN) : (C->interface->mtu)) #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #endif /* ISIS_CONSTANTS_H */ quagga-1.2.4/isisd/isis_csm.c000066400000000000000000000141501325323223500160540ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_csm.c * IS-IS circuit state machine * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "log.h" #include "memory.h" #include "if.h" #include "linklist.h" #include "command.h" #include "thread.h" #include "hash.h" #include "prefix.h" #include "stream.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" extern struct isis *isis; static const char *csm_statestr[] = { "C_STATE_NA", "C_STATE_INIT", "C_STATE_CONF", "C_STATE_UP" }; #define STATE2STR(S) csm_statestr[S] static const char *csm_eventstr[] = { "NO_STATE", "ISIS_ENABLE", "IF_UP_FROM_Z", "ISIS_DISABLE", "IF_DOWN_FROM_Z", }; #define EVENT2STR(E) csm_eventstr[E] struct isis_circuit * isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) { int old_state; old_state = circuit ? circuit->state : C_STATE_NA; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("CSM_EVENT: %s", EVENT2STR (event)); switch (old_state) { case C_STATE_NA: if (circuit) zlog_warn ("Non-null circuit while state C_STATE_NA"); assert (circuit == NULL); switch (event) { case ISIS_ENABLE: circuit = isis_circuit_new (); isis_circuit_configure (circuit, (struct isis_area *) arg); circuit->state = C_STATE_CONF; break; case IF_UP_FROM_Z: circuit = isis_circuit_new (); isis_circuit_if_add (circuit, (struct interface *) arg); listnode_add (isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; break; case ISIS_DISABLE: zlog_warn ("circuit already disabled"); break; case IF_DOWN_FROM_Z: zlog_warn ("circuit already disconnected"); break; } break; case C_STATE_INIT: assert (circuit); switch (event) { case ISIS_ENABLE: isis_circuit_configure (circuit, (struct isis_area *) arg); if (isis_circuit_up (circuit) != ISIS_OK) { isis_circuit_deconfigure (circuit, (struct isis_area *) arg); break; } circuit->state = C_STATE_UP; isis_event_circuit_state_change (circuit, circuit->area, 1); listnode_delete (isis->init_circ_list, circuit); break; case IF_UP_FROM_Z: assert (circuit); zlog_warn ("circuit already connected"); break; case ISIS_DISABLE: zlog_warn ("circuit already disabled"); break; case IF_DOWN_FROM_Z: isis_circuit_if_del (circuit, (struct interface *) arg); listnode_delete (isis->init_circ_list, circuit); isis_circuit_del (circuit); circuit = NULL; break; } break; case C_STATE_CONF: assert (circuit); switch (event) { case ISIS_ENABLE: zlog_warn ("circuit already enabled"); break; case IF_UP_FROM_Z: isis_circuit_if_add (circuit, (struct interface *) arg); if (isis_circuit_up (circuit) != ISIS_OK) { zlog_err("Could not bring up %s because of invalid config.", circuit->interface->name); zlog_err("Clearing config for %s. Please re-examine it.", circuit->interface->name); if (circuit->ip_router) { circuit->ip_router = 0; circuit->area->ip_circuits--; } if (circuit->ipv6_router) { circuit->ipv6_router = 0; circuit->area->ipv6_circuits--; } circuit_update_nlpids(circuit); isis_circuit_deconfigure(circuit, circuit->area); listnode_add (isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; break; } circuit->state = C_STATE_UP; isis_event_circuit_state_change (circuit, circuit->area, 1); break; case ISIS_DISABLE: isis_circuit_deconfigure (circuit, (struct isis_area *) arg); isis_circuit_del (circuit); circuit = NULL; break; case IF_DOWN_FROM_Z: zlog_warn ("circuit already disconnected"); break; } break; case C_STATE_UP: assert (circuit); switch (event) { case ISIS_ENABLE: zlog_warn ("circuit already configured"); break; case IF_UP_FROM_Z: zlog_warn ("circuit already connected"); break; case ISIS_DISABLE: isis_circuit_down (circuit); isis_circuit_deconfigure (circuit, (struct isis_area *) arg); circuit->state = C_STATE_INIT; isis_event_circuit_state_change (circuit, (struct isis_area *)arg, 0); listnode_add (isis->init_circ_list, circuit); break; case IF_DOWN_FROM_Z: isis_circuit_down (circuit); isis_circuit_if_del (circuit, (struct interface *) arg); circuit->state = C_STATE_CONF; isis_event_circuit_state_change (circuit, circuit->area, 0); break; } break; default: zlog_warn ("Invalid circuit state %d", old_state); } if (isis->debugs & DEBUG_EVENTS) zlog_debug ("CSM_STATE_CHANGE: %s -> %s ", STATE2STR (old_state), circuit ? STATE2STR (circuit->state) : STATE2STR (C_STATE_NA)); return circuit; } quagga-1.2.4/isisd/isis_csm.h000066400000000000000000000030171325323223500160610ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_csm.h * IS-IS circuit state machine * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_CSM_H #define _ZEBRA_ISIS_CSM_H /* * Circuit states */ #define C_STATE_NA 0 #define C_STATE_INIT 1 /* Connected to interface */ #define C_STATE_CONF 2 /* Configured for ISIS */ #define C_STATE_UP 3 /* CONN | CONF */ /* * Circuit events */ #define ISIS_ENABLE 1 #define IF_UP_FROM_Z 2 #define ISIS_DISABLE 3 #define IF_DOWN_FROM_Z 4 struct isis_circuit *isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg); #endif /* _ZEBRA_ISIS_CSM_H */ quagga-1.2.4/isisd/isis_dlpi.c000066400000000000000000000411431325323223500162240ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_dlpi.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #if ISIS_METHOD == ISIS_METHOD_DLPI #include #include #include #include #include #include #include #include #include #include "log.h" #include "network.h" #include "stream.h" #include "if.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_circuit.h" #include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_network.h" #include "privs.h" extern struct zebra_privs_t isisd_privs; static t_uscalar_t dlpi_ctl[1024]; /* DLPI control messages */ /* * Table 9 - Architectural constants for use with ISO 8802 subnetworks * ISO 10589 - 8.4.8 */ u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 }; u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 }; u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 }; u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 }; static u_char sock_buff[8192]; static u_short pf_filter[] = { ENF_PUSHWORD + 0, /* Get the SSAP/DSAP values */ ENF_PUSHLIT | ENF_CAND, /* Check them */ ISO_SAP | (ISO_SAP << 8), ENF_PUSHWORD + 1, /* Get the control value */ ENF_PUSHLIT | ENF_AND, /* Isolate it */ #ifdef _BIG_ENDIAN 0xFF00, #else 0x00FF, #endif ENF_PUSHLIT | ENF_CAND, /* Test for expected value */ #ifdef _BIG_ENDIAN 0x0300 #else 0x0003 #endif }; /* * We would like to use something like libdlpi here, but that's not present on * all versions of Solaris or on any non-Solaris system, so it's nowhere near * as portable as we'd like. Thus, we use the standards-conformant DLPI * interfaces plus the (optional; not needed) Solaris packet filter module. */ static int dlpisend (int fd, const void *cbuf, size_t cbuflen, const void *dbuf, size_t dbuflen, int flags) { const struct strbuf *ctlptr = NULL; const struct strbuf *dataptr = NULL; struct strbuf ctlbuf, databuf; int rv; if (cbuf != NULL) { memset (&ctlbuf, 0, sizeof (ctlbuf)); ctlbuf.len = cbuflen; ctlbuf.buf = (void *)cbuf; ctlptr = &ctlbuf; } if (dbuf != NULL) { memset (&databuf, 0, sizeof (databuf)); databuf.len = dbuflen; databuf.buf = (void *)dbuf; dataptr = &databuf; } /* We assume this doesn't happen often and isn't operationally significant */ rv = putmsg(fd, ctlptr, dataptr, flags); if (rv == -1 && dbuf == NULL) { /* * For actual PDU transmission - recognizable buf dbuf != NULL, * the error is passed upwards and should not be printed here. */ zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno)); } return rv; } static ssize_t dlpirctl (int fd) { struct pollfd fds[1]; struct strbuf ctlbuf, databuf; int flags, retv; do { /* Poll is used here in case the device doesn't speak DLPI correctly */ memset (fds, 0, sizeof (fds)); fds[0].fd = fd; fds[0].events = POLLIN | POLLPRI; if (poll (fds, 1, 1000) <= 0) return -1; memset (&ctlbuf, 0, sizeof (ctlbuf)); memset (&databuf, 0, sizeof (databuf)); ctlbuf.maxlen = sizeof (dlpi_ctl); ctlbuf.buf = (void *)dlpi_ctl; databuf.maxlen = sizeof (sock_buff); databuf.buf = (void *)sock_buff; flags = 0; retv = getmsg (fd, &ctlbuf, &databuf, &flags); if (retv < 0) return -1; } while (ctlbuf.len == 0); if (!(retv & MORECTL)) { while (retv & MOREDATA) { flags = 0; retv = getmsg (fd, NULL, &databuf, &flags); } return ctlbuf.len; } while (retv & MORECTL) { flags = 0; retv = getmsg (fd, &ctlbuf, &databuf, &flags); } return -1; } static int dlpiok (int fd, t_uscalar_t oprim) { int retv; dl_ok_ack_t *doa = (dl_ok_ack_t *)dlpi_ctl; retv = dlpirctl (fd); if (retv < (ssize_t)DL_OK_ACK_SIZE || doa->dl_primitive != DL_OK_ACK || doa->dl_correct_primitive != oprim) { return -1; } else { return 0; } } static int dlpiinfo (int fd) { dl_info_req_t dir; ssize_t retv; memset (&dir, 0, sizeof (dir)); dir.dl_primitive = DL_INFO_REQ; /* Info_req uses M_PCPROTO. */ dlpisend (fd, &dir, sizeof (dir), NULL, 0, RS_HIPRI); retv = dlpirctl (fd); if (retv < (ssize_t)DL_INFO_ACK_SIZE || dlpi_ctl[0] != DL_INFO_ACK) return -1; else return retv; } static int dlpiopen (const char *devpath, ssize_t *acklen) { int fd, flags; fd = open (devpath, O_RDWR | O_NONBLOCK | O_NOCTTY); if (fd == -1) return -1; /* All that we want is for the open itself to be non-blocking, not I/O. */ flags = fcntl (fd, F_GETFL, 0); if (flags != -1) fcntl (fd, F_SETFL, flags & ~O_NONBLOCK); /* After opening, ask for information */ if ((*acklen = dlpiinfo (fd)) == -1) { close (fd); return -1; } return fd; } static int dlpiattach (int fd, int unit) { dl_attach_req_t dar; memset (&dar, 0, sizeof (dar)); dar.dl_primitive = DL_ATTACH_REQ; dar.dl_ppa = unit; dlpisend (fd, &dar, sizeof (dar), NULL, 0, 0); return dlpiok (fd, dar.dl_primitive); } static int dlpibind (int fd) { dl_bind_req_t dbr; int retv; dl_bind_ack_t *dba = (dl_bind_ack_t *)dlpi_ctl; memset (&dbr, 0, sizeof (dbr)); dbr.dl_primitive = DL_BIND_REQ; dbr.dl_service_mode = DL_CLDLS; dlpisend (fd, &dbr, sizeof (dbr), NULL, 0, 0); retv = dlpirctl (fd); if (retv < (ssize_t)DL_BIND_ACK_SIZE || dba->dl_primitive != DL_BIND_ACK) return -1; else return 0; } static int dlpimcast (int fd, const u_char *mcaddr) { struct { dl_enabmulti_req_t der; u_char addr[ETHERADDRL]; } dler; memset (&dler, 0, sizeof (dler)); dler.der.dl_primitive = DL_ENABMULTI_REQ; dler.der.dl_addr_length = sizeof (dler.addr); dler.der.dl_addr_offset = dler.addr - (u_char *)&dler; memcpy (dler.addr, mcaddr, sizeof (dler.addr)); dlpisend (fd, &dler, sizeof (dler), NULL, 0, 0); return dlpiok (fd, dler.der.dl_primitive); } static int dlpiaddr (int fd, u_char *addr) { dl_phys_addr_req_t dpar; dl_phys_addr_ack_t *dpaa = (dl_phys_addr_ack_t *)dlpi_ctl; int retv; memset (&dpar, 0, sizeof (dpar)); dpar.dl_primitive = DL_PHYS_ADDR_REQ; dpar.dl_addr_type = DL_CURR_PHYS_ADDR; dlpisend (fd, &dpar, sizeof (dpar), NULL, 0, 0); retv = dlpirctl (fd); if (retv < (ssize_t)DL_PHYS_ADDR_ACK_SIZE || dpaa->dl_primitive != DL_PHYS_ADDR_ACK) return -1; if (dpaa->dl_addr_offset < DL_PHYS_ADDR_ACK_SIZE || dpaa->dl_addr_length != ETHERADDRL || dpaa->dl_addr_offset + dpaa->dl_addr_length > (size_t)retv) return -1; bcopy((char *)dpaa + dpaa->dl_addr_offset, addr, ETHERADDRL); return 0; } static int open_dlpi_dev (struct isis_circuit *circuit) { int fd = -1, unit, retval; char devpath[MAXPATHLEN]; dl_info_ack_t *dia = (dl_info_ack_t *)dlpi_ctl; ssize_t acklen; /* Only broadcast-type are supported at the moment */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn ("%s: non-broadcast interface %s", __func__, circuit->interface->name); return ISIS_WARNING; } /* Try the vanity node first, if permitted */ if (getenv("DLPI_DEVONLY") == NULL) { (void) snprintf (devpath, sizeof(devpath), "/dev/net/%s", circuit->interface->name); fd = dlpiopen (devpath, &acklen); } /* Now try as an ordinary Style 1 node */ if (fd == -1) { (void) snprintf (devpath, sizeof (devpath), "/dev/%s", circuit->interface->name); unit = -1; fd = dlpiopen (devpath, &acklen); } /* If that fails, try again as Style 2 */ if (fd == -1) { char *cp; cp = devpath + strlen (devpath); while (--cp >= devpath && isdigit(*cp)) ; unit = strtol(cp, NULL, 0); *cp = '\0'; fd = dlpiopen (devpath, &acklen); /* If that too fails, then the device really doesn't exist */ if (fd == -1) { zlog_warn ("%s: unknown interface %s", __func__, circuit->interface->name); return ISIS_WARNING; } /* Double check the DLPI style */ if (dia->dl_provider_style != DL_STYLE2) { zlog_warn ("open_dlpi_dev(): interface %s: %s is not style 2", circuit->interface->name, devpath); close (fd); return ISIS_WARNING; } /* If it succeeds, then we need to attach to the unit specified */ dlpiattach (fd, unit); /* Reget the information, as it may be different per node */ if ((acklen = dlpiinfo (fd)) == -1) { close (fd); return ISIS_WARNING; } } else { /* Double check the DLPI style */ if (dia->dl_provider_style != DL_STYLE1) { zlog_warn ("open_dlpi_dev(): interface %s: %s is not style 1", circuit->interface->name, devpath); close (fd); return ISIS_WARNING; } } /* Check that the interface we've got is the kind we expect */ if ((dia->dl_sap_length != 2 && dia->dl_sap_length != -2) || dia->dl_service_mode != DL_CLDLS || dia->dl_addr_length != ETHERADDRL + 2 || dia->dl_brdcst_addr_length != ETHERADDRL) { zlog_warn ("%s: unsupported interface type for %s", __func__, circuit->interface->name); close (fd); return ISIS_WARNING; } switch (dia->dl_mac_type) { case DL_CSMACD: case DL_ETHER: case DL_100VG: case DL_100VGTPR: case DL_ETH_CSMA: case DL_100BT: break; default: zlog_warn ("%s: unexpected mac type on %s: %lld", __func__, circuit->interface->name, (long long)dia->dl_mac_type); close (fd); return ISIS_WARNING; } circuit->sap_length = dia->dl_sap_length; /* * The local hardware address is something that should be provided by way of * sockaddr_dl for the interface, but isn't on Solaris. We set it here based * on DLPI's reported address to avoid roto-tilling the world. * (Note that isis_circuit_if_add on Solaris doesn't set the snpa.) * * Unfortunately, GLD is broken and doesn't provide the address after attach, * so we need to be careful and use DL_PHYS_ADDR_REQ instead. */ if (dlpiaddr (fd, circuit->u.bc.snpa) == -1) { zlog_warn ("open_dlpi_dev(): interface %s: unable to get MAC address", circuit->interface->name); close (fd); return ISIS_WARNING; } /* Now bind to SAP 0. This gives us 802-type traffic. */ if (dlpibind (fd) == -1) { zlog_warn ("%s: cannot bind SAP 0 on %s", __func__, circuit->interface->name); close (fd); return ISIS_WARNING; } /* * Join to multicast groups according to * 8.4.2 - Broadcast subnetwork IIH PDUs */ retval = 0; retval |= dlpimcast (fd, ALL_L1_ISS); retval |= dlpimcast (fd, ALL_ISS); retval |= dlpimcast (fd, ALL_L2_ISS); if (retval != 0) { zlog_warn ("%s: unable to join multicast on %s", __func__, circuit->interface->name); close (fd); return ISIS_WARNING; } /* Push on the packet filter to avoid stray 802 packets */ if (ioctl (fd, I_PUSH, "pfmod") == 0) { struct packetfilt pfil; struct strioctl sioc; pfil.Pf_Priority = 0; pfil.Pf_FilterLen = sizeof (pf_filter) / sizeof (u_short); memcpy (pfil.Pf_Filter, pf_filter, sizeof (pf_filter)); /* pfmod does not support transparent ioctls */ sioc.ic_cmd = PFIOCSETF; sioc.ic_timout = 5; sioc.ic_len = sizeof (struct packetfilt); sioc.ic_dp = (char *)&pfil; if (ioctl (fd, I_STR, &sioc) == -1) zlog_warn("%s: could not perform PF_IOCSETF on %s", __func__, circuit->interface->name); } circuit->fd = fd; return ISIS_OK; } /* * Create the socket and set the tx/rx funcs */ int isis_sock_init (struct isis_circuit *circuit) { int retval = ISIS_OK; if (isisd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno)); retval = open_dlpi_dev (circuit); if (retval != ISIS_OK) { zlog_warn ("%s: could not initialize the socket", __func__); goto end; } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { circuit->tx = isis_send_pdu_bcast; circuit->rx = isis_recv_pdu_bcast; } else { zlog_warn ("isis_sock_init(): unknown circuit type"); retval = ISIS_WARNING; goto end; } end: if (isisd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno)); return retval; } int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) { struct pollfd fds[1]; struct strbuf ctlbuf, databuf; int flags, retv; dl_unitdata_ind_t *dui = (dl_unitdata_ind_t *)dlpi_ctl; memset (fds, 0, sizeof (fds)); fds[0].fd = circuit->fd; fds[0].events = POLLIN | POLLPRI; if (poll (fds, 1, 0) <= 0) return ISIS_WARNING; memset (&ctlbuf, 0, sizeof (ctlbuf)); memset (&databuf, 0, sizeof (databuf)); ctlbuf.maxlen = sizeof (dlpi_ctl); ctlbuf.buf = (void *)dlpi_ctl; databuf.maxlen = sizeof (sock_buff); databuf.buf = (void *)sock_buff; flags = 0; retv = getmsg (circuit->fd, &ctlbuf, &databuf, &flags); if (retv < 0) { zlog_warn ("isis_recv_pdu_bcast: getmsg failed: %s", safe_strerror (errno)); return ISIS_WARNING; } if (retv & (MORECTL | MOREDATA)) { while (retv & (MORECTL | MOREDATA)) { flags = 0; retv = getmsg (circuit->fd, &ctlbuf, &databuf, &flags); } return ISIS_WARNING; } if (ctlbuf.len < (ssize_t)DL_UNITDATA_IND_SIZE || dui->dl_primitive != DL_UNITDATA_IND) return ISIS_WARNING; if (dui->dl_src_addr_length != ETHERADDRL + 2 || dui->dl_src_addr_offset < DL_UNITDATA_IND_SIZE || dui->dl_src_addr_offset + dui->dl_src_addr_length > (size_t)ctlbuf.len) return ISIS_WARNING; memcpy (ssnpa, (char *)dui + dui->dl_src_addr_offset + (circuit->sap_length > 0 ? circuit->sap_length : 0), ETHERADDRL); if (databuf.len < LLC_LEN || sock_buff[0] != ISO_SAP || sock_buff[1] != ISO_SAP || sock_buff[2] != 3) return ISIS_WARNING; stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, databuf.len - LLC_LEN); stream_set_getp (circuit->rcv_stream, 0); return ISIS_OK; } int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { dl_unitdata_req_t *dur = (dl_unitdata_req_t *)dlpi_ctl; char *dstaddr; u_short *dstsap; int buflen; int rv; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN; if ((size_t)buflen > sizeof (sock_buff)) { zlog_warn ("isis_send_pdu_bcast: sock_buff size %zu is less than " "output pdu size %d on circuit %s", sizeof (sock_buff), buflen, circuit->interface->name); return ISIS_WARNING; } stream_set_getp (circuit->snd_stream, 0); memset (dur, 0, sizeof (*dur)); dur->dl_primitive = DL_UNITDATA_REQ; dur->dl_dest_addr_length = ETHERADDRL + 2; dur->dl_dest_addr_offset = sizeof (*dur); dstaddr = (char *)(dur + 1); if (circuit->sap_length < 0) { dstsap = (u_short *)(dstaddr + ETHERADDRL); } else { dstsap = (u_short *)dstaddr; dstaddr += circuit->sap_length; } if (level == 1) memcpy (dstaddr, ALL_L1_ISS, ETHERADDRL); else memcpy (dstaddr, ALL_L2_ISS, ETHERADDRL); /* Note: DLPI SAP values are in host byte order */ *dstsap = buflen; sock_buff[0] = ISO_SAP; sock_buff[1] = ISO_SAP; sock_buff[2] = 0x03; memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream)); rv = dlpisend(circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length, sock_buff, buflen, 0); if (rv < 0) { zlog_warn("IS-IS dlpi: could not transmit packet on %s: %s", circuit->interface->name, safe_strerror(errno)); if (ERRNO_IO_RETRY(errno)) return ISIS_WARNING; return ISIS_ERROR; } return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_DLPI */ quagga-1.2.4/isisd/isis_dr.c000066400000000000000000000237641325323223500157120ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_dr.c * IS-IS designated router related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "log.h" #include "hash.h" #include "thread.h" #include "linklist.h" #include "vty.h" #include "stream.h" #include "if.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_misc.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_constants.h" #include "isisd/isis_pdu.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_dr.h" #include "isisd/isis_events.h" const char * isis_disflag2string (int disflag) { switch (disflag) { case ISIS_IS_NOT_DIS: return "is not DIS"; case ISIS_IS_DIS: return "is DIS"; case ISIS_WAS_DIS: return "was DIS"; default: return "unknown DIS state"; } return NULL; /* not reached */ } int isis_run_dr_l1 (struct thread *thread) { struct isis_circuit *circuit; circuit = THREAD_ARG (thread); assert (circuit); if (circuit->u.bc.run_dr_elect[0]) zlog_warn ("isis_run_dr(): run_dr_elect already set for l1"); circuit->u.bc.t_run_dr[0] = NULL; circuit->u.bc.run_dr_elect[0] = 1; return ISIS_OK; } int isis_run_dr_l2 (struct thread *thread) { struct isis_circuit *circuit; circuit = THREAD_ARG (thread); assert (circuit); if (circuit->u.bc.run_dr_elect[1]) zlog_warn ("isis_run_dr(): run_dr_elect already set for l2"); circuit->u.bc.t_run_dr[1] = NULL; circuit->u.bc.run_dr_elect[1] = 1; return ISIS_OK; } static int isis_check_dr_change (struct isis_adjacency *adj, int level) { int i; if (adj->dis_record[level - 1].dis != adj->dis_record[(1 * ISIS_LEVELS) + level - 1].dis) /* was there a DIS state transition ? */ { adj->dischanges[level - 1]++; /* ok rotate the history list through */ for (i = DIS_RECORDS - 1; i > 0; i--) { adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis = adj->dis_record[((i - 1) * ISIS_LEVELS) + level - 1].dis; adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change = adj->dis_record[((i - 1) * ISIS_LEVELS) + level - 1].last_dis_change; } } return ISIS_OK; } int isis_dr_elect (struct isis_circuit *circuit, int level) { struct list *adjdb; struct listnode *node; struct isis_adjacency *adj, *adj_dr = NULL; struct list *list = list_new (); u_char own_prio; int biggest_prio = -1; int cmp_res, retval = ISIS_OK; own_prio = circuit->priority[level - 1]; adjdb = circuit->u.bc.adjdb[level - 1]; if (!adjdb) { zlog_warn ("isis_dr_elect() adjdb == NULL"); list_delete (list); return ISIS_WARNING; } isis_adj_build_up_list (adjdb, list); /* * Loop the adjacencies and find the one with the biggest priority */ for (ALL_LIST_ELEMENTS_RO (list, node, adj)) { /* clear flag for show output */ adj->dis_record[level - 1].dis = ISIS_IS_NOT_DIS; adj->dis_record[level - 1].last_dis_change = time (NULL); if (adj->prio[level - 1] > biggest_prio) { biggest_prio = adj->prio[level - 1]; adj_dr = adj; } else if (adj->prio[level - 1] == biggest_prio) { /* * Comparison of MACs breaks a tie */ if (adj_dr) { cmp_res = memcmp (adj_dr->snpa, adj->snpa, ETH_ALEN); if (cmp_res < 0) { adj_dr = adj; } if (cmp_res == 0) zlog_warn ("isis_dr_elect(): multiple adjacencies with same SNPA"); } else { adj_dr = adj; } } } if (!adj_dr) { /* * Could not find the DR - means we are alone. Resign if we were DR. */ if (circuit->u.bc.is_dr[level - 1]) retval = isis_dr_resign (circuit, level); list_delete (list); return retval; } /* * Now we have the DR adjacency, compare it to self */ if (adj_dr->prio[level - 1] < own_prio || (adj_dr->prio[level - 1] == own_prio && memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0)) { adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS; adj_dr->dis_record[level - 1].last_dis_change = time (NULL); /* rotate the history log */ for (ALL_LIST_ELEMENTS_RO (list, node, adj)) isis_check_dr_change (adj, level); /* We are the DR, commence DR */ if (circuit->u.bc.is_dr[level - 1] == 0 && listcount (list) > 0) retval = isis_dr_commence (circuit, level); } else { /* ok we have found the DIS - lets mark the adjacency */ /* set flag for show output */ adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS; adj_dr->dis_record[level - 1].last_dis_change = time (NULL); /* now loop through a second time to check if there has been a DIS change * if yes rotate the history log */ for (ALL_LIST_ELEMENTS_RO (list, node, adj)) isis_check_dr_change (adj, level); /* * We are not DR - if we were -> resign */ if (circuit->u.bc.is_dr[level - 1]) retval = isis_dr_resign (circuit, level); } list_delete (list); return retval; } int isis_dr_resign (struct isis_circuit *circuit, int level) { u_char id[ISIS_SYS_ID_LEN + 2]; zlog_debug ("isis_dr_resign l%d", level); circuit->u.bc.is_dr[level - 1] = 0; circuit->u.bc.run_dr_elect[level - 1] = 0; THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[level - 1]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]); circuit->lsp_regenerate_pending[level - 1] = 0; memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = circuit->circuit_id; LSP_FRAGMENT (id) = 0; lsp_purge_pseudo (id, circuit, level); if (level == 1) { memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1); THREAD_TIMER_OFF (circuit->t_send_csnp[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, isis_jitter (circuit->psnp_interval[level - 1], PSNP_JITTER)); } else { memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1); THREAD_TIMER_OFF (circuit->t_send_csnp[1]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, isis_jitter (circuit->psnp_interval[level - 1], PSNP_JITTER)); } thread_add_event (master, isis_event_dis_status_change, circuit, 0); return ISIS_OK; } int isis_dr_commence (struct isis_circuit *circuit, int level) { u_char old_dr[ISIS_SYS_ID_LEN + 2]; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("isis_dr_commence l%d", level); /* Lets keep a pause in DR election */ circuit->u.bc.run_dr_elect[level - 1] = 0; if (level == 1) THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); else THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); circuit->u.bc.is_dr[level - 1] = 1; if (level == 1) { memcpy (old_dr, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (old_dr) = 0; if (LSP_PSEUDO_ID (old_dr)) { /* there was a dr elected, purge its LSPs from the db */ lsp_purge_pseudo (old_dr, circuit, level); } memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN); *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id; assert (circuit->circuit_id); /* must be non-zero */ /* if (circuit->t_send_l1_psnp) thread_cancel (circuit->t_send_l1_psnp); */ lsp_generate_pseudo (circuit, 1); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit, isis_jitter (circuit->csnp_interval[level - 1], CSNP_JITTER)); } else { memcpy (old_dr, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (old_dr) = 0; if (LSP_PSEUDO_ID (old_dr)) { /* there was a dr elected, purge its LSPs from the db */ lsp_purge_pseudo (old_dr, circuit, level); } memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN); *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id; assert (circuit->circuit_id); /* must be non-zero */ /* if (circuit->t_send_l1_psnp) thread_cancel (circuit->t_send_l1_psnp); */ lsp_generate_pseudo (circuit, 2); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit, isis_jitter (circuit->csnp_interval[level - 1], CSNP_JITTER)); } thread_add_event (master, isis_event_dis_status_change, circuit, 0); return ISIS_OK; } quagga-1.2.4/isisd/isis_dr.h000066400000000000000000000027711325323223500157120ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_dr.h * IS-IS designated router related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_DR_H #define _ZEBRA_ISIS_DR_H int isis_run_dr_l1 (struct thread *thread); int isis_run_dr_l2 (struct thread *thread); int isis_dr_elect (struct isis_circuit *circuit, int level); int isis_dr_resign (struct isis_circuit *circuit, int level); int isis_dr_commence (struct isis_circuit *circuit, int level); const char *isis_disflag2string (int disflag); enum isis_dis_state { ISIS_IS_NOT_DIS, ISIS_IS_DIS, ISIS_WAS_DIS, ISIS_UNKNOWN_DIS }; #endif /* _ZEBRA_ISIS_DR_H */ quagga-1.2.4/isisd/isis_dynhn.c000066400000000000000000000103411325323223500164100ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_dynhn.c * Dynamic hostname cache * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "vty.h" #include "linklist.h" #include "memory.h" #include "log.h" #include "stream.h" #include "command.h" #include "if.h" #include "thread.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" extern struct host host; struct list *dyn_cache = NULL; static int dyn_cache_cleanup (struct thread *); void dyn_cache_init (void) { if (dyn_cache == NULL) dyn_cache = list_new (); THREAD_TIMER_ON (master, isis->t_dync_clean, dyn_cache_cleanup, NULL, 120); return; } static int dyn_cache_cleanup (struct thread *thread) { struct listnode *node, *nnode; struct isis_dynhn *dyn; time_t now = time (NULL); isis->t_dync_clean = NULL; for (ALL_LIST_ELEMENTS (dyn_cache, node, nnode, dyn)) { if ((now - dyn->refresh) < MAX_LSP_LIFETIME) continue; list_delete_node (dyn_cache, node); XFREE (MTYPE_ISIS_DYNHN, dyn); } THREAD_TIMER_ON (master, isis->t_dync_clean, dyn_cache_cleanup, NULL, 120); return ISIS_OK; } struct isis_dynhn * dynhn_find_by_id (const u_char * id) { struct listnode *node = NULL; struct isis_dynhn *dyn = NULL; for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn)) if (memcmp (dyn->id, id, ISIS_SYS_ID_LEN) == 0) return dyn; return NULL; } struct isis_dynhn * dynhn_find_by_name (const char *hostname) { struct listnode *node = NULL; struct isis_dynhn *dyn = NULL; for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn)) if (strncmp ((char *)dyn->name.name, hostname, 255) == 0) return dyn; return NULL; } void isis_dynhn_insert (const u_char * id, struct hostname *hostname, int level) { struct isis_dynhn *dyn; dyn = dynhn_find_by_id (id); if (dyn) { memcpy (&dyn->name, hostname, hostname->namelen + 1); memcpy (dyn->id, id, ISIS_SYS_ID_LEN); dyn->refresh = time (NULL); return; } dyn = XCALLOC (MTYPE_ISIS_DYNHN, sizeof (struct isis_dynhn)); if (!dyn) { zlog_warn ("isis_dynhn_insert(): out of memory!"); return; } /* we also copy the length */ memcpy (&dyn->name, hostname, hostname->namelen + 1); memcpy (dyn->id, id, ISIS_SYS_ID_LEN); dyn->refresh = time (NULL); dyn->level = level; listnode_add (dyn_cache, dyn); return; } void isis_dynhn_remove (const u_char * id) { struct isis_dynhn *dyn; dyn = dynhn_find_by_id (id); if (!dyn) return; listnode_delete (dyn_cache, dyn); XFREE (MTYPE_ISIS_DYNHN, dyn); return; } /* * Level System ID Dynamic Hostname (notag) * 2 0000.0000.0001 foo-gw * 2 0000.0000.0002 bar-gw * * 0000.0000.0004 this-gw */ void dynhn_print_all (struct vty *vty) { struct listnode *node; struct isis_dynhn *dyn; vty_out (vty, "Level System ID Dynamic Hostname%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn)) { vty_out (vty, "%-7d", dyn->level); vty_out (vty, "%-15s%-15s%s", sysid_print (dyn->id), dyn->name.name, VTY_NEWLINE); } vty_out (vty, " * %s %s%s", sysid_print (isis->sysid), unix_hostname (), VTY_NEWLINE); return; } quagga-1.2.4/isisd/isis_dynhn.h000066400000000000000000000027661325323223500164310ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_dynhn.h * Dynamic hostname cache * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_DYNHN_H #define _ZEBRA_ISIS_DYNHN_H struct isis_dynhn { u_char id[ISIS_SYS_ID_LEN]; struct hostname name; time_t refresh; int level; }; void dyn_cache_init (void); void isis_dynhn_insert (const u_char * id, struct hostname *hostname, int level); void isis_dynhn_remove (const u_char * id); struct isis_dynhn *dynhn_find_by_id (const u_char * id); struct isis_dynhn *dynhn_find_by_name (const char *hostname); void dynhn_print_all (struct vty *vty); #endif /* _ZEBRA_ISIS_DYNHN_H */ quagga-1.2.4/isisd/isis_events.c000066400000000000000000000172711325323223500166050ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_events.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "log.h" #include "memory.h" #include "if.h" #include "linklist.h" #include "command.h" #include "thread.h" #include "hash.h" #include "prefix.h" #include "stream.h" #include "table.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" #include "isisd/isis_spf.h" /* debug isis-spf spf-events 4w4d: ISIS-Spf (tlt): L2 SPF needed, new adjacency, from 0x609229F4 4w4d: ISIS-Spf (tlt): L2, 0000.0000.0042.01-00 TLV contents changed, code 0x2 4w4d: ISIS-Spf (tlt): L2, new LSP 0 DEAD.BEEF.0043.00-00 4w5d: ISIS-Spf (tlt): L1 SPF needed, periodic SPF, from 0x6091C844 4w5d: ISIS-Spf (tlt): L2 SPF needed, periodic SPF, from 0x6091C844 */ void isis_event_circuit_state_change (struct isis_circuit *circuit, struct isis_area *area, int up) { area->circuit_state_changes++; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) circuit %s", area->area_tag, up ? "up" : "down"); /* * Regenerate LSPs this affects */ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } static void circuit_commence_level (struct isis_circuit *circuit, int level) { if (level == 1) { if (! circuit->is_passive) THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, isis_jitter (circuit->hello_interval[0], IIH_JITTER)); circuit->u.bc.lan_neighs[0] = list_new (); } } else { if (! circuit->is_passive) THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], send_lan_l2_hello, circuit, isis_jitter (circuit->hello_interval[1], IIH_JITTER)); circuit->u.bc.lan_neighs[1] = list_new (); } } return; } static void circuit_resign_level (struct isis_circuit *circuit, int level) { int idx = level - 1; THREAD_TIMER_OFF (circuit->t_send_csnp[idx]); THREAD_TIMER_OFF (circuit->t_send_psnp[idx]); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[idx]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[idx]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[idx]); circuit->lsp_regenerate_pending[idx] = 0; circuit->u.bc.run_dr_elect[idx] = 0; if (circuit->u.bc.lan_neighs[idx] != NULL) { list_delete (circuit->u.bc.lan_neighs[idx]); circuit->u.bc.lan_neighs[idx] = NULL; } } return; } void isis_circuit_is_type_set (struct isis_circuit *circuit, int newtype) { if (circuit->state != C_STATE_UP) { circuit->is_type = newtype; return; } if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) circuit type change %s -> %s", circuit->area->area_tag, circuit_t2string (circuit->is_type), circuit_t2string (newtype)); if (circuit->is_type == newtype) return; /* No change */ if (!(newtype & circuit->area->is_type)) { zlog_err ("ISIS-Evt (%s) circuit type change - invalid level %s because" " area is %s", circuit->area->area_tag, circuit_t2string (newtype), circuit_t2string (circuit->area->is_type)); return; } if (! circuit->is_passive) { switch (circuit->is_type) { case IS_LEVEL_1: if (newtype == IS_LEVEL_2) circuit_resign_level (circuit, 1); circuit_commence_level (circuit, 2); break; case IS_LEVEL_1_AND_2: if (newtype == IS_LEVEL_1) circuit_resign_level (circuit, 2); else circuit_resign_level (circuit, 1); break; case IS_LEVEL_2: if (newtype == IS_LEVEL_1) circuit_resign_level (circuit, 2); circuit_commence_level (circuit, 1); break; default: break; } } circuit->is_type = newtype; lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } /* 04/18/2002 by Gwak. */ /************************************************************************** * * EVENTS for LSP generation * * 1) an Adajacency or Circuit Up/Down event * 2) a chnage in Circuit metric * 3) a change in Reachable Address metric * 4) a change in manualAreaAddresses * 5) a change in systemID * 6) a change in DIS status * 7) a chnage in the waiting status * * *********************************************************************** * * current support event * * 1) Adjacency Up/Down event * 6) a change in DIS status * * ***********************************************************************/ void isis_event_adjacency_state_change (struct isis_adjacency *adj, int newstate) { /* adjacency state change event. * - the only proto-type was supported */ /* invalid arguments */ if (!adj || !adj->circuit || !adj->circuit->area) return; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) Adjacency State change", adj->circuit->area->area_tag); /* LSP generation again */ lsp_regenerate_schedule (adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } /* events supporting code */ int isis_event_dis_status_change (struct thread *thread) { struct isis_circuit *circuit; circuit = THREAD_ARG (thread); /* invalid arguments */ if (!circuit || !circuit->area) return 0; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) DIS status change", circuit->area->area_tag); /* LSP generation again */ lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return 0; } void isis_event_auth_failure (char *area_tag, const char *error_string, u_char *sysid) { if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) Authentication failure %s from %s", area_tag, error_string, sysid_print (sysid)); return; } quagga-1.2.4/isisd/isis_events.h000066400000000000000000000032431325323223500166040ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_events.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_EVENTS_H #define _ZEBRA_ISIS_EVENTS_H /* * Events related to circuit */ void isis_event_circuit_state_change (struct isis_circuit *circuit, struct isis_area *area, int state); void isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype); /* * Events related to adjacencies */ void isis_event_adjacency_state_change (struct isis_adjacency *adj, int newstate); int isis_event_dis_status_change (struct thread *thread); /* * Error events */ #define AUTH_ERROR_TYPE_LSP 3 #define AUTH_ERROR_TYPE_SNP 2 #define AUTH_ERROR_TYPE_HELLO 1 void isis_event_auth_failure (char *area_tag, const char *error_string, u_char *sysid); #endif /* _ZEBRA_ISIS_EVENTS_H */ quagga-1.2.4/isisd/isis_flags.c000066400000000000000000000041771325323223500163760ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_flags.c * Routines for manipulation of SSN and SRM flags * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "log.h" #include "linklist.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" void flags_initialize (struct flags *flags) { flags->maxindex = 0; flags->free_idcs = NULL; } long int flags_get_index (struct flags *flags) { struct listnode *node; long int index; if (flags->free_idcs == NULL || flags->free_idcs->count == 0) { index = flags->maxindex++; } else { node = listhead (flags->free_idcs); index = (long int) listgetdata (node); listnode_delete (flags->free_idcs, (void *) index); index--; } return index; } void flags_free_index (struct flags *flags, long int index) { if (index + 1 == flags->maxindex) { flags->maxindex--; return; } if (flags->free_idcs == NULL) { flags->free_idcs = list_new (); } listnode_add (flags->free_idcs, (void *) (index + 1)); return; } int flags_any_set (u_int32_t * flags) { u_int32_t zero[ISIS_MAX_CIRCUITS]; memset (zero, 0x00, ISIS_MAX_CIRCUITS * 4); return bcmp (flags, zero, ISIS_MAX_CIRCUITS * 4); } quagga-1.2.4/isisd/isis_flags.h000066400000000000000000000041361325323223500163760ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_flags.h * Routines for manipulation of SSN and SRM flags * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_FLAGS_H #define _ZEBRA_ISIS_FLAGS_H /* The grand plan is to support 1024 circuits so we have 32*32 bit flags * the support will be achived using the newest drafts */ #define ISIS_MAX_CIRCUITS 32 /* = 1024 */ /* * Flags structure for SSN and SRM flags */ struct flags { int maxindex; struct list *free_idcs; }; void flags_initialize (struct flags *flags); long int flags_get_index (struct flags *flags); void flags_free_index (struct flags *flags, long int index); int flags_any_set (u_int32_t * flags); #define ISIS_SET_FLAG(F,C) \ { \ F[C->idx>>5] |= (1<<(C->idx & 0x1F)); \ } #define ISIS_CLEAR_FLAG(F,C) \ { \ F[C->idx>>5] &= ~(1<<(C->idx & 0x1F)); \ } #define ISIS_CHECK_FLAG(F, C) (F[(C)->idx>>5] & (1<<(C->idx & 0x1F))) /* sets all u_32int_t flags to 1 */ #define ISIS_FLAGS_SET_ALL(FLAGS) \ { \ memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4); \ } #define ISIS_FLAGS_CLEAR_ALL(FLAGS) \ { \ memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4); \ } #endif /* _ZEBRA_ISIS_FLAGS_H */ quagga-1.2.4/isisd/isis_lsp.c000066400000000000000000002754531325323223500161070ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_lsp.c * LSP processing * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "thread.h" #include "vty.h" #include "stream.h" #include "memory.h" #include "log.h" #include "prefix.h" #include "command.h" #include "hash.h" #include "if.h" #include "checksum.h" #include "md5.h" #include "table.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" #include "isisd/isis_te.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" #endif /* staticly assigned vars for printing purposes */ char lsp_bits_string[200]; /* FIXME: enough ? */ static int lsp_l1_refresh (struct thread *thread); static int lsp_l2_refresh (struct thread *thread); static int lsp_l1_refresh_pseudo (struct thread *thread); static int lsp_l2_refresh_pseudo (struct thread *thread); int lsp_id_cmp (u_char * id1, u_char * id2) { return memcmp (id1, id2, ISIS_SYS_ID_LEN + 2); } dict_t * lsp_db_init (void) { dict_t *dict; dict = dict_create (DICTCOUNT_T_MAX, (dict_comp_t) lsp_id_cmp); return dict; } struct isis_lsp * lsp_search (u_char * id, dict_t * lspdb) { dnode_t *node; #ifdef EXTREME_DEBUG dnode_t *dn; zlog_debug ("searching db"); for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn)) { zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)), dnode_get (dn)); } #endif /* EXTREME DEBUG */ node = dict_lookup (lspdb, id); if (node) return (struct isis_lsp *) dnode_get (node); return NULL; } static void lsp_clear_data (struct isis_lsp *lsp) { if (!lsp) return; if (lsp->tlv_data.hostname) isis_dynhn_remove (lsp->lsp_header->lsp_id); if (lsp->own_lsp) { if (lsp->tlv_data.nlpids) XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids); if (lsp->tlv_data.hostname) XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname); if (lsp->tlv_data.router_id) XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id); } free_tlvs (&lsp->tlv_data); } static void lsp_destroy (struct isis_lsp *lsp) { struct listnode *cnode, *lnode, *lnnode; struct isis_lsp *lsp_in_list; struct isis_circuit *circuit; if (!lsp) return; if (lsp->area->circuit_list) { for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit)) { if (circuit->lsp_queue == NULL) continue; for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list)) if (lsp_in_list == lsp) list_delete_node(circuit->lsp_queue, lnode); } } ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); lsp_clear_data (lsp); if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) { list_delete (lsp->lspu.frags); lsp->lspu.frags = NULL; } isis_spf_schedule (lsp->area, lsp->level); #ifdef HAVE_IPV6 isis_spf_schedule6 (lsp->area, lsp->level); #endif if (lsp->pdu) stream_free (lsp->pdu); XFREE (MTYPE_ISIS_LSP, lsp); } void lsp_db_destroy (dict_t * lspdb) { dnode_t *dnode, *next; struct isis_lsp *lsp; dnode = dict_first (lspdb); while (dnode) { next = dict_next (lspdb, dnode); lsp = dnode_get (dnode); lsp_destroy (lsp); dict_delete_free (lspdb, dnode); dnode = next; } dict_free (lspdb); return; } /* * Remove all the frags belonging to the given lsp */ static void lsp_remove_frags (struct list *frags, dict_t * lspdb) { dnode_t *dnode; struct listnode *lnode, *lnnode; struct isis_lsp *lsp; for (ALL_LIST_ELEMENTS (frags, lnode, lnnode, lsp)) { dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id); lsp_destroy (lsp); dnode_destroy (dict_delete (lspdb, dnode)); } list_delete_all_node (frags); return; } void lsp_search_and_destroy (u_char * id, dict_t * lspdb) { dnode_t *node; struct isis_lsp *lsp; node = dict_lookup (lspdb, id); if (node) { node = dict_delete (lspdb, node); lsp = dnode_get (node); /* * If this is a zero lsp, remove all the frags now */ if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0) { if (lsp->lspu.frags) lsp_remove_frags (lsp->lspu.frags, lspdb); } else { /* * else just remove this frag, from the zero lsps' frag list */ if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags) listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp); } lsp_destroy (lsp); dnode_destroy (node); } } /* * Compares a LSP to given values * Params are given in net order */ int lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, u_int16_t checksum, u_int16_t rem_lifetime) { /* no point in double ntohl on seqnum */ if (lsp->lsp_header->seq_num == seq_num && lsp->lsp_header->checksum == checksum && /*comparing with 0, no need to do ntohl */ ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) || (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0))) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x," " lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); zlog_debug ("ISIS-Snp (%s): is equal to ours seq 0x%08x," " cksum 0x%04x, lifetime %us", areatag, ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime)); } return LSP_EQUAL; } /* * LSPs with identical checksums should only be treated as newer if: * a) The current LSP has a remaining lifetime != 0 and the other LSP has a * remaining lifetime == 0. In this case, we should participate in the purge * and should not treat the current LSP with remaining lifetime == 0 as older. * b) The LSP has an incorrect checksum. In this case, we need to react as given * in 7.3.16.2. */ if (ntohl (seq_num) > ntohl (lsp->lsp_header->seq_num) || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num) && ( (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime == 0) || lsp->lsp_header->checksum != checksum))) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x," " lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime)); zlog_debug ("ISIS-Snp (%s): is newer than ours seq 0x%08x, " "cksum 0x%04x, lifetime %us", areatag, ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); } return LSP_NEWER; } if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime)); zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x," " cksum 0x%04x, lifetime %us", areatag, ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); } return LSP_OLDER; } static void lsp_auth_add (struct isis_lsp *lsp) { struct isis_passwd *passwd; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; /* * Add the authentication info if its present */ (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) : (passwd = &lsp->area->domain_passwd); switch (passwd->type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd)); tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu); break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later * overwrite the MD5 hash */ lsp->auth_tlv_offset = stream_get_endp (lsp->pdu); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5; lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE; memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, lsp->pdu); break; default: break; } } static void lsp_auth_update (struct isis_lsp *lsp) { struct isis_passwd *passwd; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; uint16_t checksum, rem_lifetime; /* For HMAC MD5 we need to recompute the md5 hash and store it */ (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) : (passwd = &lsp->area->domain_passwd); if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5) return; /* * In transient conditions (when net is configured where authentication * config and lsp regenerate schedule is not yet run), there could be * an own_lsp with auth_tlv_offset set to 0. In such a case, simply * return, when lsp_regenerate is run, lsp will have auth tlv. */ if (lsp->auth_tlv_offset == 0) return; /* * RFC 5304 set auth value, checksum and remaining lifetime to zero * before computation and reset to old values after computation. */ checksum = lsp->lsp_header->checksum; rem_lifetime = lsp->lsp_header->rem_lifetime; lsp->lsp_header->checksum = 0; lsp->lsp_header->rem_lifetime = 0; /* Set the authentication value as well to zero */ memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3, 0, ISIS_AUTH_MD5_SIZE); /* Compute autentication value */ hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu), (unsigned char *) &passwd->passwd, passwd->len, (unsigned char *) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); /* Copy back the checksum and remaining lifetime */ lsp->lsp_header->checksum = checksum; lsp->lsp_header->rem_lifetime = rem_lifetime; } void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num) { u_int32_t newseq; if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num) newseq = ntohl (lsp->lsp_header->seq_num) + 1; else newseq = seq_num + 1; lsp->lsp_header->seq_num = htonl (newseq); /* Recompute authentication and checksum information */ lsp_auth_update (lsp); /* ISO 10589 - 7.3.11 Generation of the checksum * The checksum shall be computed over all fields in the LSP which appear * after the Remaining Lifetime field. This field (and those appearing * before it) are excluded so that the LSP may be aged by systems without * requiring recomputation. */ fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); isis_spf_schedule (lsp->area, lsp->level); #ifdef HAVE_IPV6 isis_spf_schedule6 (lsp->area, lsp->level); #endif return; } /* * Genetates checksum for LSP and its frags */ static void lsp_seqnum_update (struct isis_lsp *lsp0) { struct isis_lsp *lsp; struct listnode *node; lsp_inc_seqnum (lsp0, 0); if (!lsp0->lspu.frags) return; for (ALL_LIST_ELEMENTS_RO (lsp0->lspu.frags, node, lsp)) lsp_inc_seqnum (lsp, 0); return; } static u_int8_t lsp_bits_generate (int level, int overload_bit, int attached_bit) { u_int8_t lsp_bits = 0; if (level == IS_LEVEL_1) lsp_bits = IS_LEVEL_1; else lsp_bits = IS_LEVEL_1_AND_2; if (overload_bit) lsp_bits |= overload_bit; if (attached_bit) lsp_bits |= attached_bit; return lsp_bits; } static void lsp_update_data (struct isis_lsp *lsp, struct stream *stream, struct isis_area *area, int level) { uint32_t expected = 0, found; int retval; /* free the old lsp data */ lsp_clear_data (lsp); /* copying only the relevant part of our stream */ if (lsp->pdu != NULL) stream_free (lsp->pdu); lsp->pdu = stream_dup (stream); /* setting pointers to the correct place */ lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu)); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); lsp->area = area; lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; lsp->installed = time (NULL); /* * Get LSP data i.e. TLVs */ expected |= TLVFLAG_AUTH_INFO; expected |= TLVFLAG_AREA_ADDRS; expected |= TLVFLAG_IS_NEIGHS; expected |= TLVFLAG_NLPID; if (area->dynhostname) expected |= TLVFLAG_DYN_HOSTNAME; if (area->newmetric) { expected |= TLVFLAG_TE_IS_NEIGHS; expected |= TLVFLAG_TE_IPV4_REACHABILITY; expected |= TLVFLAG_TE_ROUTER_ID; } expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV4_INT_REACHABILITY; expected |= TLVFLAG_IPV4_EXT_REACHABILITY; #ifdef HAVE_IPV6 expected |= TLVFLAG_IPV6_ADDR; expected |= TLVFLAG_IPV6_REACHABILITY; #endif /* HAVE_IPV6 */ retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, ntohs (lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &lsp->tlv_data, NULL); if (retval != ISIS_OK) { zlog_warn ("Could not parse LSP"); return; } if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) { isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, (lsp->lsp_header->lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1); } return; } void lsp_update (struct isis_lsp *lsp, struct stream *stream, struct isis_area *area, int level) { dnode_t *dnode = NULL; /* Remove old LSP from database. This is required since the * lsp_update_data will free the lsp->pdu (which has the key, lsp_id) * and will update it with the new data in the stream. */ dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id); if (dnode) dnode_destroy (dict_delete (area->lspdb[level - 1], dnode)); /* rebuild the lsp data */ lsp_update_data (lsp, stream, area, level); /* insert the lsp back into the database */ lsp_insert (lsp, area->lspdb[level - 1]); } /* creation of LSP directly from what we received */ struct isis_lsp * lsp_new_from_stream_ptr (struct stream *stream, u_int16_t pdu_len, struct isis_lsp *lsp0, struct isis_area *area, int level) { struct isis_lsp *lsp; lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); lsp_update_data (lsp, stream, area, level); if (lsp0 == NULL) { /* * zero lsp -> create the list for fragments */ lsp->lspu.frags = list_new (); } else { /* * a fragment -> set the backpointer and add this to zero lsps frag list */ lsp->lspu.zero_lsp = lsp0; listnode_add (lsp0->lspu.frags, lsp); } return lsp; } struct isis_lsp * lsp_new(struct isis_area *area, u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, u_int8_t lsp_bits, u_int16_t checksum, int level) { struct isis_lsp *lsp; lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); lsp->area = area; lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); if (LSP_FRAGMENT (lsp_id) == 0) lsp->lspu.frags = list_new (); lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu)); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); /* at first we fill the FIXED HEADER */ (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) : fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE); /* now for the LSP HEADER */ /* Minimal LSP PDU size */ lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2); lsp->lsp_header->checksum = checksum; /* Provided in network order */ lsp->lsp_header->seq_num = htonl (seq_num); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp->lsp_header->lsp_bits = lsp_bits; lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); if (isis->debugs & DEBUG_EVENTS) zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x", sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id), LSP_FRAGMENT (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num)); return lsp; } void lsp_insert (struct isis_lsp *lsp, dict_t * lspdb) { dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp); if (lsp->lsp_header->seq_num != 0) { isis_spf_schedule (lsp->area, lsp->level); #ifdef HAVE_IPV6 isis_spf_schedule6 (lsp->area, lsp->level); #endif } } /* * Build a list of LSPs with non-zero ht bounded by start and stop ids */ void lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id, struct list *list, dict_t * lspdb) { dnode_t *first, *last, *curr; first = dict_lower_bound (lspdb, start_id); if (!first) return; last = dict_upper_bound (lspdb, stop_id); curr = first; if (((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime) listnode_add (list, first->dict_data); while (curr) { curr = dict_next (lspdb, curr); if (curr && ((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime) listnode_add (list, curr->dict_data); if (curr == last) break; } return; } /* * Build a list of num_lsps LSPs bounded by start_id and stop_id. */ void lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps, struct list *list, dict_t * lspdb) { u_char count; dnode_t *first, *last, *curr; first = dict_lower_bound (lspdb, start_id); if (!first) return; last = dict_upper_bound (lspdb, stop_id); curr = first; listnode_add (list, first->dict_data); count = 1; while (curr) { curr = dict_next (lspdb, curr); if (curr) { listnode_add (list, curr->dict_data); count++; } if (count == num_lsps || curr == last) break; } return; } /* * Build a list of LSPs with SSN flag set for the given circuit */ void lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps, struct list *list, dict_t * lspdb) { dnode_t *dnode, *next; struct isis_lsp *lsp; u_char count = 0; dnode = dict_first (lspdb); while (dnode != NULL) { next = dict_next (lspdb, dnode); lsp = dnode_get (dnode); if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit)) { listnode_add (list, lsp); ++count; } if (count == num_lsps) break; dnode = next; } return; } static void lsp_set_time (struct isis_lsp *lsp) { assert (lsp); if (lsp->lsp_header->rem_lifetime == 0) { if (lsp->age_out > 0) lsp->age_out--; return; } lsp->lsp_header->rem_lifetime = htons (ntohs (lsp->lsp_header->rem_lifetime) - 1); } static void lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag) { struct isis_dynhn *dyn = NULL; u_char id[SYSID_STRLEN]; if (dynhost) dyn = dynhn_find_by_id (lsp_id); else dyn = NULL; if (dyn) sprintf ((char *)id, "%.14s", dyn->name.name); else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost) sprintf ((char *)id, "%.14s", unix_hostname ()); else memcpy (id, sysid_print (lsp_id), 15); if (frag) sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id), LSP_FRAGMENT (lsp_id)); else sprintf ((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID (lsp_id)); } /* Convert the lsp attribute bits to attribute string */ const char * lsp_bits2string (u_char * lsp_bits) { char *pos = lsp_bits_string; if (!*lsp_bits) return " none"; /* we only focus on the default metric */ pos += sprintf (pos, "%d/", ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits) ? 1 : 0); pos += sprintf (pos, "%d/", ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits) ? 1 : 0); pos += sprintf (pos, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits) ? 1 : 0); *(pos) = '\0'; return lsp_bits_string; } /* this function prints the lsp on show isis database */ void lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost) { u_char LSPid[255]; char age_out[8]; lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1); vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' '); vty_out (vty, "%5u ", ntohs (lsp->lsp_header->pdu_len)); vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num)); vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum)); if (ntohs (lsp->lsp_header->rem_lifetime) == 0) { snprintf (age_out, 8, "(%u)", lsp->age_out); age_out[7] = '\0'; vty_out (vty, "%7s ", age_out); } else vty_out (vty, " %5u ", ntohs (lsp->lsp_header->rem_lifetime)); vty_out (vty, "%s%s", lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE); } void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) { struct area_addr *area_addr; int i; struct listnode *lnode; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct ipv4_reachability *ipv4_reach; struct in_addr *ipv4_addr; struct te_ipv4_reachability *te_ipv4_reach; #ifdef HAVE_IPV6 struct ipv6_reachability *ipv6_reach; struct in6_addr in6; u_char buff[BUFSIZ]; #endif u_char LSPid[255]; u_char hostname[255]; u_char ipv4_reach_prefix[20]; u_char ipv4_reach_mask[20]; u_char ipv4_address[20]; lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1); lsp_print (lsp, vty, dynhost); /* for all area address */ if (lsp->tlv_data.area_addrs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.area_addrs, lnode, area_addr)) { vty_out (vty, " Area Address: %s%s", isonet_print (area_addr->area_addr, area_addr->addr_len), VTY_NEWLINE); } /* for the nlpid tlv */ if (lsp->tlv_data.nlpids) { for (i = 0; i < lsp->tlv_data.nlpids->count; i++) { switch (lsp->tlv_data.nlpids->nlpids[i]) { case NLPID_IP: case NLPID_IPV6: vty_out (vty, " NLPID : 0x%X%s", lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE); break; default: vty_out (vty, " NLPID : %s%s", "unknown", VTY_NEWLINE); break; } } } /* for the hostname tlv */ if (lsp->tlv_data.hostname) { bzero (hostname, sizeof (hostname)); memcpy (hostname, lsp->tlv_data.hostname->name, lsp->tlv_data.hostname->namelen); vty_out (vty, " Hostname : %s%s", hostname, VTY_NEWLINE); } /* authentication tlv */ if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED) { if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5) vty_out (vty, " Auth type : md5%s", VTY_NEWLINE); else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT) vty_out (vty, " Auth type : clear text%s", VTY_NEWLINE); } /* TE router id */ if (lsp->tlv_data.router_id) { memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id), sizeof (ipv4_address)); vty_out (vty, " Router ID : %s%s", ipv4_address, VTY_NEWLINE); } if (lsp->tlv_data.ipv4_addrs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr)) { memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address)); vty_out (vty, " IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE); } /* for the IS neighbor tlv */ if (lsp->tlv_data.is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh)) { lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0); vty_out (vty, " Metric : %-8d IS : %s%s", is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE); } /* for the internal reachable tlv */ if (lsp->tlv_data.ipv4_int_reachs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode, ipv4_reach)) { memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix), sizeof (ipv4_reach_prefix)); memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask), sizeof (ipv4_reach_mask)); vty_out (vty, " Metric : %-8d IPv4-Internal : %s %s%s", ipv4_reach->metrics.metric_default, ipv4_reach_prefix, ipv4_reach_mask, VTY_NEWLINE); } /* for the external reachable tlv */ if (lsp->tlv_data.ipv4_ext_reachs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode, ipv4_reach)) { memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix), sizeof (ipv4_reach_prefix)); memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask), sizeof (ipv4_reach_mask)); vty_out (vty, " Metric : %-8d IPv4-External : %s %s%s", ipv4_reach->metrics.metric_default, ipv4_reach_prefix, ipv4_reach_mask, VTY_NEWLINE); } /* IPv6 tlv */ #ifdef HAVE_IPV6 if (lsp->tlv_data.ipv6_reachs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach)) { memset (&in6, 0, sizeof (in6)); memcpy (in6.s6_addr, ipv6_reach->prefix, PSIZE (ipv6_reach->prefix_len)); inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ); if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL) vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s", ntohl (ipv6_reach->metric), buff, ipv6_reach->prefix_len, VTY_NEWLINE); else vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s", ntohl (ipv6_reach->metric), buff, ipv6_reach->prefix_len, VTY_NEWLINE); } #endif /* TE IS neighbor tlv */ if (lsp->tlv_data.te_is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh)) { lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0); vty_out (vty, " Metric : %-8d IS-Extended : %s%s", GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE); if (IS_MPLS_TE(isisMplsTE)) mpls_te_print_detail(vty, te_is_neigh); } /* TE IPv4 tlv */ if (lsp->tlv_data.te_ipv4_reachs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode, te_ipv4_reach)) { /* FIXME: There should be better way to output this stuff. */ vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s", ntohl (te_ipv4_reach->te_metric), inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start, te_ipv4_reach->control)), te_ipv4_reach->control & 0x3F, VTY_NEWLINE); } vty_out (vty, "%s", VTY_NEWLINE); return; } /* print all the lsps info in the local lspdb */ int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost) { dnode_t *node = dict_first (lspdb), *next; int lsp_count = 0; if (detail == ISIS_UI_LEVEL_BRIEF) { while (node != NULL) { /* I think it is unnecessary, so I comment it out */ /* dict_contains (lspdb, node); */ next = dict_next (lspdb, node); lsp_print (dnode_get (node), vty, dynhost); node = next; lsp_count++; } } else if (detail == ISIS_UI_LEVEL_DETAIL) { while (node != NULL) { next = dict_next (lspdb, node); lsp_print_detail (dnode_get (node), vty, dynhost); node = next; lsp_count++; } } return lsp_count; } #define FRAG_THOLD(S,T) \ ((STREAM_SIZE(S)*T)/100) /* stream*, area->lsp_frag_threshold, increment */ #define FRAG_NEEDED(S,T,I) \ (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T)) /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have * variable length (TE TLVs, sub TLVs). */ static void lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int tlvsize, int frag_thold, int tlv_build_func (struct list *, struct stream *)) { int count, i; /* can we fit all ? */ if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2)) { tlv_build_func (*from, lsp->pdu); if (listcount (*to) != 0) { struct listnode *node, *nextnode; void *elem; for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) { listnode_add (*to, elem); list_delete_node (*from, node); } } else { list_free (*to); *to = *from; *from = NULL; } } else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2)) { /* fit all we can */ count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 - (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu)); count = count / tlvsize; if (count > (int)listcount (*from)) count = listcount (*from); for (i = 0; i < count; i++) { listnode_add (*to, listgetdata (listhead (*from))); listnode_delete (*from, listgetdata (listhead (*from))); } tlv_build_func (*to, lsp->pdu); } lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); return; } /* Process IS_NEIGHBOURS TLV with TE subTLVs */ static void lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold) { int count, size = 0; struct listnode *node, *nextnode; struct te_is_neigh *elem; /* Start computing real size of TLVs */ for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN; /* can we fit all ? */ if (!FRAG_NEEDED (lsp->pdu, frag_thold, size)) { tlv_add_te_is_neighs (*from, lsp->pdu); if (listcount (*to) != 0) { for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) { listnode_add (*to, elem); list_delete_node (*from, node); } } else { list_free (*to); *to = *from; *from = NULL; } } else { /* fit all we can */ /* Compute remaining place in LSP PDU */ count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 - (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu)); /* Determine size of TE SubTLVs */ elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from)); count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN; if (count > 0) { while (count > 0) { listnode_add (*to, listgetdata ((struct listnode *)listhead (*from))); listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from))); elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from)); count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN; } tlv_add_te_is_neighs (*to, lsp->pdu); } } lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); return; } static u_int16_t lsp_rem_lifetime (struct isis_area *area, int level) { u_int16_t rem_lifetime; /* Add jitter to configured LSP lifetime */ rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1], MAX_AGE_JITTER); /* No jitter if the max refresh will be less than configure gen interval */ /* N.B. this calucation is acceptable since rem_lifetime is in [332,65535] at * this point */ if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300)) rem_lifetime = area->max_lsp_lifetime[level - 1]; return rem_lifetime; } static u_int16_t lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime) { struct isis_area *area = lsp->area; int level = lsp->level; u_int16_t refresh_time; /* Add jitter to LSP refresh time */ refresh_time = isis_jitter (area->lsp_refresh[level - 1], MAX_LSP_GEN_JITTER); /* RFC 4444 : make sure the refresh time is at least less than 300 * of the remaining lifetime and more than gen interval */ if (refresh_time <= area->lsp_gen_interval[level - 1] || refresh_time > (rem_lifetime - 300)) refresh_time = rem_lifetime - 300; /* In cornercases, refresh_time might be <= lsp_gen_interval, however * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */ return refresh_time; } static struct isis_lsp * lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, int level) { struct isis_lsp *lsp; u_char frag_id[ISIS_SYS_ID_LEN + 2]; memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (frag_id) = frag_num; /* FIXME add authentication TLV for fragment LSPs */ lsp = lsp_search (frag_id, area->lspdb[level - 1]); if (lsp) { /* Clear the TLVs */ lsp_clear_data (lsp); return lsp; } lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, lsp_bits_generate (level, area->overload_bit, area->attached_bit), 0, level); lsp->area = area; lsp->own_lsp = 1; lsp_insert (lsp, area->lspdb[level - 1]); listnode_add (lsp0->lspu.frags, lsp); lsp->lspu.zero_lsp = lsp0; return lsp; } static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area, struct tlvs *tlv_data) { struct route_table *er_table; struct route_node *rn; struct prefix_ipv4 *ipv4; struct isis_ext_info *info; struct ipv4_reachability *ipreach; struct te_ipv4_reachability *te_ipreach; er_table = get_ext_reach(area, AF_INET, lsp->level); if (!er_table) return; for (rn = route_top(er_table); rn; rn = route_next(rn)) { if (!rn->info) continue; ipv4 = (struct prefix_ipv4*)&rn->p; info = rn->info; if (area->oldmetric) { if (tlv_data->ipv4_ext_reachs == NULL) { tlv_data->ipv4_ext_reachs = list_new(); tlv_data->ipv4_ext_reachs->del = free_tlv; } ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach)); ipreach->prefix.s_addr = ipv4->prefix.s_addr; masklen2ip(ipv4->prefixlen, &ipreach->mask); ipreach->prefix.s_addr &= ipreach->mask.s_addr; if ((info->metric & 0x3f) != info->metric) ipreach->metrics.metric_default = 0x3f; else ipreach->metrics.metric_default = info->metric; ipreach->metrics.metric_expense = METRICS_UNSUPPORTED; ipreach->metrics.metric_error = METRICS_UNSUPPORTED; ipreach->metrics.metric_delay = METRICS_UNSUPPORTED; listnode_add(tlv_data->ipv4_ext_reachs, ipreach); } if (area->newmetric) { if (tlv_data->te_ipv4_reachs == NULL) { tlv_data->te_ipv4_reachs = list_new(); tlv_data->te_ipv4_reachs->del = free_tlv; } te_ipreach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen)); if (info->metric > MAX_WIDE_PATH_METRIC) te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC); else te_ipreach->te_metric = htonl(info->metric); te_ipreach->control = ipv4->prefixlen & 0x3f; memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr, PSIZE(ipv4->prefixlen)); listnode_add(tlv_data->te_ipv4_reachs, te_ipreach); } } } static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area, struct tlvs *tlv_data) { struct route_table *er_table; struct route_node *rn; struct prefix_ipv6 *ipv6; struct isis_ext_info *info; struct ipv6_reachability *ip6reach; er_table = get_ext_reach(area, AF_INET6, lsp->level); if (!er_table) return; for (rn = route_top(er_table); rn; rn = route_next(rn)) { if (!rn->info) continue; ipv6 = (struct prefix_ipv6*)&rn->p; info = rn->info; if (tlv_data->ipv6_reachs == NULL) { tlv_data->ipv6_reachs = list_new(); tlv_data->ipv6_reachs->del = free_tlv; } ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach)); if (info->metric > MAX_WIDE_PATH_METRIC) ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC); else ip6reach->metric = htonl(info->metric); ip6reach->control_info = DISTRIBUTION_EXTERNAL; ip6reach->prefix_len = ipv6->prefixlen; memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix)); listnode_add(tlv_data->ipv6_reachs, ip6reach); } } static void lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area, struct tlvs *tlv_data) { lsp_build_ext_reach_ipv4(lsp, area, tlv_data); lsp_build_ext_reach_ipv6(lsp, area, tlv_data); } /* * Builds the LSP data part. This func creates a new frag whenever * area->lsp_frag_threshold is exceeded. */ static void lsp_build (struct isis_lsp *lsp, struct isis_area *area) { struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct listnode *node, *ipnode; int level = lsp->level; struct isis_circuit *circuit; struct prefix_ipv4 *ipv4; struct ipv4_reachability *ipreach; struct te_ipv4_reachability *te_ipreach; struct isis_adjacency *nei; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6, ip6prefix; struct ipv6_reachability *ip6reach; #endif /* HAVE_IPV6 */ struct tlvs tlv_data; struct isis_lsp *lsp0 = lsp; struct in_addr *routerid; uint32_t expected = 0, found = 0; uint32_t metric; u_char zero_id[ISIS_SYS_ID_LEN + 1]; int retval = ISIS_OK; char buf[BUFSIZ]; lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level); /* * Building the zero lsp */ memset (zero_id, 0, ISIS_SYS_ID_LEN + 1); /* Reset stream endp. Stream is always there and on every LSP refresh only * TLV part of it is overwritten. So we must seek past header we will not * touch. */ stream_reset (lsp->pdu); stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Add the authentication info if its present */ lsp_auth_add (lsp); /* * First add the tlvs related to area */ /* Area addresses */ if (lsp->tlv_data.area_addrs == NULL) lsp->tlv_data.area_addrs = list_new (); list_add_list (lsp->tlv_data.area_addrs, area->area_addrs); if (listcount (lsp->tlv_data.area_addrs) > 0) tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu); /* Protocols Supported */ if (area->ip_circuits > 0 #ifdef HAVE_IPV6 || area->ipv6_circuits > 0 #endif /* HAVE_IPV6 */ ) { lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids)); lsp->tlv_data.nlpids->count = 0; if (area->ip_circuits > 0) { lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag); lsp->tlv_data.nlpids->count++; lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP; } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0) { lsp_debug("ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area->area_tag); lsp->tlv_data.nlpids->count++; lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] = NLPID_IPV6; } #endif /* HAVE_IPV6 */ tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu); } /* Dynamic Hostname */ if (area->dynhostname) { const char *hostname = unix_hostname(); size_t hostname_len = strlen(hostname); lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct hostname)); strncpy((char *)lsp->tlv_data.hostname->name, hostname, sizeof(lsp->tlv_data.hostname->name)); if (hostname_len <= MAX_TLV_LEN) lsp->tlv_data.hostname->namelen = hostname_len; else lsp->tlv_data.hostname->namelen = MAX_TLV_LEN; lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area->area_tag, lsp->tlv_data.hostname->namelen, lsp->tlv_data.hostname->name); tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); } else { lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag); } /* IPv4 address and TE router ID TLVs. In case of the first one we don't * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into * LSP and this address is same as router id. */ if (isis->router_id != 0) { inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf)); lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area->area_tag, buf); if (lsp->tlv_data.ipv4_addrs == NULL) { lsp->tlv_data.ipv4_addrs = list_new (); lsp->tlv_data.ipv4_addrs->del = free_tlv; } routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr)); routerid->s_addr = isis->router_id; listnode_add (lsp->tlv_data.ipv4_addrs, routerid); tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR); /* Exactly same data is put into TE router ID TLV, but only if new style * TLV's are in use. */ if (area->newmetric) { lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag); lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr)); lsp->tlv_data.router_id->id.s_addr = isis->router_id; tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu, TE_ROUTER_ID); } } else { lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag); } memset (&tlv_data, 0, sizeof (struct tlvs)); #ifdef TOPOLOGY_GENERATE /* If topology exists (and we create topology for level 1 only), create * (hardcoded) link to topology. */ if (area->topology && level == IS_LEVEL_1) { if (tlv_data.is_neighs == NULL) { tlv_data.is_neighs = list_new (); tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN); is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (1 & 0xFF); is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((1 >> 8) & 0xFF); is_neigh->metrics.metric_default = 0x01; is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); } #endif /* TOPOLOGY_GENERATE */ lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag); /* * Then build lists of tlvs related to circuits */ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) { if (!circuit->interface) lsp_debug("ISIS (%s): Processing %s circuit %p with unknown interface", area->area_tag, circuit_type2string(circuit->circ_type), circuit); else lsp_debug("ISIS (%s): Processing %s circuit %s", area->area_tag, circuit_type2string(circuit->circ_type), circuit->interface->name); if (circuit->state != C_STATE_UP) { lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area->area_tag); continue; } /* * Add IPv4 internal reachability of this circuit */ if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) { lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag); if (area->oldmetric) { if (tlv_data.ipv4_int_reachs == NULL) { tlv_data.ipv4_int_reachs = list_new (); tlv_data.ipv4_int_reachs->del = free_tlv; } for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4)) { ipreach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability)); ipreach->metrics.metric_default = circuit->metric[level - 1]; ipreach->metrics.metric_expense = METRICS_UNSUPPORTED; ipreach->metrics.metric_error = METRICS_UNSUPPORTED; ipreach->metrics.metric_delay = METRICS_UNSUPPORTED; masklen2ip (ipv4->prefixlen, &ipreach->mask); ipreach->prefix.s_addr = ((ipreach->mask.s_addr) & (ipv4->prefix.s_addr)); inet_ntop(AF_INET, &ipreach->prefix.s_addr, buf, sizeof(buf)); lsp_debug("ISIS (%s): Adding old-style IP reachability for %s/%d", area->area_tag, buf, ipv4->prefixlen); listnode_add (tlv_data.ipv4_int_reachs, ipreach); } } if (area->newmetric) { if (tlv_data.te_ipv4_reachs == NULL) { tlv_data.te_ipv4_reachs = list_new (); tlv_data.te_ipv4_reachs->del = free_tlv; } for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4)) { /* FIXME All this assumes that we have no sub TLVs. */ te_ipreach = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_ipv4_reachability) + ((ipv4->prefixlen + 7)/8) - 1); if (area->oldmetric) te_ipreach->te_metric = htonl (circuit->metric[level - 1]); else te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]); te_ipreach->control = (ipv4->prefixlen & 0x3F); memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr, (ipv4->prefixlen + 7)/8); inet_ntop(AF_INET, &ipv4->prefix.s_addr, buf, sizeof(buf)); lsp_debug("ISIS (%s): Adding te-style IP reachability for %s/%d", area->area_tag, buf, ipv4->prefixlen); listnode_add (tlv_data.te_ipv4_reachs, te_ipreach); } } } #ifdef HAVE_IPV6 /* * Add IPv6 reachability of this circuit */ if (circuit->ipv6_router && circuit->ipv6_non_link && circuit->ipv6_non_link->count > 0) { if (tlv_data.ipv6_reachs == NULL) { tlv_data.ipv6_reachs = list_new (); tlv_data.ipv6_reachs->del = free_tlv; } for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6)) { ip6reach = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability)); if (area->oldmetric) ip6reach->metric = htonl (circuit->metric[level - 1]); else ip6reach->metric = htonl (circuit->te_metric[level - 1]); ip6reach->control_info = 0; ip6reach->prefix_len = ipv6->prefixlen; memcpy(&ip6prefix, ipv6, sizeof(ip6prefix)); apply_mask_ipv6(&ip6prefix); inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, buf, sizeof(buf)); lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d", area->area_tag, buf, ipv6->prefixlen); memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr, sizeof (ip6reach->prefix)); listnode_add (tlv_data.ipv6_reachs, ip6reach); } } #endif /* HAVE_IPV6 */ switch (circuit->circ_type) { case CIRCUIT_T_BROADCAST: if (level & circuit->is_type) { if (area->oldmetric) { if (tlv_data.is_neighs == NULL) { tlv_data.is_neighs = list_new (); tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); if (level == IS_LEVEL_1) memcpy (is_neigh->neigh_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); is_neigh->metrics.metric_default = circuit->metric[level - 1]; is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; if (!memcmp (is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) { XFREE (MTYPE_ISIS_TLV, is_neigh); lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.", area->area_tag); } else { listnode_add (tlv_data.is_neighs, is_neigh); lsp_debug("ISIS (%s): Adding DIS %s.%02x as old-style neighbor", area->area_tag, sysid_print(is_neigh->neigh_id), LSP_PSEUDO_ID(is_neigh->neigh_id)); } } if (area->newmetric) { if (tlv_data.te_is_neighs == NULL) { tlv_data.te_is_neighs = list_new (); tlv_data.te_is_neighs->del = free_tlv; } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); if (level == IS_LEVEL_1) memcpy (te_is_neigh->neigh_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (te_is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); if (area->oldmetric) metric = circuit->metric[level - 1]; else metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); if (!memcmp (te_is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) { XFREE (MTYPE_ISIS_TLV, te_is_neigh); lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.", area->area_tag); } else { /* Check if MPLS_TE is activate */ if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface)) /* Add SubTLVs & Adjust real size of SubTLVs */ te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc); else /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */ te_is_neigh->sub_tlvs_length = 0; listnode_add (tlv_data.te_is_neighs, te_is_neigh); lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor", area->area_tag, sysid_print(te_is_neigh->neigh_id), LSP_PSEUDO_ID(te_is_neigh->neigh_id)); } } } else { lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors", area->area_tag); } break; case CIRCUIT_T_P2P: nei = circuit->u.p2p.neighbor; if (nei && (level & nei->circuit_t)) { if (area->oldmetric) { if (tlv_data.is_neighs == NULL) { tlv_data.is_neighs = list_new (); tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); is_neigh->metrics.metric_default = circuit->metric[level - 1]; is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag, sysid_print(is_neigh->neigh_id)); } if (area->newmetric) { uint32_t metric; if (tlv_data.te_is_neighs == NULL) { tlv_data.te_is_neighs = list_new (); tlv_data.te_is_neighs->del = free_tlv; } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); /* Check if MPLS_TE is activate */ if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface)) /* Update Local and Remote IP address for MPLS TE circuit parameters */ /* NOTE sure that it is the pertinent place for that updates */ /* Local IP address could be updated in isis_circuit.c - isis_circuit_add_addr() */ /* But, where update remote IP address ? in isis_pdu.c - process_p2p_hello() ? */ /* Add SubTLVs & Adjust real size of SubTLVs */ te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc); else /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */ te_is_neigh->sub_tlvs_length = 0; listnode_add (tlv_data.te_is_neighs, te_is_neigh); lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag, sysid_print(te_is_neigh->neigh_id)); } } else { lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors", area->area_tag); } break; case CIRCUIT_T_LOOPBACK: break; default: zlog_warn ("lsp_area_create: unknown circuit type"); } } lsp_build_ext_reach(lsp, area, &tlv_data); lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag); while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs)) { if (lsp->tlv_data.ipv4_int_reachs == NULL) lsp->tlv_data.ipv4_int_reachs = list_new (); lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs, &lsp->tlv_data.ipv4_int_reachs, IPV4_REACH_LEN, area->lsp_frag_threshold, tlv_add_ipv4_int_reachs); if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs)) { if (lsp->tlv_data.ipv4_ext_reachs == NULL) lsp->tlv_data.ipv4_ext_reachs = list_new (); lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs, &lsp->tlv_data.ipv4_ext_reachs, IPV4_REACH_LEN, area->lsp_frag_threshold, tlv_add_ipv4_ext_reachs); if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit() * for now. lsp_tlv_fit() needs to be fixed to deal with variable length * TLVs (sub TLVs!). */ while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs)) { if (lsp->tlv_data.te_ipv4_reachs == NULL) lsp->tlv_data.te_ipv4_reachs = list_new (); lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, &lsp->tlv_data.te_ipv4_reachs, TE_IPV4_REACH_LEN, area->lsp_frag_threshold, tlv_add_te_ipv4_reachs); if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } #ifdef HAVE_IPV6 while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs)) { if (lsp->tlv_data.ipv6_reachs == NULL) lsp->tlv_data.ipv6_reachs = list_new (); lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs, IPV6_REACH_LEN, area->lsp_frag_threshold, tlv_add_ipv6_reachs); if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } #endif /* HAVE_IPV6 */ while (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) { if (lsp->tlv_data.is_neighs == NULL) lsp->tlv_data.is_neighs = list_new (); lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs, IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, tlv_add_is_neighs); if (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) { if (lsp->tlv_data.te_is_neighs == NULL) lsp->tlv_data.te_is_neighs = list_new (); lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs, IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, tlv_add_te_is_neighs); if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); free_tlvs (&tlv_data); /* Validate the LSP */ retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, stream_get_endp (lsp->pdu) - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &tlv_data, NULL); assert (retval == ISIS_OK); return; } /* * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs */ int lsp_generate (struct isis_area *area, int level) { struct isis_lsp *oldlsp, *newlsp; u_int32_t seq_num = 0; u_char lspid[ISIS_SYS_ID_LEN + 2]; u_int16_t rem_lifetime, refresh_time; if ((area == NULL) || (area->is_type & level) != level) return ISIS_ERROR; memset (&lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN); /* only builds the lsp if the area shares the level */ oldlsp = lsp_search (lspid, area->lspdb[level - 1]); if (oldlsp) { /* FIXME: we should actually initiate a purge */ seq_num = ntohl (oldlsp->lsp_header->seq_num); lsp_search_and_destroy (oldlsp->lsp_header->lsp_id, area->lspdb[level - 1]); } rem_lifetime = lsp_rem_lifetime (area, level); newlsp = lsp_new (area, lspid, rem_lifetime, seq_num, area->is_type | area->overload_bit | area->attached_bit, 0, level); newlsp->area = area; newlsp->own_lsp = 1; lsp_insert (newlsp, area->lspdb[level - 1]); /* build_lsp_data (newlsp, area); */ lsp_build (newlsp, area); /* time to calculate our checksum */ lsp_seqnum_update (newlsp); newlsp->last_generated = time(NULL); lsp_set_all_srmflags (newlsp); refresh_time = lsp_refresh_time (newlsp, rem_lifetime); THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); area->lsp_regenerate_pending[level - 1] = 0; if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l1_refresh, area, refresh_time); else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l2_refresh, area, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, " "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us", area->area_tag, level, rawlspid_print (newlsp->lsp_header->lsp_id), ntohl (newlsp->lsp_header->pdu_len), ntohl (newlsp->lsp_header->seq_num), ntohs (newlsp->lsp_header->checksum), ntohs (newlsp->lsp_header->rem_lifetime), refresh_time); } sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.", area->area_tag, level); return ISIS_OK; } /* * Search own LSPs, update holding time and set SRM */ static int lsp_regenerate (struct isis_area *area, int level) { dict_t *lspdb; struct isis_lsp *lsp, *frag; struct listnode *node; u_char lspid[ISIS_SYS_ID_LEN + 2]; u_int16_t rem_lifetime, refresh_time; if ((area == NULL) || (area->is_type & level) != level) return ISIS_ERROR; lspdb = area->lspdb[level - 1]; memset (lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); lsp = lsp_search (lspid, lspdb); if (!lsp) { zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!", area->area_tag, level); return ISIS_ERROR; } lsp_clear_data (lsp); lsp_build (lsp, area); lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit, area->attached_bit); rem_lifetime = lsp_rem_lifetime (area, level); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_seqnum_update (lsp); lsp->last_generated = time (NULL); lsp_set_all_srmflags (lsp); for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag)) { frag->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit, area->attached_bit); /* Set the lifetime values of all the fragments to the same value, * so that no fragment expires before the lsp is refreshed. */ frag->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_set_all_srmflags (frag); } refresh_time = lsp_refresh_time (lsp, rem_lifetime); if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l1_refresh, area, refresh_time); else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l2_refresh, area, refresh_time); area->lsp_regenerate_pending[level - 1] = 0; if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, " "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us", area->area_tag, level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime), refresh_time); } sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.", area->area_tag, level); return ISIS_OK; } /* * Something has changed or periodic refresh -> regenerate LSP */ static int lsp_l1_refresh (struct thread *thread) { struct isis_area *area; area = THREAD_ARG (thread); assert (area); area->t_lsp_refresh[0] = NULL; area->lsp_regenerate_pending[0] = 0; if ((area->is_type & IS_LEVEL_1) == 0) return ISIS_ERROR; sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area->area_tag); return lsp_regenerate (area, IS_LEVEL_1); } static int lsp_l2_refresh (struct thread *thread) { struct isis_area *area; area = THREAD_ARG (thread); assert (area); area->t_lsp_refresh[1] = NULL; area->lsp_regenerate_pending[1] = 0; if ((area->is_type & IS_LEVEL_2) == 0) return ISIS_ERROR; sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area->area_tag); return lsp_regenerate (area, IS_LEVEL_2); } int lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo) { struct isis_lsp *lsp; u_char id[ISIS_SYS_ID_LEN + 2]; time_t now, diff; long timeout; struct listnode *cnode; struct isis_circuit *circuit; int lvl; if (area == NULL) return ISIS_ERROR; sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs", area->area_tag, circuit_t2string(level), all_pseudo ? "" : "not "); memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0; now = time (NULL); for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { if (!((level & lvl) && (area->is_type & lvl))) continue; sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled", area->area_tag, lvl); if (area->lsp_regenerate_pending[lvl - 1]) { struct timeval remain = thread_timer_remain(area->t_lsp_refresh[lvl - 1]); sched_debug("ISIS (%s): Regeneration is already pending, nothing todo." " (Due in %lld.%03lld seconds)", area->area_tag, (long long)remain.tv_sec, (long long)remain.tv_usec / 1000); continue; } lsp = lsp_search (id, area->lspdb[lvl - 1]); if (!lsp) { sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.", area->area_tag); continue; } /* * Throttle avoidance */ sched_debug("ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld", area->area_tag, (long long)lsp->last_generated, (long long)now); THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]); diff = now - lsp->last_generated; if (diff < area->lsp_gen_interval[lvl - 1]) { timeout = 1000 * (area->lsp_gen_interval[lvl - 1] - diff); sched_debug("ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval", area->area_tag, timeout); } else { /* * lsps are not regenerated if lsp_regenerate function is called * directly. However if the lsp_regenerate call is queued for * later execution it works. */ timeout = 100; sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago." " Scheduling for execution in %ld ms.", area->area_tag, timeout); } area->lsp_regenerate_pending[lvl - 1] = 1; if (lvl == IS_LEVEL_1) { THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1], lsp_l1_refresh, area, timeout); } else if (lvl == IS_LEVEL_2) { THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1], lsp_l2_refresh, area, timeout); } } if (all_pseudo) { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) lsp_regenerate_schedule_pseudo (circuit, level); } return ISIS_OK; } /* * Funcs for pseudonode LSPs */ /* * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs */ static void lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, int level) { struct isis_adjacency *adj; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct es_neigh *es_neigh; struct list *adj_list; struct listnode *node; struct isis_area *area = circuit->area; lsp_debug("ISIS (%s): Constructing pseudo LSP %s for interface %s level %d", area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id), circuit->interface->name, level); lsp->level = level; /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0, circuit->area->attached_bit); /* * add self to IS neighbours */ if (circuit->area->oldmetric) { if (lsp->tlv_data.is_neighs == NULL) { lsp->tlv_data.is_neighs = list_new (); lsp->tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.is_neighs, is_neigh); lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (self)", area->area_tag, sysid_print(is_neigh->neigh_id), LSP_PSEUDO_ID(is_neigh->neigh_id)); } if (circuit->area->newmetric) { if (lsp->tlv_data.te_is_neighs == NULL) { lsp->tlv_data.te_is_neighs = list_new (); lsp->tlv_data.te_is_neighs->del = free_tlv; } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh); lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (self)", area->area_tag, sysid_print(te_is_neigh->neigh_id), LSP_PSEUDO_ID(te_is_neigh->neigh_id)); } adj_list = list_new (); isis_adj_build_up_list (circuit->u.bc.adjdb[level - 1], adj_list); for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj)) { if (adj->level & level) { if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) || (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS && adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) { /* an IS neighbour -> add it */ if (circuit->area->oldmetric) { is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.is_neighs, is_neigh); lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (peer)", area->area_tag, sysid_print(is_neigh->neigh_id), LSP_PSEUDO_ID(is_neigh->neigh_id)); } if (circuit->area->newmetric) { te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh); lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (peer)", area->area_tag, sysid_print(te_is_neigh->neigh_id), LSP_PSEUDO_ID(te_is_neigh->neigh_id)); } } else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES) { /* an ES neigbour add it, if we are building level 1 LSP */ /* FIXME: the tlv-format is hard to use here */ if (lsp->tlv_data.es_neighs == NULL) { lsp->tlv_data.es_neighs = list_new (); lsp->tlv_data.es_neighs->del = free_tlv; } es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh)); memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.es_neighs, es_neigh); lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)", area->area_tag, sysid_print(es_neigh->first_es_neigh)); } else { lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match", area->area_tag, sysid_print(adj->sysid)); } } else { lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect", area->area_tag, sysid_print(adj->sysid)); } } list_delete (adj_list); lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area->area_tag); /* Reset endp of stream to overwrite only TLV part of it. */ stream_reset (lsp->pdu); stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Add the authentication info if it's present */ lsp_auth_add (lsp); if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0) tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu); if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0) tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu); if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0) tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu); lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); /* Recompute authentication and checksum information */ lsp_auth_update (lsp); fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); return; } int lsp_generate_pseudo (struct isis_circuit *circuit, int level) { dict_t *lspdb = circuit->area->lspdb[level - 1]; struct isis_lsp *lsp; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; u_int16_t rem_lifetime, refresh_time; if ((circuit->is_type & level) != level || (circuit->state != C_STATE_UP) || (circuit->circ_type != CIRCUIT_T_BROADCAST) || (circuit->u.bc.is_dr[level - 1] == 0)) return ISIS_ERROR; memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_FRAGMENT (lsp_id) = 0; LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; /* * If for some reason have a pseudo LSP in the db already -> regenerate */ if (lsp_search (lsp_id, lspdb)) return lsp_regenerate_schedule_pseudo (circuit, level); rem_lifetime = lsp_rem_lifetime (circuit->area, level); /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ lsp = lsp_new (circuit->area, lsp_id, rem_lifetime, 1, circuit->area->is_type | circuit->area->attached_bit, 0, level); lsp->area = circuit->area; lsp_build_pseudo (lsp, circuit, level); lsp->own_lsp = 1; lsp_insert (lsp, lspdb); lsp_set_all_srmflags (lsp); refresh_time = lsp_refresh_time (lsp, rem_lifetime); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]); circuit->lsp_regenerate_pending[level - 1] = 0; if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], lsp_l1_refresh_pseudo, circuit, refresh_time); else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], lsp_l2_refresh_pseudo, circuit, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, " "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", circuit->area->area_tag, level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime), refresh_time); } return ISIS_OK; } static int lsp_regenerate_pseudo (struct isis_circuit *circuit, int level) { dict_t *lspdb = circuit->area->lspdb[level - 1]; struct isis_lsp *lsp; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; u_int16_t rem_lifetime, refresh_time; if ((circuit->is_type & level) != level || (circuit->state != C_STATE_UP) || (circuit->circ_type != CIRCUIT_T_BROADCAST) || (circuit->u.bc.is_dr[level - 1] == 0)) return ISIS_ERROR; memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, lspdb); if (!lsp) { zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!", level, rawlspid_print (lsp_id)); return ISIS_ERROR; } lsp_clear_data (lsp); lsp_build_pseudo (lsp, circuit, level); /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0, circuit->area->attached_bit); rem_lifetime = lsp_rem_lifetime (circuit->area, level); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_inc_seqnum (lsp, 0); lsp->last_generated = time (NULL); lsp_set_all_srmflags (lsp); refresh_time = lsp_refresh_time (lsp, rem_lifetime); if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], lsp_l1_refresh_pseudo, circuit, refresh_time); else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], lsp_l2_refresh_pseudo, circuit, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, " "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", circuit->area->area_tag, level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime), refresh_time); } return ISIS_OK; } /* * Something has changed or periodic refresh -> regenerate pseudo LSP */ static int lsp_l1_refresh_pseudo (struct thread *thread) { struct isis_circuit *circuit; u_char id[ISIS_SYS_ID_LEN + 2]; circuit = THREAD_ARG (thread); circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL; circuit->lsp_regenerate_pending[0] = 0; if ((circuit->u.bc.is_dr[0] == 0) || (circuit->is_type & IS_LEVEL_1) == 0) { memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = circuit->circuit_id; LSP_FRAGMENT (id) = 0; lsp_purge_pseudo (id, circuit, IS_LEVEL_1); return ISIS_ERROR; } return lsp_regenerate_pseudo (circuit, IS_LEVEL_1); } static int lsp_l2_refresh_pseudo (struct thread *thread) { struct isis_circuit *circuit; u_char id[ISIS_SYS_ID_LEN + 2]; circuit = THREAD_ARG (thread); circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL; circuit->lsp_regenerate_pending[1] = 0; if ((circuit->u.bc.is_dr[1] == 0) || (circuit->is_type & IS_LEVEL_2) == 0) { memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = circuit->circuit_id; LSP_FRAGMENT (id) = 0; lsp_purge_pseudo (id, circuit, IS_LEVEL_2); return ISIS_ERROR; } return lsp_regenerate_pseudo (circuit, IS_LEVEL_2); } int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level) { struct isis_lsp *lsp; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; time_t now, diff; long timeout; int lvl; struct isis_area *area = circuit->area; if (circuit == NULL || circuit->circ_type != CIRCUIT_T_BROADCAST || circuit->state != C_STATE_UP) return ISIS_OK; sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s", area->area_tag, circuit_t2string(level), circuit->interface->name); memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; LSP_FRAGMENT (lsp_id) = 0; now = time (NULL); for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled", area->area_tag, lvl); if (!((level & lvl) && (circuit->is_type & lvl))) { sched_debug("ISIS (%s): Level is not active on circuit", area->area_tag); continue; } if (circuit->u.bc.is_dr[lvl - 1] == 0) { sched_debug("ISIS (%s): This IS is not DR, nothing to do.", area->area_tag); continue; } if (circuit->lsp_regenerate_pending[lvl - 1]) { struct timeval remain = thread_timer_remain(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]); sched_debug("ISIS (%s): Regenerate is already pending, nothing todo." " (Due in %lld.%03lld seconds)", area->area_tag, (long long)remain.tv_sec, (long long)remain.tv_usec/1000); continue; } lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]); if (!lsp) { sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.", area->area_tag); continue; } /* * Throttle avoidance */ sched_debug("ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld", area->area_tag, (long long)lsp->last_generated, (long long) now); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]); diff = now - lsp->last_generated; if (diff < circuit->area->lsp_gen_interval[lvl - 1]) { timeout = 1000 * (circuit->area->lsp_gen_interval[lvl - 1] - diff); sched_debug("ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval", area->area_tag, timeout); } else { timeout = 100; sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago." " Scheduling for execution in %ld ms.", area->area_tag, timeout); } circuit->lsp_regenerate_pending[lvl - 1] = 1; if (lvl == IS_LEVEL_1) { THREAD_TIMER_MSEC_ON(master, circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], lsp_l1_refresh_pseudo, circuit, timeout); } else if (lvl == IS_LEVEL_2) { THREAD_TIMER_MSEC_ON(master, circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], lsp_l2_refresh_pseudo, circuit, timeout); } } return ISIS_OK; } /* * Walk through LSPs for an area * - set remaining lifetime * - set LSPs with SRMflag set for sending */ int lsp_tick (struct thread *thread) { struct isis_area *area; struct isis_circuit *circuit; struct isis_lsp *lsp; struct list *lsp_list; struct listnode *lspnode, *cnode; dnode_t *dnode, *dnode_next; int level; u_int16_t rem_lifetime; lsp_list = list_new (); area = THREAD_ARG (thread); assert (area); area->t_tick = NULL; THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1); /* * Build a list of LSPs with (any) SRMflag set * and removed the ones that have aged out */ for (level = 0; level < ISIS_LEVELS; level++) { if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) { for (dnode = dict_first (area->lspdb[level]); dnode != NULL; dnode = dnode_next) { dnode_next = dict_next (area->lspdb[level], dnode); lsp = dnode_get (dnode); /* * The lsp rem_lifetime is kept at 0 for MaxAge or * ZeroAgeLifetime depending on explicit purge or * natural age out. So schedule spf only once when * the first time rem_lifetime becomes 0. */ rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime); lsp_set_time (lsp); /* * Schedule may run spf which should be done only after * the lsp rem_lifetime becomes 0 for the first time. * ISO 10589 - 7.3.16.4 first paragraph. */ if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0) { /* 7.3.16.4 a) set SRM flags on all */ lsp_set_all_srmflags (lsp); /* 7.3.16.4 b) retain only the header FIXME */ /* 7.3.16.4 c) record the time to purge FIXME */ /* run/schedule spf */ /* isis_spf_schedule is called inside lsp_destroy() below; * so it is not needed here. */ /* isis_spf_schedule (lsp->area, lsp->level); */ } if (lsp->age_out == 0) { zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out", area->area_tag, lsp->level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num)); #ifdef TOPOLOGY_GENERATE if (lsp->from_topology) THREAD_TIMER_OFF (lsp->t_lsp_top_ref); #endif /* TOPOLOGY_GENERATE */ lsp_destroy (lsp); lsp = NULL; dict_delete_free (area->lspdb[level], dnode); } else if (flags_any_set (lsp->SRMflags)) listnode_add (lsp_list, lsp); } /* * Send LSPs on circuits indicated by the SRMflags */ if (listcount (lsp_list) > 0) { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) { int diff = time (NULL) - circuit->lsp_queue_last_cleared; if (circuit->lsp_queue == NULL || diff < MIN_LSP_TRANS_INTERVAL) continue; for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp)) { if (circuit->upadjcount[lsp->level - 1] && ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) { /* Add the lsp only if it is not already in lsp * queue */ if (! listnode_lookup (circuit->lsp_queue, lsp)) { listnode_add (circuit->lsp_queue, lsp); thread_add_event (master, send_lsp, circuit, 0); } } } } list_delete_all_node (lsp_list); } } } list_delete (lsp_list); return ISIS_OK; } void lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level) { struct isis_lsp *lsp; u_int16_t seq_num; u_int8_t lsp_bits; lsp = lsp_search (id, circuit->area->lspdb[level - 1]); if (!lsp) return; /* store old values */ seq_num = lsp->lsp_header->seq_num; lsp_bits = lsp->lsp_header->lsp_bits; /* reset stream */ lsp_clear_data (lsp); stream_reset (lsp->pdu); /* update header */ lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2); lsp->lsp_header->checksum = 0; lsp->lsp_header->seq_num = seq_num; lsp->lsp_header->rem_lifetime = 0; lsp->lsp_header->lsp_bits = lsp_bits; lsp->level = level; lsp->age_out = lsp->area->max_lsp_lifetime[level-1]; stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Add and update the authentication info if its present */ lsp_auth_add (lsp); lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); lsp_auth_update (lsp); fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); lsp_set_all_srmflags (lsp); return; } /* * Purge own LSP that is received and we don't have. * -> Do as in 7.3.16.4 */ void lsp_purge_non_exist (int level, struct isis_link_state_hdr *lsp_hdr, struct isis_area *area) { struct isis_lsp *lsp; /* * We need to create the LSP to be purged */ lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); lsp->area = area; lsp->level = level; lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu); fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN); stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Set the remaining lifetime to 0 */ lsp->lsp_header->rem_lifetime = 0; /* * Add and update the authentication info if its present */ lsp_auth_add (lsp); lsp_auth_update (lsp); /* * Update the PDU length to header plus any authentication TLV. */ lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); /* * Put the lsp into LSPdb */ lsp_insert (lsp, area->lspdb[lsp->level - 1]); /* * Send in to whole area */ lsp_set_all_srmflags (lsp); return; } void lsp_set_all_srmflags (struct isis_lsp *lsp) { struct listnode *node; struct isis_circuit *circuit; assert (lsp); ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags); if (lsp->area) { struct list *circuit_list = lsp->area->circuit_list; for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit)) { ISIS_SET_FLAG(lsp->SRMflags, circuit); } } } #ifdef TOPOLOGY_GENERATE static int top_lsp_refresh (struct thread *thread) { struct isis_lsp *lsp; u_int16_t rem_lifetime; lsp = THREAD_ARG (thread); assert (lsp); lsp->t_lsp_top_ref = NULL; lsp_seqnum_update (lsp); lsp_set_all_srmflags (lsp); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s", rawlspid_print (lsp->lsp_header->lsp_id)); } /* Refresh dynamic hostname in the cache. */ isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, IS_LEVEL_1); lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level, lsp->area->overload_bit, lsp->area->attached_bit); rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); /* refresh_time = lsp_refresh_time (lsp, rem_lifetime); */ THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp, lsp->area->lsp_refresh[0]); return ISIS_OK; } void generate_topology_lsps (struct isis_area *area) { struct listnode *node; int i, max = 0; struct arc *arc; u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; u_int16_t rem_lifetime, refresh_time; /* first we find the maximal node */ for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc)) { if (arc->from_node > max) max = arc->from_node; if (arc->to_node > max) max = arc->to_node; } for (i = 1; i < (max + 1); i++) { memcpy (lspid, area->topology_baseis, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lspid) = 0x00; LSP_FRAGMENT (lspid) = 0x00; lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF); lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF); rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1); lsp = lsp_new (area, lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit | area->attached_bit, 0, 1); if (!lsp) return; lsp->from_topology = 1; /* Creating LSP data based on topology info. */ build_topology_lsp_data (lsp, area, i); /* Checksum is also calculated here. */ lsp_seqnum_update (lsp); /* Take care of inserting dynamic hostname into cache. */ isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1); refresh_time = lsp_refresh_time (lsp, rem_lifetime); THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp, refresh_time); lsp_set_all_srmflags (lsp); lsp_insert (lsp, area->lspdb[0]); } } void remove_topology_lsps (struct isis_area *area) { struct isis_lsp *lsp; dnode_t *dnode, *dnode_next; dnode = dict_first (area->lspdb[0]); while (dnode != NULL) { dnode_next = dict_next (area->lspdb[0], dnode); lsp = dnode_get (dnode); if (lsp->from_topology) { THREAD_TIMER_OFF (lsp->t_lsp_top_ref); lsp_destroy (lsp); dict_delete (area->lspdb[0], dnode); } dnode = dnode_next; } } void build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area, int lsp_top_num) { struct listnode *node; struct arc *arc; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; char buff[200]; struct tlvs tlv_data; struct isis_lsp *lsp0 = lsp; /* Add area addresses. FIXME: Is it needed at all? */ if (lsp->tlv_data.area_addrs == NULL) lsp->tlv_data.area_addrs = list_new (); list_add_list (lsp->tlv_data.area_addrs, area->area_addrs); if (lsp->tlv_data.nlpids == NULL) lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids)); lsp->tlv_data.nlpids->count = 1; lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP; if (area->dynhostname) { lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct hostname)); memset (buff, 0x00, 200); sprintf (buff, "%s%d", area->topology_basedynh ? area->topology_basedynh : "feedme", lsp_top_num); memcpy (lsp->tlv_data.hostname->name, buff, strlen (buff)); lsp->tlv_data.hostname->namelen = strlen (buff); } if (lsp->tlv_data.nlpids) tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu); if (lsp->tlv_data.hostname) tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0) tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu); memset (&tlv_data, 0, sizeof (struct tlvs)); if (tlv_data.is_neighs == NULL) { tlv_data.is_neighs = list_new (); tlv_data.is_neighs->del = free_tlv; } /* Add reachability for this IS for simulated 1. */ if (lsp_top_num == 1) { is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00; /* Metric MUST NOT be 0, unless it's not alias TLV. */ is_neigh->metrics.metric_default = 0x01; is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); } /* Add IS reachabilities. */ for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc)) { int to_lsp = 0; if ((lsp_top_num != arc->from_node) && (lsp_top_num != arc->to_node)) continue; if (lsp_top_num == arc->from_node) to_lsp = arc->to_node; else to_lsp = arc->from_node; if (area->oldmetric) { is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN); is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF); is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF); is_neigh->metrics.metric_default = arc->distance; is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); } if (area->newmetric) { if (tlv_data.te_is_neighs == NULL) { tlv_data.te_is_neighs = list_new (); tlv_data.te_is_neighs->del = free_tlv; } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (&te_is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN); te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF); te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF); SET_TE_METRIC(te_is_neigh, arc->distance); listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } while (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) { if (lsp->tlv_data.is_neighs == NULL) lsp->tlv_data.is_neighs = list_new (); lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs, IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, tlv_add_is_neighs); if (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, IS_LEVEL_1); } while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) { if (lsp->tlv_data.te_is_neighs == NULL) lsp->tlv_data.te_is_neighs = list_new (); lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs, IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, tlv_add_te_is_neighs); if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, IS_LEVEL_1); } free_tlvs (&tlv_data); return; } #endif /* TOPOLOGY_GENERATE */ quagga-1.2.4/isisd/isis_lsp.h000066400000000000000000000115431325323223500161000ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_lsp.h * LSP processing * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_LSP_H #define _ZEBRA_ISIS_LSP_H /* Structure for isis_lsp, this structure will only support the fixed * System ID (Currently 6) (atleast for now). In order to support more * We will have to split the header into two parts, and for readability * sake it should better be avoided */ struct isis_lsp { struct isis_fixed_hdr *isis_header; /* normally equals pdu */ struct isis_link_state_hdr *lsp_header; /* pdu + isis_header_len */ struct stream *pdu; /* full pdu lsp */ union { struct list *frags; struct isis_lsp *zero_lsp; } lspu; u_int32_t auth_tlv_offset; /* authentication TLV position in the pdu */ u_int32_t SRMflags[ISIS_MAX_CIRCUITS]; u_int32_t SSNflags[ISIS_MAX_CIRCUITS]; int level; /* L1 or L2? */ int scheduled; /* scheduled for sending */ time_t installed; time_t last_generated; int own_lsp; #ifdef TOPOLOGY_GENERATE int from_topology; struct thread *t_lsp_top_ref; #endif /* used for 60 second counting when rem_lifetime is zero */ int age_out; struct isis_area *area; struct tlvs tlv_data; /* Simplifies TLV access */ }; dict_t *lsp_db_init (void); void lsp_db_destroy (dict_t * lspdb); int lsp_tick (struct thread *thread); int lsp_generate (struct isis_area *area, int level); int lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo); int lsp_generate_pseudo (struct isis_circuit *circuit, int level); int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level); struct isis_lsp *lsp_new (struct isis_area *area, u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, u_int8_t lsp_bits, u_int16_t checksum, int level); struct isis_lsp *lsp_new_from_stream_ptr (struct stream *stream, u_int16_t pdu_len, struct isis_lsp *lsp0, struct isis_area *area, int level); void lsp_insert (struct isis_lsp *lsp, dict_t * lspdb); struct isis_lsp *lsp_search (u_char * id, dict_t * lspdb); void lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps, struct list *list, dict_t * lspdb); void lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id, struct list *list, dict_t * lspdb); void lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps, struct list *list, dict_t * lspdb); void lsp_search_and_destroy (u_char * id, dict_t * lspdb); void lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level); void lsp_purge_non_exist (int level, struct isis_link_state_hdr *lsp_hdr, struct isis_area *area); #define LSP_EQUAL 1 #define LSP_NEWER 2 #define LSP_OLDER 3 #define LSP_PSEUDO_ID(I) ((I)[ISIS_SYS_ID_LEN]) #define LSP_FRAGMENT(I) ((I)[ISIS_SYS_ID_LEN + 1]) #define OWNLSPID(I) \ memcpy ((I), isis->sysid, ISIS_SYS_ID_LEN);\ (I)[ISIS_SYS_ID_LEN] = 0;\ (I)[ISIS_SYS_ID_LEN + 1] = 0 int lsp_id_cmp (u_char * id1, u_char * id2); int lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, u_int16_t checksum, u_int16_t rem_lifetime); void lsp_update (struct isis_lsp *lsp, struct stream *stream, struct isis_area *area, int level); void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num); void lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost); void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost); int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost); const char *lsp_bits2string (u_char *); /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags (struct isis_lsp *lsp); #ifdef TOPOLOGY_GENERATE void generate_topology_lsps (struct isis_area *area); void remove_topology_lsps (struct isis_area *area); void build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area, int lsp_top_num); #endif /* TOPOLOGY_GENERATE */ #endif /* ISIS_LSP */ quagga-1.2.4/isisd/isis_main.c000066400000000000000000000203071325323223500162170ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_main.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "getopt.h" #include "thread.h" #include "log.h" #include #include "command.h" #include "vty.h" #include "memory.h" #include "stream.h" #include "if.h" #include "privs.h" #include "sigevent.h" #include "filter.h" #include "plist.h" #include "zclient.h" #include "vrf.h" #include "isisd/dict.h" #include "include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_spf.h" #include "isisd/isis_route.h" #include "isisd/isis_routemap.h" #include "isisd/isis_zebra.h" #include "isisd/isis_tlv.h" #include "isisd/isis_te.h" /* Default configuration file name */ #define ISISD_DEFAULT_CONFIG "isisd.conf" /* Default vty port */ #define ISISD_VTY_PORT 2608 /* isisd privileges */ zebra_capabilities_t _caps_p[] = { ZCAP_NET_RAW, ZCAP_BIND }; struct zebra_privs_t isisd_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = sizeof (_caps_p) / sizeof (*_caps_p), .cap_num_i = 0 }; /* isisd options */ struct option longopts[] = { {"daemon", no_argument, NULL, 'd'}, {"config_file", required_argument, NULL, 'f'}, {"pid_file", required_argument, NULL, 'i'}, {"socket", required_argument, NULL, 'z'}, {"vty_addr", required_argument, NULL, 'A'}, {"vty_port", required_argument, NULL, 'P'}, {"user", required_argument, NULL, 'u'}, {"group", required_argument, NULL, 'g'}, {"version", no_argument, NULL, 'v'}, {"dryrun", no_argument, NULL, 'C'}, {"help", no_argument, NULL, 'h'}, {0} }; /* Configuration file and directory. */ char config_default[] = SYSCONFDIR ISISD_DEFAULT_CONFIG; char *config_file = NULL; /* isisd program name. */ char *progname; int daemon_mode = 0; /* Master of threads. */ struct thread_master *master; /* Process ID saved for use by init system */ const char *pid_file = PATH_ISISD_PID; /* for reload */ char _cwd[MAXPATHLEN]; char _progpath[MAXPATHLEN]; int _argc; char **_argv; char **_envp; /* * Prototypes. */ void reload(void); void sighup(void); void sigint(void); void sigterm(void); void sigusr1(void); /* 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 IS-IS routing\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\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } void reload () { zlog_debug ("Reload"); /* FIXME: Clean up func call here */ vty_reset (); (void) isisd_privs.change (ZPRIVS_RAISE); execve (_progpath, _argv, _envp); zlog_err ("Reload failed: cannot exec %s: %s", _progpath, safe_strerror (errno)); } static void terminate (int i) { exit (i); } /* * Signal handlers */ void sighup (void) { zlog_debug ("SIGHUP received"); reload (); return; } void sigint (void) { zlog_notice ("Terminating on signal SIGINT"); terminate (0); } void sigterm (void) { zlog_notice ("Terminating on signal SIGTERM"); terminate (0); } void sigusr1 (void) { zlog_debug ("SIGUSR1 received"); zlog_rotate (NULL); } struct quagga_signal_t isisd_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigterm, }, }; /* * Main routine of isisd. Parse arguments and handle IS-IS state machine. */ int main (int argc, char **argv, char **envp) { char *p; int opt, vty_port = ISISD_VTY_PORT; char *config_file = NULL; char *vty_addr = NULL; int dryrun = 0; /* Get the programname without the preceding path. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog (progname, ZLOG_ISIS, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); /* for reload */ _argc = argc; _argv = argv; _envp = envp; getcwd (_cwd, sizeof (_cwd)); if (*argv[0] == '.') snprintf (_progpath, sizeof (_progpath), "%s/%s", _cwd, _argv[0]); else snprintf (_progpath, sizeof (_progpath), "%s", argv[0]); /* Command line argument treatment. */ while (1) { opt = getopt_long (argc, argv, "df:i:z:hA:p:P:u:g:vC", 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 'z': zclient_serv_path_set (optarg); break; case 'A': vty_addr = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure, and isisd not listening on isisd port... */ if (strcmp (optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); vty_port = (vty_port ? vty_port : ISISD_VTY_PORT); break; case 'u': isisd_privs.user = optarg; break; case 'g': isisd_privs.group = optarg; break; case 'v': printf ("ISISd version %s\n", ISISD_VERSION); printf ("Copyright (c) 2001-2002 Sampo Saaristo," " Ofer Wald and Hannes Gredler\n"); print_version ("Zebra"); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (0); break; default: usage (1); break; } } /* thread master */ master = thread_master_create (); /* random seed from time */ srandom (time (NULL)); /* * initializations */ zprivs_init (&isisd_privs); signal_init (master, array_size (isisd_signals), isisd_signals); cmd_init (1); vty_init (master); memory_init (); access_list_init(); vrf_init (); prefix_list_init(); isis_init (); isis_circuit_init (); isis_spf_cmds_init (); isis_redist_init (); isis_route_map_init(); isis_mpls_te_init(); /* create the global 'isis' instance */ isis_new (1); isis_zebra_init (master); /* parse config file */ /* this is needed three times! because we have interfaces before the areas */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if (dryrun) return(0); /* demonize */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("IS-IS daemon failed: %s", strerror(errno)); exit (1); } /* Process ID file creation. */ if (pid_file[0] != '\0') pid_output (pid_file); /* Make isis vty socket. */ vty_serv_sock (vty_addr, vty_port, ISIS_VTYSH_PATH); /* Print banner. */ zlog_notice ("Quagga-ISISd %s starting: vty@%d", QUAGGA_VERSION, vty_port); /* Start finite state machine. */ thread_main (master); /* Not reached. */ exit (0); } quagga-1.2.4/isisd/isis_misc.c000066400000000000000000000304141325323223500162260ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_misc.h * Miscellanous routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "stream.h" #include "vty.h" #include "hash.h" #include "if.h" #include "command.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" #include "isisd/isisd.h" #include "isisd/isis_misc.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dynhn.h" /* staticly assigned vars for printing purposes */ struct in_addr new_prefix; /* len of xxxx.xxxx.xxxx + place for #0 termination */ char sysid[15]; /* len of xxxx.xxxx.xxxx + place for #0 termination */ char snpa[15]; /* len of xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx */ char isonet[51]; /* + place for #0 termination */ /* len of xxxx.xxxx.xxxx.xx.xx + place for #0 termination */ char lspid[21]; /* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */ char datestring[20]; char nlpidstring[30]; /* * This converts the isonet to its printable format */ const char * isonet_print (const u_char * from, int len) { int i = 0; char *pos = isonet; if (!from) return "unknown"; while (i < len) { if (i & 1) { sprintf (pos, "%02x", *(from + i)); pos += 2; } else { if (i == (len - 1)) { /* No dot at the end of address */ sprintf (pos, "%02x", *(from + i)); pos += 2; } else { sprintf (pos, "%02x.", *(from + i)); pos += 3; } } i++; } *(pos) = '\0'; return isonet; } /* * Returns 0 on error, length of buff on ok * extract dot from the dotted str, and insert all the number in a buff */ int dotformat2buff (u_char * buff, const char * dotted) { int dotlen, len = 0; const char *pos = dotted; u_char number[3]; int nextdotpos = 2; number[2] = '\0'; dotlen = strlen(dotted); if (dotlen > 50) { /* this can't be an iso net, its too long */ return 0; } while ((pos - dotted) < dotlen && len < 20) { if (*pos == '.') { /* we expect the . at 2, and than every 5 */ if ((pos - dotted) != nextdotpos) { len = 0; break; } nextdotpos += 5; pos++; continue; } /* we must have at least two chars left here */ if (dotlen - (pos - dotted) < 2) { len = 0; break; } if ((isxdigit ((int) *pos)) && (isxdigit ((int) *(pos + 1)))) { memcpy (number, pos, 2); pos += 2; } else { len = 0; break; } *(buff + len) = (char) strtol ((char *)number, NULL, 16); len++; } return len; } /* * conversion of XXXX.XXXX.XXXX to memory */ int sysid2buff (u_char * buff, const char * dotted) { int len = 0; const char *pos = dotted; u_char number[3]; number[2] = '\0'; // surely not a sysid_string if not 14 length if (strlen (dotted) != 14) { return 0; } while (len < ISIS_SYS_ID_LEN) { if (*pos == '.') { /* the . is not positioned correctly */ if (((pos - dotted) != 4) && ((pos - dotted) != 9)) { len = 0; break; } pos++; continue; } if ((isxdigit ((int) *pos)) && (isxdigit ((int) *(pos + 1)))) { memcpy (number, pos, 2); pos += 2; } else { len = 0; break; } *(buff + len) = (char) strtol ((char *)number, NULL, 16); len++; } return len; } /* * converts the nlpids struct (filled by TLV #129) * into a string */ char * nlpid2string (struct nlpids *nlpids) { char *pos = nlpidstring; int i; for (i = 0; i < nlpids->count; i++) { switch (nlpids->nlpids[i]) { case NLPID_IP: pos += sprintf (pos, "IPv4"); break; case NLPID_IPV6: pos += sprintf (pos, "IPv6"); break; case NLPID_SNAP: pos += sprintf (pos, "SNAP"); break; case NLPID_CLNP: pos += sprintf (pos, "CLNP"); break; case NLPID_ESIS: pos += sprintf (pos, "ES-IS"); break; default: pos += sprintf (pos, "unknown"); break; } if (nlpids->count - i > 1) pos += sprintf (pos, ", "); } *(pos) = '\0'; return nlpidstring; } /* * supports the given af ? */ int speaks (struct nlpids *nlpids, int family) { int i, speaks = 0; if (nlpids == (struct nlpids *) NULL) return speaks; for (i = 0; i < nlpids->count; i++) { if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP) speaks = 1; if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6) speaks = 1; } return speaks; } /* * Returns 0 on error, IS-IS Circuit Type on ok */ int string2circuit_t (const char * str) { if (!str) return 0; if (!strcmp (str, "level-1")) return IS_LEVEL_1; if (!strcmp (str, "level-2-only") || !strcmp (str, "level-2")) return IS_LEVEL_2; if (!strcmp (str, "level-1-2")) return IS_LEVEL_1_AND_2; return 0; } const char * circuit_state2string (int state) { switch (state) { case C_STATE_INIT: return "Init"; case C_STATE_CONF: return "Config"; case C_STATE_UP: return "Up"; default: return "Unknown"; } return NULL; } const char * circuit_type2string (int type) { switch (type) { case CIRCUIT_T_P2P: return "p2p"; case CIRCUIT_T_BROADCAST: return "lan"; case CIRCUIT_T_LOOPBACK: return "loopback"; default: return "Unknown"; } return NULL; } const char * circuit_t2string (int circuit_t) { switch (circuit_t) { case IS_LEVEL_1: return "L1"; case IS_LEVEL_2: return "L2"; case IS_LEVEL_1_AND_2: return "L1L2"; default: return "??"; } return NULL; /* not reached */ } const char * syst2string (int type) { switch (type) { case ISIS_SYSTYPE_ES: return "ES"; case ISIS_SYSTYPE_IS: return "IS"; case ISIS_SYSTYPE_L1_IS: return "1"; case ISIS_SYSTYPE_L2_IS: return "2"; default: return "??"; } return NULL; /* not reached */ } /* * Print functions - we print to static vars */ const char * snpa_print (const u_char * from) { int i = 0; u_char *pos = (u_char *)snpa; if (!from) return "unknown"; while (i < ETH_ALEN - 1) { if (i & 1) { sprintf ((char *)pos, "%02x.", *(from + i)); pos += 3; } else { sprintf ((char *)pos, "%02x", *(from + i)); pos += 2; } i++; } sprintf ((char *)pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); pos += 2; *(pos) = '\0'; return snpa; } const char * sysid_print (const u_char * from) { int i = 0; char *pos = sysid; if (!from) return "unknown"; while (i < ISIS_SYS_ID_LEN - 1) { if (i & 1) { sprintf (pos, "%02x.", *(from + i)); pos += 3; } else { sprintf (pos, "%02x", *(from + i)); pos += 2; } i++; } sprintf (pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); pos += 2; *(pos) = '\0'; return sysid; } const char * rawlspid_print (const u_char * from) { char *pos = lspid; if (!from) return "unknown"; memcpy (pos, sysid_print (from), 15); pos += 14; sprintf (pos, ".%02x", LSP_PSEUDO_ID (from)); pos += 3; sprintf (pos, "-%02x", LSP_FRAGMENT (from)); pos += 3; *(pos) = '\0'; return lspid; } const char * time2string (u_int32_t time) { char *pos = datestring; u_int32_t rest; if (time == 0) return "-"; if (time / SECS_PER_YEAR) pos += sprintf (pos, "%uY", time / SECS_PER_YEAR); rest = time % SECS_PER_YEAR; if (rest / SECS_PER_MONTH) pos += sprintf (pos, "%uM", rest / SECS_PER_MONTH); rest = rest % SECS_PER_MONTH; if (rest / SECS_PER_WEEK) pos += sprintf (pos, "%uw", rest / SECS_PER_WEEK); rest = rest % SECS_PER_WEEK; if (rest / SECS_PER_DAY) pos += sprintf (pos, "%ud", rest / SECS_PER_DAY); rest = rest % SECS_PER_DAY; if (rest / SECS_PER_HOUR) pos += sprintf (pos, "%uh", rest / SECS_PER_HOUR); rest = rest % SECS_PER_HOUR; if (rest / SECS_PER_MINUTE) pos += sprintf (pos, "%um", rest / SECS_PER_MINUTE); rest = rest % SECS_PER_MINUTE; if (rest) pos += sprintf (pos, "%us", rest); *(pos) = 0; return datestring; } /* * routine to decrement a timer by a random * number * * first argument is the timer and the second is * the jitter */ unsigned long isis_jitter (unsigned long timer, unsigned long jitter) { int j, k; if (jitter >= 100) return timer; if (timer == 1) return timer; /* * randomizing just the percent value provides * no good random numbers - hence the spread * to RANDOM_SPREAD (100000), which is ok as * most IS-IS timers are no longer than 16 bit */ j = 1 + (int) ((RANDOM_SPREAD * random ()) / (RAND_MAX + 1.0)); k = timer - (timer * (100 - jitter)) / 100; timer = timer - (k * j / RANDOM_SPREAD); return timer; } struct in_addr newprefix2inaddr (u_char * prefix_start, u_char prefix_masklen) { memset (&new_prefix, 0, sizeof (new_prefix)); memcpy (&new_prefix, prefix_start, (prefix_masklen & 0x3F) ? ((((prefix_masklen & 0x3F) - 1) >> 3) + 1) : 0); return new_prefix; } /* * Returns host.name if any, otherwise * it returns the system hostname. */ const char * unix_hostname (void) { static struct utsname names; const char *hostname; hostname = host.name; if (!hostname) { uname (&names); hostname = names.nodename; } return hostname; } /* * Returns the dynamic hostname associated with the passed system ID. * If no dynamic hostname found then returns formatted system ID. */ const char * print_sys_hostname (const u_char *sysid) { struct isis_dynhn *dyn; if (!sysid) return "nullsysid"; /* For our system ID return our host name */ if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0) return unix_hostname(); dyn = dynhn_find_by_id (sysid); if (dyn) return (const char *)dyn->name.name; return sysid_print (sysid); } /* * This function is a generic utility that logs data of given length. * Move this to a shared lib so that any protocol can use it. */ void zlog_dump_data (void *data, int len) { int i; unsigned char *p; unsigned char c; char bytestr[4]; char addrstr[10]; char hexstr[ 16*3 + 5]; char charstr[16*1 + 5]; p = data; memset (bytestr, 0, sizeof(bytestr)); memset (addrstr, 0, sizeof(addrstr)); memset (hexstr, 0, sizeof(hexstr)); memset (charstr, 0, sizeof(charstr)); for (i = 1; i <= len; i++) { c = *p; if (isalnum (c) == 0) c = '.'; /* store address for this line */ if ((i % 16) == 1) snprintf (addrstr, sizeof(addrstr), "%p", p); /* store hex str (for left side) */ snprintf (bytestr, sizeof (bytestr), "%02X ", *p); strncat (hexstr, bytestr, sizeof (hexstr) - strlen (hexstr) - 1); /* store char str (for right side) */ snprintf (bytestr, sizeof (bytestr), "%c", c); strncat (charstr, bytestr, sizeof (charstr) - strlen (charstr) - 1); if ((i % 16) == 0) { /* line completed */ zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr); hexstr[0] = 0; charstr[0] = 0; } else if ((i % 8) == 0) { /* half line: add whitespaces */ strncat (hexstr, " ", sizeof (hexstr) - strlen (hexstr) - 1); strncat (charstr, " ", sizeof (charstr) - strlen (charstr) - 1); } p++; /* next byte */ } /* print rest of buffer if not empty */ if (strlen (hexstr) > 0) zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr); return; } quagga-1.2.4/isisd/isis_misc.h000066400000000000000000000050751325323223500162400ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_misc.h * Miscellanous routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_MISC_H #define _ZEBRA_ISIS_MISC_H int string2circuit_t (const char *); const char *circuit_t2string (int); const char *circuit_state2string (int state); const char *circuit_type2string (int type); const char *syst2string (int); struct in_addr newprefix2inaddr (u_char * prefix_start, u_char prefix_masklen); /* * Converting input to memory stored format * return value of 0 indicates wrong input */ int dotformat2buff (u_char *, const char *); int sysid2buff (u_char *, const char *); /* * Printing functions */ const char *isonet_print (const u_char *, int len); const char *sysid_print (const u_char *); const char *snpa_print (const u_char *); const char *rawlspid_print (const u_char *); const char *time2string (u_int32_t); /* typedef struct nlpids nlpids; */ char *nlpid2string (struct nlpids *); const char *print_sys_hostname (const u_char *sysid); void zlog_dump_data (void *data, int len); /* * misc functions */ int speaks (struct nlpids *nlpids, int family); unsigned long isis_jitter (unsigned long timer, unsigned long jitter); const char *unix_hostname (void); /* * macros */ #define GETSYSID(A) (A->area_addr + (A->addr_len - \ (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN))) /* used for calculating nice string representation instead of plain seconds */ #define SECS_PER_MINUTE 60 #define SECS_PER_HOUR 3600 #define SECS_PER_DAY 86400 #define SECS_PER_WEEK 604800 #define SECS_PER_MONTH 2628000 #define SECS_PER_YEAR 31536000 enum { ISIS_UI_LEVEL_BRIEF, ISIS_UI_LEVEL_DETAIL, ISIS_UI_LEVEL_EXTENSIVE, }; #endif quagga-1.2.4/isisd/isis_network.h000066400000000000000000000026561325323223500170000ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_network.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_NETWORK_H #define _ZEBRA_ISIS_NETWORK_H extern u_char ALL_L1_ISYSTEMS[]; extern u_char ALL_L2_ISYSTEMS[]; int isis_sock_init (struct isis_circuit *circuit); int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa); int isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa); int isis_send_pdu_bcast (struct isis_circuit *circuit, int level); int isis_send_pdu_p2p (struct isis_circuit *circuit, int level); #endif /* _ZEBRA_ISIS_NETWORK_H */ quagga-1.2.4/isisd/isis_pdu.c000066400000000000000000002654501325323223500160750ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_pdu.c * PDU processing * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "memory.h" #include "thread.h" #include "linklist.h" #include "log.h" #include "stream.h" #include "vty.h" #include "hash.h" #include "prefix.h" #include "if.h" #include "checksum.h" #include "md5.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_dr.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/iso_checksum.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" #include "isisd/isis_te.h" #define ISIS_MINIMUM_FIXED_HDR_LEN 15 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */ #ifndef PNBBY #define PNBBY 8 #endif /* PNBBY */ /* Utility mask array. */ static const u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; /* * HELPER FUNCS */ /* * Compares two sets of area addresses */ static int area_match (struct list *left, struct list *right) { struct area_addr *addr1, *addr2; struct listnode *node1, *node2; for (ALL_LIST_ELEMENTS_RO (left, node1, addr1)) { for (ALL_LIST_ELEMENTS_RO (right, node2, addr2)) { if (addr1->addr_len == addr2->addr_len && !memcmp (addr1->area_addr, addr2->area_addr, (int) addr1->addr_len)) return 1; /* match */ } } return 0; /* mismatch */ } /* * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() ) * param ip1 the IS interface ip address structure * param ip2 the IIH's ip address * return 0 the IIH's IP is not in the IS's subnetwork * 1 the IIH's IP is in the IS's subnetwork */ static int ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2) { u_char *addr1, *addr2; int shift, offset, offsetloop; int len; addr1 = (u_char *) & ip1->prefix.s_addr; addr2 = (u_char *) & ip2->s_addr; len = ip1->prefixlen; shift = len % PNBBY; offsetloop = offset = len / PNBBY; while (offsetloop--) if (addr1[offsetloop] != addr2[offsetloop]) return 0; if (shift) if (maskbit[shift] & (addr1[offset] ^ addr2[offset])) return 0; return 1; /* match */ } /* * Compares two set of ip addresses * param left the local interface's ip addresses * param right the iih interface's ip address * return 0 no match; * 1 match; */ static int ip_match (struct list *left, struct list *right) { struct prefix_ipv4 *ip1; struct in_addr *ip2; struct listnode *node1, *node2; if ((left == NULL) || (right == NULL)) return 0; for (ALL_LIST_ELEMENTS_RO (left, node1, ip1)) { for (ALL_LIST_ELEMENTS_RO (right, node2, ip2)) { if (ip_same_subnet (ip1, ip2)) { return 1; /* match */ } } } return 0; } /* * Checks whether we should accept a PDU of given level */ static int accept_level (int level, int circuit_t) { int retval = ((circuit_t & level) == level); /* simple approach */ return retval; } /* * Verify authentication information * Support cleartext and HMAC MD5 authentication */ static int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct stream *stream, uint32_t auth_tlv_offset) { unsigned char digest[ISIS_AUTH_MD5_SIZE]; /* Auth fail () - passwd type mismatch */ if (local->type != remote->type) return ISIS_ERROR; switch (local->type) { /* No authentication required */ case ISIS_PASSWD_TYPE_UNUSED: break; /* Cleartext (ISO 10589) */ case ISIS_PASSWD_TYPE_CLEARTXT: /* Auth fail () - passwd len mismatch */ if (remote->len != local->len) return ISIS_ERROR; return memcmp (local->passwd, remote->passwd, local->len); /* HMAC MD5 (RFC 3567) */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Auth fail () - passwd len mismatch */ if (remote->len != ISIS_AUTH_MD5_SIZE) return ISIS_ERROR; /* Set the authentication value to 0 before the check */ memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0, ISIS_AUTH_MD5_SIZE); /* Compute the digest */ hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream), (unsigned char *) &(local->passwd), local->len, (unsigned char *) &digest); /* Copy back the authentication value after the check */ memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3, remote->passwd, ISIS_AUTH_MD5_SIZE); return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE); default: zlog_err ("Unsupported authentication type"); return ISIS_ERROR; } /* Authentication pass when no authentication is configured */ return ISIS_OK; } static int lsp_authentication_check (struct stream *stream, struct isis_area *area, int level, struct isis_passwd *passwd) { struct isis_link_state_hdr *hdr; uint32_t expected = 0, found = 0, auth_tlv_offset = 0; uint16_t checksum, rem_lifetime, pdu_len; struct tlvs tlvs; int retval = ISIS_OK; hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream)); pdu_len = ntohs (hdr->pdu_len); expected |= TLVFLAG_AUTH_INFO; auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN; retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN, pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs, &auth_tlv_offset); if (retval != ISIS_OK) { zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, " "cksum 0x%04x, lifetime %us, len %u", area->area_tag, level, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), pdu_len); if ((isis->debugs & DEBUG_UPDATE_PACKETS) && (isis->debugs & DEBUG_PACKET_DUMP)) zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream)); return retval; } if (!(found & TLVFLAG_AUTH_INFO)) { zlog_err ("No authentication tlv in LSP"); return ISIS_ERROR; } if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT && tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) { zlog_err ("Unknown authentication type in LSP"); return ISIS_ERROR; } /* * RFC 5304 set checksum and remaining lifetime to zero before * verification and reset to old values after verification. */ checksum = hdr->checksum; rem_lifetime = hdr->rem_lifetime; hdr->checksum = 0; hdr->rem_lifetime = 0; retval = authentication_check (&tlvs.auth_info, passwd, stream, auth_tlv_offset); hdr->checksum = checksum; hdr->rem_lifetime = rem_lifetime; return retval; } /* * Processing helper functions */ static void del_addr (void *val) { XFREE (MTYPE_ISIS_TMP, val); } static void tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) { struct listnode *node; struct area_addr *area_addr, *malloced; if (adj->area_addrs) { adj->area_addrs->del = del_addr; list_delete (adj->area_addrs); } adj->area_addrs = list_new (); if (tlvs->area_addrs) { for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr)) { malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr)); memcpy (malloced, area_addr, sizeof (struct area_addr)); listnode_add (adj->area_addrs, malloced); } } } static int tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) { int i; struct nlpids *tlv_nlpids; if (tlvs->nlpids) { tlv_nlpids = tlvs->nlpids; if (tlv_nlpids->count > array_size (adj->nlpids.nlpids)) return 1; adj->nlpids.count = tlv_nlpids->count; for (i = 0; i < tlv_nlpids->count; i++) { adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i]; } } return 0; } static void tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) { struct listnode *node; struct in_addr *ipv4_addr, *malloced; if (adj->ipv4_addrs) { adj->ipv4_addrs->del = del_addr; list_delete (adj->ipv4_addrs); } adj->ipv4_addrs = list_new (); if (tlvs->ipv4_addrs) { for (ALL_LIST_ELEMENTS_RO (tlvs->ipv4_addrs, node, ipv4_addr)) { malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr)); memcpy (malloced, ipv4_addr, sizeof (struct in_addr)); listnode_add (adj->ipv4_addrs, malloced); } } } #ifdef HAVE_IPV6 static void tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) { struct listnode *node; struct in6_addr *ipv6_addr, *malloced; if (adj->ipv6_addrs) { adj->ipv6_addrs->del = del_addr; list_delete (adj->ipv6_addrs); } adj->ipv6_addrs = list_new (); if (tlvs->ipv6_addrs) { for (ALL_LIST_ELEMENTS_RO (tlvs->ipv6_addrs, node, ipv6_addr)) { malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr)); memcpy (malloced, ipv6_addr, sizeof (struct in6_addr)); listnode_add (adj->ipv6_addrs, malloced); } } } #endif /* HAVE_IPV6 */ /* * RECEIVE SIDE */ /* * Process P2P IIH * ISO - 10589 * Section 8.2.5 - Receiving point-to-point IIH PDUs * */ static int process_p2p_hello (struct isis_circuit *circuit) { int retval = ISIS_OK; struct isis_p2p_hello_hdr *hdr; struct isis_adjacency *adj; u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; uint16_t pdu_len; struct tlvs tlvs; int v4_usable = 0, v6_usable = 0; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u", circuit->area->area_tag, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } if (circuit->circ_type != CIRCUIT_T_P2P) { zlog_warn ("p2p hello on non p2p circuit"); return ISIS_WARNING; } if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN) { zlog_warn ("Packet too short"); return ISIS_WARNING; } /* 8.2.5.1 PDU acceptance tests */ /* 8.2.5.1 a) external domain untrue */ /* FIXME: not useful at all? */ /* 8.2.5.1 b) ID Length mismatch */ /* checked at the handle_pdu */ /* 8.2.5.2 IIH PDU Processing */ /* 8.2.5.2 a) 1) Maximum Area Addresses */ /* Already checked, and can also be ommited */ /* * Get the header */ hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream); pdu_len = ntohs (hdr->pdu_len); if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " "invalid pdu length %d", circuit->area->area_tag, circuit->interface->name, pdu_len); return ISIS_WARNING; } /* * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ if (pdu_len < stream_get_endp (circuit->rcv_stream)) stream_set_endp (circuit->rcv_stream, pdu_len); stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); /* * Lets get the TLVS now */ expected |= TLVFLAG_AREA_ADDRS; expected |= TLVFLAG_AUTH_INFO; expected |= TLVFLAG_NLPID; expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV6_ADDR; auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { zlog_warn ("parse_tlvs() failed"); free_tlvs (&tlvs); return retval; }; if (!(found & TLVFLAG_AREA_ADDRS)) { zlog_warn ("No Area addresses TLV in P2P IS to IS hello"); free_tlvs (&tlvs); return ISIS_WARNING; } if (!(found & TLVFLAG_NLPID)) { zlog_warn ("No supported protocols TLV in P2P IS to IS hello"); free_tlvs (&tlvs); return ISIS_WARNING; } /* 8.2.5.1 c) Authentication */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || authentication_check (&tlvs.auth_info, &circuit->passwd, circuit->rcv_stream, auth_tlv_offset)) { isis_event_auth_failure (circuit->area->area_tag, "P2P hello authentication failure", hdr->source_id); free_tlvs (&tlvs); return ISIS_OK; } } /* * check if it's own interface ip match iih ip addrs */ if (found & TLVFLAG_IPV4_ADDR) { if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) v4_usable = 1; else zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap " "in P2P IIH from %s\n", circuit->interface->name); } #ifndef HAVE_IPV6 else /* !(found & TLVFLAG_IPV4_ADDR) */ zlog_warn ("ISIS-Adj: no IPv4 in P2P IIH from %s " "(this isisd has no IPv6)\n", circuit->interface->name); #else if (found & TLVFLAG_IPV6_ADDR) { /* TBA: check that we have a linklocal ourselves? */ struct listnode *node; struct in6_addr *ip; for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) if (IN6_IS_ADDR_LINKLOCAL (ip)) { v6_usable = 1; break; } if (!v6_usable) zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local " "in P2P IIH from %s\n", circuit->interface->name); } if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n", circuit->interface->name); #endif if (!v6_usable && !v4_usable) { free_tlvs (&tlvs); return ISIS_WARNING; } /* * it's own p2p IIH PDU - discard */ if (!memcmp (hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN)) { zlog_warn ("ISIS-Adj (%s): it's own IIH PDU - discarded", circuit->area->area_tag); free_tlvs (&tlvs); return ISIS_WARNING; } /* * My interpertation of the ISO, if no adj exists we will create one for * the circuit */ adj = circuit->u.p2p.neighbor; /* If an adjacency exists, check it is with the source of the hello * packets */ if (adj) { if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN)) { zlog_debug("hello source and adjacency do not match, set adj down\n"); isis_adj_state_change (adj, ISIS_ADJ_DOWN, "adj do not exist"); return 0; } } if (!adj || adj->level != hdr->circuit_t) { if (!adj) { adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit); if (adj == NULL) return ISIS_ERROR; } else { adj->level = hdr->circuit_t; } circuit->u.p2p.neighbor = adj; /* Build lsp with the new neighbor entry when a new * adjacency is formed. Set adjacency circuit type to * IIH PDU header circuit type before lsp is regenerated * when an adjacency is up. This will result in the new * adjacency entry getting added to the lsp tlv neighbor list. */ adj->circuit_t = hdr->circuit_t; isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } /* 8.2.6 Monitoring point-to-point adjacencies */ adj->hold_time = ntohs (hdr->hold_time); adj->last_upd = time (NULL); /* we do this now because the adj may not survive till the end... */ tlvs_to_adj_area_addrs (&tlvs, adj); /* which protocol are spoken ??? */ if (tlvs_to_adj_nlpids (&tlvs, adj)) { free_tlvs (&tlvs); return ISIS_WARNING; } /* we need to copy addresses to the adj */ if (found & TLVFLAG_IPV4_ADDR) tlvs_to_adj_ipv4_addrs (&tlvs, adj); /* Update MPLS TE Remote IP address parameter if possible */ if (IS_MPLS_TE(isisMplsTE) && circuit->mtc && IS_CIRCUIT_TE(circuit->mtc)) if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0) { struct in_addr *ip_addr; ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs)); set_circuitparams_rmt_ipaddr (circuit->mtc, *ip_addr); } #ifdef HAVE_IPV6 if (found & TLVFLAG_IPV6_ADDR) tlvs_to_adj_ipv6_addrs (&tlvs, adj); #endif /* HAVE_IPV6 */ /* lets take care of the expiry */ THREAD_TIMER_OFF (adj->t_expire); THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, (long) adj->hold_time); /* 8.2.5.2 a) a match was detected */ if (area_match (circuit->area->area_addrs, tlvs.area_addrs)) { /* 8.2.5.2 a) 2) If the system is L1 - table 5 */ if (circuit->area->is_type == IS_LEVEL_1) { switch (hdr->circuit_t) { case IS_LEVEL_1: case IS_LEVEL_1_AND_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (4) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (5) adj usage level 1 */ adj->adj_usage = ISIS_ADJ_LEVEL1; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { ; /* accept */ } break; case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (7) reject - wrong system type event */ zlog_warn ("wrongSystemType"); free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (6) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } break; } } /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */ if (circuit->area->is_type == IS_LEVEL_1_AND_2) { switch (hdr->circuit_t) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (7) adj usage level 1 */ adj->adj_usage = ISIS_ADJ_LEVEL1; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { ; /* accept */ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (8) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } break; case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (9) adj usage level 2 */ adj->adj_usage = ISIS_ADJ_LEVEL2; } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)) { /* (8) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { ; /* Accept */ } break; case IS_LEVEL_1_AND_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (10) adj usage level 1 */ adj->adj_usage = ISIS_ADJ_LEVEL1AND2; } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (8) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { ; /* Accept */ } break; } } /* 8.2.5.2 a) 4) If the system is L2 - table 7 */ if (circuit->area->is_type == IS_LEVEL_2) { switch (hdr->circuit_t) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (5) reject - wrong system type event */ zlog_warn ("wrongSystemType"); free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (6) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } break; case IS_LEVEL_1_AND_2: case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (7) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (8) adj usage level 2 */ adj->adj_usage = ISIS_ADJ_LEVEL2; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { /* (6) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { ; /* Accept */ } break; } } } /* 8.2.5.2 b) if no match was detected */ else if (listcount (circuit->area->area_addrs) > 0) { if (circuit->area->is_type == IS_LEVEL_1) { /* 8.2.5.2 b) 1) is_type L1 and adj is not up */ if (adj->adj_state != ISIS_ADJ_UP) { isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); /* 8.2.5.2 b) 2)is_type L1 and adj is up */ } else { isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Down - Area Mismatch"); } } /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */ else { switch (hdr->circuit_t) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) reject - Area Mismatch event */ zlog_warn ("AreaMismatch"); free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - area mismatch */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (7) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } break; case IS_LEVEL_1_AND_2: case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (8) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (9) adj usage level 2 */ adj->adj_usage = ISIS_ADJ_LEVEL2; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { if (hdr->circuit_t == IS_LEVEL_2) { /* (7) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else { /* (7) down - area mismatch */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); } } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { ; /* Accept */ } break; } } } else { /* down - area mismatch */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); } /* 8.2.5.2 c) if the action was up - comparing circuit IDs */ /* FIXME - Missing parts */ /* some of my own understanding of the ISO, why the heck does * it not say what should I change the system_type to... */ switch (adj->adj_usage) { case ISIS_ADJ_LEVEL1: adj->sys_type = ISIS_SYSTYPE_L1_IS; break; case ISIS_ADJ_LEVEL2: adj->sys_type = ISIS_SYSTYPE_L2_IS; break; case ISIS_ADJ_LEVEL1AND2: adj->sys_type = ISIS_SYSTYPE_L2_IS; break; case ISIS_ADJ_NONE: adj->sys_type = ISIS_SYSTYPE_UNKNOWN; break; } if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," " cir id %02d, length %d", circuit->area->area_tag, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id, pdu_len); } free_tlvs (&tlvs); return retval; } /* * Process IS-IS LAN Level 1/2 Hello PDU */ static int process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa) { int retval = ISIS_OK; struct isis_lan_hello_hdr hdr; struct isis_adjacency *adj; u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; struct tlvs tlvs; u_char *snpa; struct listnode *node; int v4_usable = 0, v6_usable = 0; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, " "cirID %u", circuit->area->area_tag, level, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn ("lan hello on non broadcast circuit"); return ISIS_WARNING; } if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN) { zlog_warn ("Packet too short"); return ISIS_WARNING; } if (circuit->ext_domain) { zlog_debug ("level %d LAN Hello received over circuit with " "externalDomain = true", level); return ISIS_WARNING; } if (!accept_level (level, circuit->is_type)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s", circuit->area->area_tag, circuit->interface->name); } return ISIS_WARNING; } #if 0 /* Cisco's debug message compatability */ if (!accept_level (level, circuit->area->is_type)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): is type mismatch", circuit->area->area_tag); } return ISIS_WARNING; } #endif /* * Fill the header */ hdr.circuit_t = stream_getc (circuit->rcv_stream); stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); hdr.hold_time = stream_getw (circuit->rcv_stream); hdr.pdu_len = stream_getw (circuit->rcv_stream); hdr.prio = stream_getc (circuit->rcv_stream); stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) || hdr.pdu_len > ISO_MTU(circuit) || hdr.pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " "invalid pdu length %d", circuit->area->area_tag, circuit->interface->name, hdr.pdu_len); return ISIS_WARNING; } /* * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream)) stream_set_endp (circuit->rcv_stream, hdr.pdu_len); if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 && hdr.circuit_t != IS_LEVEL_1_AND_2 && (level & hdr.circuit_t) == 0) { zlog_err ("Level %d LAN Hello with Circuit Type %d", level, hdr.circuit_t); return ISIS_ERROR; } /* * Then get the tlvs */ expected |= TLVFLAG_AUTH_INFO; expected |= TLVFLAG_AREA_ADDRS; expected |= TLVFLAG_LAN_NEIGHS; expected |= TLVFLAG_NLPID; expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV6_ADDR; auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { zlog_warn ("parse_tlvs() failed"); goto out; } if (!(found & TLVFLAG_AREA_ADDRS)) { zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello", level); retval = ISIS_WARNING; goto out; } if (!(found & TLVFLAG_NLPID)) { zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello", level); retval = ISIS_WARNING; goto out; } /* Verify authentication, either cleartext of HMAC MD5 */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || authentication_check (&tlvs.auth_info, &circuit->passwd, circuit->rcv_stream, auth_tlv_offset)) { isis_event_auth_failure (circuit->area->area_tag, "LAN hello authentication failure", hdr.source_id); retval = ISIS_WARNING; goto out; } } if (!memcmp (hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN)) { zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s", circuit->area->area_tag, circuit->interface->name); return ISIS_WARNING; } /* * Accept the level 1 adjacency only if a match between local and * remote area addresses is found */ if (listcount (circuit->area->area_addrs) == 0 || (level == IS_LEVEL_1 && area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s", circuit->area->area_tag, level, circuit->interface->name); } retval = ISIS_OK; goto out; } /* * it's own IIH PDU - discard silently */ if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN)) { zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded", circuit->area->area_tag); retval = ISIS_OK; goto out; } /* * check if it's own interface ip match iih ip addrs */ if (found & TLVFLAG_IPV4_ADDR) { if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) v4_usable = 1; else zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap " "in LAN IIH from %s\n", circuit->interface->name); } #ifndef HAVE_IPV6 else /* !(found & TLVFLAG_IPV4_ADDR) */ zlog_warn ("ISIS-Adj: no IPv4 in LAN IIH from %s " "(this isisd has no IPv6)\n", circuit->interface->name); #else if (found & TLVFLAG_IPV6_ADDR) { /* TBA: check that we have a linklocal ourselves? */ struct listnode *node; struct in6_addr *ip; for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) if (IN6_IS_ADDR_LINKLOCAL (ip)) { v6_usable = 1; break; } if (!v6_usable) zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local " "in LAN IIH from %s\n", circuit->interface->name); } if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n", circuit->interface->name); #endif if (!v6_usable && !v4_usable) { free_tlvs (&tlvs); return ISIS_WARNING; } adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]); if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) || (adj->level != level)) { if (!adj) { /* * Do as in 8.4.2.5 */ adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit); if (adj == NULL) { retval = ISIS_ERROR; goto out; } } else { if (ssnpa) { memcpy (adj->snpa, ssnpa, 6); } else { memset (adj->snpa, ' ', 6); } adj->level = level; } isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); if (level == IS_LEVEL_1) adj->sys_type = ISIS_SYSTYPE_L1_IS; else adj->sys_type = ISIS_SYSTYPE_L2_IS; list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], circuit->u.bc.lan_neighs[level - 1]); } if(adj->dis_record[level-1].dis==ISIS_IS_DIS) switch (level) { case 1: if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) { thread_add_event (master, isis_event_dis_status_change, circuit, 0); memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1); } break; case 2: if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) { thread_add_event (master, isis_event_dis_status_change, circuit, 0); memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1); } break; } adj->hold_time = hdr.hold_time; adj->last_upd = time (NULL); adj->prio[level - 1] = hdr.prio; memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1); tlvs_to_adj_area_addrs (&tlvs, adj); /* which protocol are spoken ??? */ if (tlvs_to_adj_nlpids (&tlvs, adj)) { retval = ISIS_WARNING; goto out; } /* we need to copy addresses to the adj */ if (found & TLVFLAG_IPV4_ADDR) tlvs_to_adj_ipv4_addrs (&tlvs, adj); #ifdef HAVE_IPV6 if (found & TLVFLAG_IPV6_ADDR) tlvs_to_adj_ipv6_addrs (&tlvs, adj); #endif /* HAVE_IPV6 */ adj->circuit_t = hdr.circuit_t; /* lets take care of the expiry */ THREAD_TIMER_OFF (adj->t_expire); THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, (long) adj->hold_time); /* * If the snpa for this circuit is found from LAN Neighbours TLV * we have two-way communication -> adjacency can be put to state "up" */ if (found & TLVFLAG_LAN_NEIGHS) { if (adj->adj_state != ISIS_ADJ_UP) { for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) { if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) { isis_adj_state_change (adj, ISIS_ADJ_UP, "own SNPA found in LAN Neighbours TLV"); } } } else { int found = 0; for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) { found = 1; break; } if (found == 0) isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, "own SNPA not found in LAN Neighbours TLV"); } } else if (adj->adj_state == ISIS_ADJ_UP) { isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, "no LAN Neighbours TLV found"); } out: if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, " "cirID %u, length %zd", circuit->area->area_tag, level, snpa_print (ssnpa), circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id, stream_get_endp (circuit->rcv_stream)); } free_tlvs (&tlvs); return retval; } /* * Process Level 1/2 Link State * ISO - 10589 * Section 7.3.15.1 - Action on receipt of a link state PDU */ static int process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa) { struct isis_link_state_hdr *hdr; struct isis_adjacency *adj = NULL; struct isis_lsp *lsp, *lsp0 = NULL; int retval = ISIS_OK, comp = 0; u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_passwd *passwd; uint16_t pdu_len; int lsp_confusion; if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u", circuit->area->area_tag, level, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN) { zlog_warn ("Packet too short"); return ISIS_WARNING; } /* Reference the header */ hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream); pdu_len = ntohs (hdr->pdu_len); /* lsp length check */ if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), pdu_len); return ISIS_WARNING; } /* * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ if (pdu_len < stream_get_endp (circuit->rcv_stream)) stream_set_endp (circuit->rcv_stream, pdu_len); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, " "lifetime %us, len %u, on %s", circuit->area->area_tag, level, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), pdu_len, circuit->interface->name); } /* lsp is_type check */ if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 && (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), hdr->lsp_bits); /* continue as per RFC1122 Be liberal in what you accept, and * conservative in what you send */ } /* Checksum sanity check - FIXME: move to correct place */ /* 12 = sysid+pdu+remtime */ if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4, pdu_len - 12, &hdr->checksum)) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohs (hdr->checksum)); return ISIS_WARNING; } /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */ if (circuit->ext_domain) { zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit with " "externalDomain = true", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), level); return ISIS_WARNING; } /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */ if (!accept_level (level, circuit->is_type)) { zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of" " type %s", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), level, circuit_t2string (circuit->is_type)); return ISIS_WARNING; } /* 7.3.15.1 a) 4 - need to make sure IDLength matches */ /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */ /* 7.3.15.1 a) 7 - password check */ (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) : (passwd = &circuit->area->domain_passwd); if (passwd->type) { if (lsp_authentication_check (circuit->rcv_stream, circuit->area, level, passwd)) { isis_event_auth_failure (circuit->area->area_tag, "LSP authentication failure", hdr->lsp_id); return ISIS_WARNING; } } /* Find the LSP in our database and compare it to this Link State header */ lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]); if (lsp) comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num, hdr->checksum, hdr->rem_lifetime); if (lsp && (lsp->own_lsp #ifdef TOPOLOGY_GENERATE || lsp->from_topology #endif /* TOPOLOGY_GENERATE */ )) goto dontcheckadj; /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */ /* for broadcast circuits, snpa should be compared */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]); if (!adj) { zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, " "lifetime %us on %s", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), circuit->interface->name); return ISIS_WARNING; /* Silently discard */ } } /* for non broadcast, we just need to find same level adj */ else { /* If no adj, or no sharing of level */ if (!circuit->u.p2p.neighbor) { return ISIS_OK; /* Silently discard */ } else { if (((level == IS_LEVEL_1) && (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) || ((level == IS_LEVEL_2) && (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1))) return ISIS_WARNING; /* Silently discard */ adj = circuit->u.p2p.neighbor; } } dontcheckadj: /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */ /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */ /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */ /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num but * wrong checksum, initiate a purge. */ if (lsp && (lsp->lsp_header->seq_num == hdr->seq_num) && (lsp->lsp_header->checksum != hdr->checksum)) { zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.", circuit->area->area_tag, rawlspid_print(hdr->lsp_id), ntohl(hdr->seq_num)); hdr->rem_lifetime = 0; lsp_confusion = 1; } else lsp_confusion = 0; /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */ if (hdr->rem_lifetime == 0) { if (!lsp) { /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */ /* only needed on explicit update, eg - p2p */ if (circuit->circ_type == CIRCUIT_T_P2P) ack_lsp (hdr, circuit, level); return retval; /* FIXME: do we need a purge? */ } else { if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) { /* LSP by some other system -> do 7.3.16.4 b) */ /* 7.3.16.4 b) 1) */ if (comp == LSP_NEWER) { lsp_update (lsp, circuit->rcv_stream, circuit->area, level); /* ii */ lsp_set_all_srmflags (lsp); /* v */ ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */ /* For the case of lsp confusion, flood the purge back to its * originator so that it can react. Otherwise, don't reflood * through incoming circuit as usual */ if (!lsp_confusion) { /* iii */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* iv */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); } } /* 7.3.16.4 b) 2) */ else if (comp == LSP_EQUAL) { /* i */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* ii */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); } /* 7.3.16.4 b) 3) */ else { ISIS_SET_FLAG (lsp->SRMflags, circuit); ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } else if (lsp->lsp_header->rem_lifetime != 0) { /* our own LSP -> 7.3.16.4 c) */ if (comp == LSP_NEWER) { lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); lsp_set_all_srmflags (lsp); } else { ISIS_SET_FLAG (lsp->SRMflags, circuit); ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new " "seq 0x%08x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (lsp->lsp_header->seq_num)); } } return retval; } /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a * purge */ if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) { if (!lsp) { /* 7.3.16.4: initiate a purge */ lsp_purge_non_exist(level, hdr, circuit->area); return ISIS_OK; } /* 7.3.15.1 d) - If this is our own lsp and we have it */ /* In 7.3.16.1, If an Intermediate system R somewhere in the domain * has information that the current sequence number for source S is * "greater" than that held by S, ... */ if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) { /* 7.3.16.1 */ lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq " "0x%08x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (lsp->lsp_header->seq_num)); } /* If the received LSP is older or equal, * resend the LSP which will act as ACK */ lsp_set_all_srmflags (lsp); } else { /* 7.3.15.1 e) - This lsp originated on another system */ /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */ if ((!lsp || comp == LSP_NEWER)) { /* * If this lsp is a frag, need to see if we have zero lsp present */ if (LSP_FRAGMENT (hdr->lsp_id) != 0) { memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lspid) = 0; lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]); if (!lsp0) { zlog_debug ("Got lsp frag, while zero lsp not in database"); return ISIS_OK; } } /* i */ if (!lsp) { lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, pdu_len, lsp0, circuit->area, level); lsp_insert (lsp, circuit->area->lspdb[level - 1]); } else /* exists, so we overwrite */ { lsp_update (lsp, circuit->rcv_stream, circuit->area, level); } /* ii */ lsp_set_all_srmflags (lsp); /* iii */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* iv */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); /* FIXME: v) */ } /* 7.3.15.1 e) 2) LSP equal to the one in db */ else if (comp == LSP_EQUAL) { ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); lsp_update (lsp, circuit->rcv_stream, circuit->area, level); if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); } /* 7.3.15.1 e) 3) LSP older than the one in db */ else { ISIS_SET_FLAG (lsp->SRMflags, circuit); ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } return retval; } /* * Process Sequence Numbers * ISO - 10589 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU */ static int process_snp (int snp_type, int level, struct isis_circuit *circuit, const u_char *ssnpa) { int retval = ISIS_OK; int cmp, own_lsp; char typechar = ' '; uint16_t pdu_len; struct isis_adjacency *adj; struct isis_complete_seqnum_hdr *chdr = NULL; struct isis_partial_seqnum_hdr *phdr = NULL; uint32_t found = 0, expected = 0, auth_tlv_offset = 0; struct isis_lsp *lsp; struct lsp_entry *entry; struct listnode *node, *nnode; struct listnode *node2, *nnode2; struct tlvs tlvs; struct list *lsp_list = NULL; struct isis_passwd *passwd; if (snp_type == ISIS_SNP_CSNP_FLAG) { /* getting the header info */ typechar = 'C'; chdr = (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN); pdu_len = ntohs (chdr->pdu_len); if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("Received a CSNP with bogus length %d", pdu_len); return ISIS_WARNING; } } else { typechar = 'P'; phdr = (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN); pdu_len = ntohs (phdr->pdu_len); if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("Received a PSNP with bogus length %d", pdu_len); return ISIS_WARNING; } } /* * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ if (pdu_len < stream_get_endp (circuit->rcv_stream)) stream_set_endp (circuit->rcv_stream, pdu_len); /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ if (circuit->ext_domain) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " "skipping: circuit externalDomain = true", circuit->area->area_tag, level, typechar, circuit->interface->name); return ISIS_OK; } /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */ if (!accept_level (level, circuit->is_type)) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " "skipping: circuit type %s does not match level %d", circuit->area->area_tag, level, typechar, circuit->interface->name, circuit_t2string (circuit->is_type), level); return ISIS_OK; } /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */ if ((snp_type == ISIS_SNP_PSNP_FLAG) && (circuit->circ_type == CIRCUIT_T_BROADCAST) && (!circuit->u.bc.is_dr[level - 1])) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, " "skipping: we are not the DIS", circuit->area->area_tag, level, typechar, snpa_print (ssnpa), circuit->interface->name); return ISIS_OK; } /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */ /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3 * - already checked */ /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */ /* for broadcast circuits, snpa should be compared */ /* FIXME : Do we need to check SNPA? */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { if (snp_type == ISIS_SNP_CSNP_FLAG) { adj = isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]); } else { /* a psnp on a broadcast, how lovely of Juniper :) */ adj = isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]); } if (!adj) return ISIS_OK; /* Silently discard */ } else { if (!circuit->u.p2p.neighbor) { zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name); return ISIS_OK; /* Silently discard */ } } /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */ /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */ memset (&tlvs, 0, sizeof (struct tlvs)); /* parse the SNP */ expected |= TLVFLAG_LSP_ENTRIES; expected |= TLVFLAG_AUTH_INFO; auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), pdu_len - stream_get_getp (circuit->rcv_stream), &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { zlog_warn ("something went very wrong processing SNP"); free_tlvs (&tlvs); return retval; } if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) { if (passwd->type) { if (!(found & TLVFLAG_AUTH_INFO) || authentication_check (&tlvs.auth_info, passwd, circuit->rcv_stream, auth_tlv_offset)) { isis_event_auth_failure (circuit->area->area_tag, "SNP authentication" " failure", phdr ? phdr->source_id : chdr->source_id); free_tlvs (&tlvs); return ISIS_OK; } } } /* debug isis snp-packets */ if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s", circuit->area->area_tag, level, typechar, snpa_print (ssnpa), circuit->interface->name); if (tlvs.lsp_entries) { for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry)) { zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x," " cksum 0x%04x, lifetime %us", circuit->area->area_tag, typechar, rawlspid_print (entry->lsp_id), ntohl (entry->seq_num), ntohs (entry->checksum), ntohs (entry->rem_lifetime)); } } } /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */ if (tlvs.lsp_entries) { for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry)) { lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]); own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN); if (lsp) { /* 7.3.15.2 b) 1) is this LSP newer */ cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num, entry->checksum, entry->rem_lifetime); /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */ if (cmp == LSP_EQUAL) { /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */ else if (cmp == LSP_OLDER) { ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); ISIS_SET_FLAG (lsp->SRMflags, circuit); } /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */ else { if (own_lsp) { lsp_inc_seqnum (lsp, ntohl (entry->seq_num)); ISIS_SET_FLAG (lsp->SRMflags, circuit); } else { ISIS_SET_FLAG (lsp->SSNflags, circuit); /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } } } else { /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0, * insert it and set SSN on it */ if (entry->rem_lifetime && entry->checksum && entry->seq_num && memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) { lsp = lsp_new(circuit->area, entry->lsp_id, ntohs(entry->rem_lifetime), 0, 0, entry->checksum, level); lsp_insert (lsp, circuit->area->lspdb[level - 1]); ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); ISIS_SET_FLAG (lsp->SSNflags, circuit); } } } } /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */ if (snp_type == ISIS_SNP_CSNP_FLAG) { /* * Build a list from our own LSP db bounded with * start_lsp_id and stop_lsp_id */ lsp_list = list_new (); lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id, lsp_list, circuit->area->lspdb[level - 1]); /* Fixme: Find a better solution */ if (tlvs.lsp_entries) { for (ALL_LIST_ELEMENTS (tlvs.lsp_entries, node, nnode, entry)) { for (ALL_LIST_ELEMENTS (lsp_list, node2, nnode2, lsp)) { if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0) { list_delete_node (lsp_list, node2); break; } } } } /* on remaining LSPs we set SRM (neighbor knew not of) */ for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp)) ISIS_SET_FLAG (lsp->SRMflags, circuit); /* lets free it */ list_delete (lsp_list); } free_tlvs (&tlvs); return retval; } static int process_csnp (int level, struct isis_circuit *circuit, const u_char *ssnpa) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u", circuit->area->area_tag, level, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } /* Sanity check - FIXME: move to correct place */ if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN) { zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN); return ISIS_WARNING; } return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa); } static int process_psnp (int level, struct isis_circuit *circuit, const u_char *ssnpa) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u", circuit->area->area_tag, level, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN) { zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN); return ISIS_WARNING; } return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa); } /* * PDU Dispatcher */ static int isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa) { struct isis_fixed_hdr *hdr; int retval = ISIS_OK; /* * Let's first read data from stream to the header */ hdr = (struct isis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream); if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)) { zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp); return ISIS_ERROR; } /* now we need to know if this is an ISO 9542 packet and * take real good care of it, waaa! */ if (hdr->idrp == ISO9542_ESIS) { zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp); return ISIS_ERROR; } stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN); /* * and then process it */ if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN) { zlog_err ("Fixed header length = %d", hdr->length); return ISIS_ERROR; } if (hdr->version1 != 1) { zlog_warn ("Unsupported ISIS version %u", hdr->version1); return ISIS_WARNING; } /* either 6 or 0 */ if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN)) { zlog_err ("IDFieldLengthMismatch: ID Length field in a received PDU %u, " "while the parameter for this IS is %u", hdr->id_len, ISIS_SYS_ID_LEN); return ISIS_ERROR; } if (hdr->version2 != 1) { zlog_warn ("Unsupported ISIS version %u", hdr->version2); return ISIS_WARNING; } if (circuit->is_passive) { zlog_warn ("Received ISIS PDU on passive circuit %s", circuit->interface->name); return ISIS_WARNING; } /* either 3 or 0 */ if ((hdr->max_area_addrs != 0) && (hdr->max_area_addrs != isis->max_area_addrs)) { zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a " "received PDU %u while the parameter for this IS is %u", hdr->max_area_addrs, isis->max_area_addrs); return ISIS_ERROR; } switch (hdr->pdu_type) { case L1_LAN_HELLO: retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa); break; case L2_LAN_HELLO: retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa); break; case P2P_HELLO: retval = process_p2p_hello (circuit); break; case L1_LINK_STATE: retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa); break; case L2_LINK_STATE: retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa); break; case L1_COMPLETE_SEQ_NUM: retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa); break; case L2_COMPLETE_SEQ_NUM: retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa); break; case L1_PARTIAL_SEQ_NUM: retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa); break; case L2_PARTIAL_SEQ_NUM: retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa); break; default: return ISIS_ERROR; } return retval; } #ifdef GNU_LINUX int isis_receive (struct thread *thread) { struct isis_circuit *circuit; u_char ssnpa[ETH_ALEN]; int retval; /* * Get the circuit */ circuit = THREAD_ARG (thread); assert (circuit); isis_circuit_stream(circuit, &circuit->rcv_stream); retval = circuit->rx (circuit, ssnpa); circuit->t_read = NULL; if (retval == ISIS_OK) retval = isis_handle_pdu (circuit, ssnpa); /* * prepare for next packet. */ if (!circuit->is_passive) { THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit, circuit->fd); } return retval; } #else int isis_receive (struct thread *thread) { struct isis_circuit *circuit; u_char ssnpa[ETH_ALEN]; int retval; /* * Get the circuit */ circuit = THREAD_ARG (thread); assert (circuit); circuit->t_read = NULL; isis_circuit_stream(circuit, &circuit->rcv_stream); retval = circuit->rx (circuit, ssnpa); if (retval == ISIS_OK) retval = isis_handle_pdu (circuit, ssnpa); /* * prepare for next packet. */ if (!circuit->is_passive) { circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit, listcount (circuit->area->circuit_list) * 100); } return retval; } #endif /* filling of the fixed isis header */ void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type) { memset (hdr, 0, sizeof (struct isis_fixed_hdr)); hdr->idrp = ISO10589_ISIS; switch (pdu_type) { case L1_LAN_HELLO: case L2_LAN_HELLO: hdr->length = ISIS_LANHELLO_HDRLEN; break; case P2P_HELLO: hdr->length = ISIS_P2PHELLO_HDRLEN; break; case L1_LINK_STATE: case L2_LINK_STATE: hdr->length = ISIS_LSP_HDR_LEN; break; case L1_COMPLETE_SEQ_NUM: case L2_COMPLETE_SEQ_NUM: hdr->length = ISIS_CSNP_HDRLEN; break; case L1_PARTIAL_SEQ_NUM: case L2_PARTIAL_SEQ_NUM: hdr->length = ISIS_PSNP_HDRLEN; break; default: zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type); return; } hdr->length += ISIS_FIXED_HDR_LEN; hdr->pdu_type = pdu_type; hdr->version1 = 1; hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */ hdr->version2 = 1; hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */ } /* * SEND SIDE */ static void fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type, struct stream *stream) { fill_fixed_hdr (hdr, pdu_type); stream_putc (stream, hdr->idrp); stream_putc (stream, hdr->length); stream_putc (stream, hdr->version1); stream_putc (stream, hdr->id_len); stream_putc (stream, hdr->pdu_type); stream_putc (stream, hdr->version2); stream_putc (stream, hdr->reserved); stream_putc (stream, hdr->max_area_addrs); return; } int send_hello (struct isis_circuit *circuit, int level) { struct isis_fixed_hdr fixed_hdr; struct isis_lan_hello_hdr hello_hdr; struct isis_p2p_hello_hdr p2p_hello_hdr; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; size_t len_pointer, length, auth_tlv_offset = 0; u_int32_t interval; int retval; if (circuit->is_passive) return ISIS_OK; if (circuit->interface->mtu == 0) { zlog_warn ("circuit has zero MTU"); return ISIS_WARNING; } isis_circuit_stream(circuit, &circuit->snd_stream); if (circuit->circ_type == CIRCUIT_T_BROADCAST) if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, L2_LAN_HELLO, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, P2P_HELLO, circuit->snd_stream); /* * Fill LAN Level 1 or 2 Hello PDU header */ memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr)); interval = circuit->hello_multiplier[level - 1] * circuit->hello_interval[level - 1]; if (interval > USHRT_MAX) interval = USHRT_MAX; hello_hdr.circuit_t = circuit->is_type; memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN); hello_hdr.hold_time = htons ((u_int16_t) interval); hello_hdr.pdu_len = 0; /* Update the PDU Length later */ len_pointer = stream_get_endp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN; /* copy the shared part of the hello to the p2p hello if needed */ if (circuit->circ_type == CIRCUIT_T_P2P) { memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN); p2p_hello_hdr.local_id = circuit->circuit_id; /* FIXME: need better understanding */ stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN); } else { hello_hdr.prio = circuit->priority[level - 1]; if (level == IS_LEVEL_1) { memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); } else if (level == IS_LEVEL_2) { memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); } stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN); } /* * Then the variable length part. */ /* add circuit password */ switch (circuit->passwd.type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, circuit->passwd.passwd, circuit->snd_stream)) return ISIS_WARNING; break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later overwrite the MD5 hash */ auth_tlv_offset = stream_get_endp (circuit->snd_stream); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, circuit->snd_stream)) return ISIS_WARNING; break; default: break; } /* Area Addresses TLV */ if (listcount (circuit->area->area_addrs) == 0) return ISIS_WARNING; if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) return ISIS_WARNING; /* LAN Neighbors TLV */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] && listcount (circuit->u.bc.lan_neighs[0]) > 0) if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], circuit->snd_stream)) return ISIS_WARNING; if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] && listcount (circuit->u.bc.lan_neighs[1]) > 0) if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], circuit->snd_stream)) return ISIS_WARNING; } /* Protocols Supported TLV */ if (circuit->nlpids.count > 0) if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream)) return ISIS_WARNING; /* IP interface Address TLV */ if (circuit->ip_router && circuit->ip_addrs && listcount (circuit->ip_addrs) > 0) if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream)) return ISIS_WARNING; #ifdef HAVE_IPV6 /* IPv6 Interface Address TLV */ if (circuit->ipv6_router && circuit->ipv6_link && listcount (circuit->ipv6_link) > 0) if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream)) return ISIS_WARNING; #endif /* HAVE_IPV6 */ if (circuit->pad_hellos) if (tlv_add_padding (circuit->snd_stream)) return ISIS_WARNING; length = stream_get_endp (circuit->snd_stream); /* Update PDU length */ stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length); /* For HMAC MD5 we need to compute the md5 hash and store it */ if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (unsigned char *) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); } if (isis->debugs & DEBUG_ADJ_PACKETS) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { zlog_debug ("ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, length); } else { zlog_debug ("ISIS-Adj (%s): Sending P2P IIH on %s, length %zd", circuit->area->area_tag, circuit->interface->name, length); } if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream)); } retval = circuit->tx (circuit, level); if (retval != ISIS_OK) zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed", circuit->area->area_tag, level, circuit->interface->name); return retval; } int send_lan_l1_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; circuit = THREAD_ARG (thread); assert (circuit); circuit->u.bc.t_send_lan_hello[0] = NULL; if (!(circuit->area->is_type & IS_LEVEL_1)) { zlog_warn ("ISIS-Hello (%s): Trying to send L1 IIH in L2-only area", circuit->area->area_tag); return 1; } if (circuit->u.bc.run_dr_elect[0]) retval = isis_dr_elect (circuit, 1); retval = send_hello (circuit, 1); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, isis_jitter (circuit->hello_interval[0], IIH_JITTER)); return retval; } int send_lan_l2_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; circuit = THREAD_ARG (thread); assert (circuit); circuit->u.bc.t_send_lan_hello[1] = NULL; if (!(circuit->area->is_type & IS_LEVEL_2)) { zlog_warn ("ISIS-Hello (%s): Trying to send L2 IIH in L1 area", circuit->area->area_tag); return 1; } if (circuit->u.bc.run_dr_elect[1]) retval = isis_dr_elect (circuit, 2); retval = send_hello (circuit, 2); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], send_lan_l2_hello, circuit, isis_jitter (circuit->hello_interval[1], IIH_JITTER)); return retval; } int send_p2p_hello (struct thread *thread) { struct isis_circuit *circuit; circuit = THREAD_ARG (thread); assert (circuit); circuit->u.p2p.t_send_p2p_hello = NULL; send_hello (circuit, 1); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.p2p.t_send_p2p_hello, send_p2p_hello, circuit, isis_jitter (circuit->hello_interval[1], IIH_JITTER)); return ISIS_OK; } static int build_csnp (int level, u_char * start, u_char * stop, struct list *lsps, struct isis_circuit *circuit) { struct isis_fixed_hdr fixed_hdr; struct isis_passwd *passwd; unsigned long lenp; u_int16_t length; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; unsigned long auth_tlv_offset = 0; int retval = ISIS_OK; isis_circuit_stream(circuit, &circuit->snd_stream); if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM, circuit->snd_stream); /* * Fill Level 1 or 2 Complete Sequence Numbers header */ lenp = stream_get_endp (circuit->snd_stream); stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */ /* no need to send the source here, it is always us if we csnp */ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); /* with zero circuit id - ref 9.10, 9.11 */ stream_putc (circuit->snd_stream, 0x00); stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2); stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2); /* * And TLVs */ if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { switch (passwd->type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len, passwd->passwd, circuit->snd_stream)) return ISIS_WARNING; break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later overwrite the MD5 hash */ auth_tlv_offset = stream_get_endp (circuit->snd_stream); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, circuit->snd_stream)) return ISIS_WARNING; break; default: break; } } retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); if (retval != ISIS_OK) return retval; length = (u_int16_t) stream_get_endp (circuit->snd_stream); /* Update PU length */ stream_putw_at (circuit->snd_stream, lenp, length); /* For HMAC MD5 we need to compute the md5 hash and store it */ if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) { hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp(circuit->snd_stream), (unsigned char *) &passwd->passwd, passwd->len, (unsigned char *) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); } return retval; } /* * Count the maximum number of lsps that can be accomodated by a given size. */ static uint16_t get_max_lsp_count (uint16_t size) { uint16_t tlv_count; uint16_t lsp_count; uint16_t remaining_size; /* First count the full size TLVs */ tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE; lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN); /* The last TLV, if any */ remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE; if (remaining_size - 2 >= LSP_ENTRIES_LEN) lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN; return lsp_count; } /* * Calculate the length of Authentication Info. TLV. */ static uint16_t auth_tlv_length (int level, struct isis_circuit *circuit) { struct isis_passwd *passwd; uint16_t length; if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; /* Also include the length of TLV header */ length = AUTH_INFO_HDRLEN; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { switch (passwd->type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: length += passwd->len; break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: length += ISIS_AUTH_MD5_SIZE; break; default: break; } } return length; } /* * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP. */ static uint16_t max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit) { int snp_hdr_len; int auth_tlv_len; uint16_t lsp_count; snp_hdr_len = ISIS_FIXED_HDR_LEN; if (snp_type == ISIS_SNP_CSNP_FLAG) snp_hdr_len += ISIS_CSNP_HDRLEN; else snp_hdr_len += ISIS_PSNP_HDRLEN; auth_tlv_len = auth_tlv_length (level, circuit); lsp_count = get_max_lsp_count ( stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len); return lsp_count; } /* * FIXME: support multiple CSNPs */ int send_csnp (struct isis_circuit *circuit, int level) { u_char start[ISIS_SYS_ID_LEN + 2]; u_char stop[ISIS_SYS_ID_LEN + 2]; struct list *list = NULL; struct listnode *node; struct isis_lsp *lsp; u_char num_lsps, loop = 1; int i, retval = ISIS_OK; if (circuit->area->lspdb[level - 1] == NULL || dict_count (circuit->area->lspdb[level - 1]) == 0) return retval; memset (start, 0x00, ISIS_SYS_ID_LEN + 2); memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit); while (loop) { list = list_new (); lsp_build_list (start, stop, num_lsps, list, circuit->area->lspdb[level - 1]); /* * Update the stop lsp_id before encoding this CSNP. */ if (listcount (list) < num_lsps) { memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); } else { node = listtail (list); lsp = listgetdata (node); memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2); } retval = build_csnp (level, start, stop, list, circuit); if (retval != ISIS_OK) { zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); list_delete (list); return retval; } if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Sending L%d CSNP on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, stream_get_endp (circuit->snd_stream)); for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) { zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," " cksum 0x%04x, lifetime %us", circuit->area->area_tag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); } if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream)); } retval = circuit->tx (circuit, level); if (retval != ISIS_OK) { zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); list_delete (list); return retval; } /* * Start lsp_id of the next CSNP should be one plus the * stop lsp_id in this current CSNP. */ memcpy (start, stop, ISIS_SYS_ID_LEN + 2); loop = 0; for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) { if (start[i] < (u_char)0xff) { start[i] += 1; loop = 1; break; } } memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); list_delete (list); } return retval; } int send_l1_csnp (struct thread *thread) { struct isis_circuit *circuit; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); circuit->t_send_csnp[0] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0]) { send_csnp (circuit, 1); } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit, isis_jitter (circuit->csnp_interval[0], CSNP_JITTER)); return retval; } int send_l2_csnp (struct thread *thread) { struct isis_circuit *circuit; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); circuit->t_send_csnp[1] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1]) { send_csnp (circuit, 2); } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit, isis_jitter (circuit->csnp_interval[1], CSNP_JITTER)); return retval; } static int build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) { struct isis_fixed_hdr fixed_hdr; unsigned long lenp; u_int16_t length; struct isis_lsp *lsp; struct isis_passwd *passwd; struct listnode *node; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; unsigned long auth_tlv_offset = 0; int retval = ISIS_OK; isis_circuit_stream(circuit, &circuit->snd_stream); if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM, circuit->snd_stream); /* * Fill Level 1 or 2 Partial Sequence Numbers header */ lenp = stream_get_endp (circuit->snd_stream); stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); stream_putc (circuit->snd_stream, circuit->idx); /* * And TLVs */ if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { switch (passwd->type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len, passwd->passwd, circuit->snd_stream)) return ISIS_WARNING; break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later overwrite the MD5 hash */ auth_tlv_offset = stream_get_endp (circuit->snd_stream); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, circuit->snd_stream)) return ISIS_WARNING; break; default: break; } } retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); if (retval != ISIS_OK) return retval; if (isis->debugs & DEBUG_SNP_PACKETS) { for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp)) { zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x," " cksum 0x%04x, lifetime %us", circuit->area->area_tag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); } } length = (u_int16_t) stream_get_endp (circuit->snd_stream); /* Update PDU length */ stream_putw_at (circuit->snd_stream, lenp, length); /* For HMAC MD5 we need to compute the md5 hash and store it */ if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) { hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp(circuit->snd_stream), (unsigned char *) &passwd->passwd, passwd->len, (unsigned char *) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); } return ISIS_OK; } /* * 7.3.15.4 action on expiration of partial SNP interval * level 1 */ static int send_psnp (int level, struct isis_circuit *circuit) { struct isis_lsp *lsp; struct list *list = NULL; struct listnode *node; u_char num_lsps; int retval = ISIS_OK; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[level - 1]) return ISIS_OK; if (circuit->area->lspdb[level - 1] == NULL || dict_count (circuit->area->lspdb[level - 1]) == 0) return ISIS_OK; if (! circuit->snd_stream) return ISIS_ERROR; num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit); while (1) { list = list_new (); lsp_build_list_ssn (circuit, num_lsps, list, circuit->area->lspdb[level - 1]); if (listcount (list) == 0) { list_delete (list); return ISIS_OK; } retval = build_psnp (level, circuit, list); if (retval != ISIS_OK) { zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); list_delete (list); return retval; } if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Sending L%d PSNP on %s, length %zd", circuit->area->area_tag, level, circuit->interface->name, stream_get_endp (circuit->snd_stream)); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream)); } retval = circuit->tx (circuit, level); if (retval != ISIS_OK) { zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); list_delete (list); return retval; } /* * sending succeeded, we can clear SSN flags of this circuit * for the LSPs in list */ for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); list_delete (list); } return retval; } int send_l1_psnp (struct thread *thread) { struct isis_circuit *circuit; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); circuit->t_send_psnp[0] = NULL; send_psnp (1, circuit); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); return retval; } /* * 7.3.15.4 action on expiration of partial SNP interval * level 2 */ int send_l2_psnp (struct thread *thread) { struct isis_circuit *circuit; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); circuit->t_send_psnp[1] = NULL; send_psnp (2, circuit); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); return retval; } /* * ISO 10589 - 7.3.14.3 */ int send_lsp (struct thread *thread) { struct isis_circuit *circuit; struct isis_lsp *lsp; struct listnode *node; int clear_srm = 1; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); if (!circuit->lsp_queue) return ISIS_OK; node = listhead (circuit->lsp_queue); /* * Handle case where there are no LSPs on the queue. This can * happen, for instance, if an adjacency goes down before this * thread gets a chance to run. */ if (!node) return ISIS_OK; /* * Delete LSP from lsp_queue. If it's still in queue, it is assumed * as 'transmit pending', but send_lsp may never be called again. * Retry will happen because SRM flag will not be cleared. */ lsp = listgetdata(node); list_delete_node (circuit->lsp_queue, node); /* Set the last-cleared time if the queue is empty. */ /* TODO: Is is possible that new lsps keep being added to the queue * that the queue is never empty? */ if (list_isempty (circuit->lsp_queue)) circuit->lsp_queue_last_cleared = time (NULL); if (circuit->state != C_STATE_UP || circuit->is_passive == 1) goto out; /* * Do not send if levels do not match */ if (!(lsp->level & circuit->is_type)) goto out; /* * Do not send if we do not have adjacencies in state up on the circuit */ if (circuit->upadjcount[lsp->level - 1] == 0) goto out; /* stream_copy will assert and stop program execution if LSP is larger than * the circuit's MTU. So handle and log this case here. */ if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) { zlog_err("ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x," " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu" " while interface stream size is %zu.", circuit->area->area_tag, lsp->level, rawlspid_print(lsp->lsp_header->lsp_id), ntohl(lsp->lsp_header->seq_num), ntohs(lsp->lsp_header->checksum), ntohs(lsp->lsp_header->rem_lifetime), circuit->interface->name, stream_get_endp(lsp->pdu), stream_get_size(circuit->snd_stream)); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu)); retval = ISIS_ERROR; goto out; } /* copy our lsp to the send buffer */ stream_copy (circuit->snd_stream, lsp->pdu); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x," " lifetime %us on %s", circuit->area->area_tag, lsp->level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime), circuit->interface->name); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream)); } clear_srm = 0; retval = circuit->tx (circuit, lsp->level); if (retval != ISIS_OK) { zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed %s", circuit->area->area_tag, lsp->level, circuit->interface->name, (retval == ISIS_WARNING) ? "temporarily" : "permanently"); } out: if (clear_srm || (retval == ISIS_OK && circuit->circ_type == CIRCUIT_T_BROADCAST) || (retval != ISIS_OK && retval != ISIS_WARNING)) { /* SRM flag will trigger retransmission. We will not retransmit if we * encountered a fatal error. * On success, they should only be cleared if it's a broadcast circuit. * On a P2P circuit, we will wait for the ack from the neighbor to clear * the fag. */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } return retval; } int ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, int level) { unsigned long lenp; int retval; u_int16_t length; struct isis_fixed_hdr fixed_hdr; isis_circuit_stream(circuit, &circuit->snd_stream); // fill_llc_hdr (stream); if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM, circuit->snd_stream); lenp = stream_get_endp (circuit->snd_stream); stream_putw (circuit->snd_stream, 0); /* PDU length */ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); stream_putc (circuit->snd_stream, circuit->idx); stream_putc (circuit->snd_stream, 9); /* code */ stream_putc (circuit->snd_stream, 16); /* len */ stream_putw (circuit->snd_stream, ntohs (hdr->rem_lifetime)); stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2); stream_putl (circuit->snd_stream, ntohl (hdr->seq_num)); stream_putw (circuit->snd_stream, ntohs (hdr->checksum)); length = (u_int16_t) stream_get_endp (circuit->snd_stream); /* Update PDU length */ stream_putw_at (circuit->snd_stream, lenp, length); retval = circuit->tx (circuit, level); if (retval != ISIS_OK) zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); return retval; } quagga-1.2.4/isisd/isis_pdu.h000066400000000000000000000244601325323223500160740ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_pdu.h * PDU processing * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_PDU_H #define _ZEBRA_ISIS_PDU_H #ifdef __SUNPRO_C #pragma pack(1) #endif /* * ISO 9542 - 7.5,7.6 * * ES to IS Fixed Header * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Intradomain Routeing Protocol Discriminator | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Length Indicator | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Version/Protocol ID extension | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved = 0 | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | 0 | 0 | PDU Type | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Holding Time | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Checksum | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct esis_fixed_hdr { u_char idrp; u_char length; u_char version; u_char id_len; u_char pdu_type; u_int16_t holdtime; u_int16_t checksum; } __attribute__ ((packed)); #define ESIS_FIXED_HDR_LEN 9 #define ESH_PDU 2 #define ISH_PDU 4 #define RD_PDU 5 /* * IS to IS Fixed Header * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Intradomain Routeing Protocol Discriminator | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Length Indicator | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Version/Protocol ID extension | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | R | R | R | PDU Type | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Version | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Maximum Area Addresses | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_fixed_hdr { u_char idrp; u_char length; u_char version1; u_char id_len; u_char pdu_type; u_char version2; u_char reserved; u_char max_area_addrs; } __attribute__ ((packed)); #define ISIS_FIXED_HDR_LEN 8 /* * IS-IS PDU types. */ #define L1_LAN_HELLO 15 #define L2_LAN_HELLO 16 /* * L1 and L2 LAN IS to IS Hello PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved | Circuit Type | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Holding Time | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | PDU Length | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | R | Priority | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | LAN ID | id_len + 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_lan_hello_hdr { u_char circuit_t; u_char source_id[ISIS_SYS_ID_LEN]; u_int16_t hold_time; u_int16_t pdu_len; u_char prio; u_char lan_id[ISIS_SYS_ID_LEN + 1]; } __attribute__ ((packed)); #define ISIS_LANHELLO_HDRLEN 19 #define P2P_HELLO 17 /* * Point-to-point IS to IS hello PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved | Circuit Type | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Holding Time + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Local Circuit ID | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_p2p_hello_hdr { u_char circuit_t; u_char source_id[ISIS_SYS_ID_LEN]; u_int16_t hold_time; u_int16_t pdu_len; u_char local_id; } __attribute__ ((packed)); #define ISIS_P2PHELLO_HDRLEN 12 #define L1_LINK_STATE 18 #define L2_LINK_STATE 20 /* * L1 and L2 IS to IS link state PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Remaining Lifetime + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | LSP ID | id_len + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Sequence Number + 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Checksum + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | P | ATT |LSPDBOL| ISTYPE | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_link_state_hdr { u_int16_t pdu_len; u_int16_t rem_lifetime; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; u_int32_t seq_num; u_int16_t checksum; u_int8_t lsp_bits; } __attribute__ ((packed)); #define ISIS_LSP_HDR_LEN 19 /* * Since the length field of LSP Entries TLV is one byte long, and each LSP * entry is LSP_ENTRIES_LEN (16) bytes long, the maximum number of LSP entries * can be accomodated in a TLV is * 255 / 16 = 15. * * Therefore, the maximum length of the LSP Entries TLV is * 16 * 15 + 2 (header) = 242 bytes. */ #define MAX_LSP_ENTRIES_TLV_SIZE 242 #define L1_COMPLETE_SEQ_NUM 24 #define L2_COMPLETE_SEQ_NUM 25 /* * L1 and L2 IS to IS complete sequence numbers PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len + 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Start LSP ID + id_len + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + End LSP ID + id_len + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_complete_seqnum_hdr { u_int16_t pdu_len; u_char source_id[ISIS_SYS_ID_LEN + 1]; u_char start_lsp_id[ISIS_SYS_ID_LEN + 2]; u_char stop_lsp_id[ISIS_SYS_ID_LEN + 2]; }; #define ISIS_CSNP_HDRLEN 25 #define L1_PARTIAL_SEQ_NUM 26 #define L2_PARTIAL_SEQ_NUM 27 /* * L1 and L2 IS to IS partial sequence numbers PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len + 1 * +---------------------------------------------------------------+ */ struct isis_partial_seqnum_hdr { u_int16_t pdu_len; u_char source_id[ISIS_SYS_ID_LEN + 1]; }; #define ISIS_PSNP_HDRLEN 9 #ifdef __SUNPRO_C #pragma pack() #endif /* * Function for receiving IS-IS PDUs */ int isis_receive (struct thread *thread); /* * calling arguments for snp_process () */ #define ISIS_SNP_PSNP_FLAG 0 #define ISIS_SNP_CSNP_FLAG 1 #define ISIS_AUTH_MD5_SIZE 16U /* * Sending functions */ int send_lan_l1_hello (struct thread *thread); int send_lan_l2_hello (struct thread *thread); int send_p2p_hello (struct thread *thread); int send_csnp (struct isis_circuit *circuit, int level); int send_l1_csnp (struct thread *thread); int send_l2_csnp (struct thread *thread); int send_l1_psnp (struct thread *thread); int send_l2_psnp (struct thread *thread); int send_lsp (struct thread *thread); int ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, int level); void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type); int send_hello (struct isis_circuit *circuit, int level); #endif /* _ZEBRA_ISIS_PDU_H */ quagga-1.2.4/isisd/isis_pfpacket.c000066400000000000000000000300711325323223500170670ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_pfpacket.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #if ISIS_METHOD == ISIS_METHOD_PFPACKET #include /* the L2 protocols */ #include #include "log.h" #include "network.h" #include "stream.h" #include "if.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_circuit.h" #include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_constants.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" #include "privs.h" extern struct zebra_privs_t isisd_privs; /* * Table 9 - Architectural constants for use with ISO 8802 subnetworks * ISO 10589 - 8.4.8 */ u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 }; u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 }; u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 }; u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 }; static uint8_t discard_buff[8192]; static uint8_t sock_buff[8192]; /* * if level is 0 we are joining p2p multicast * FIXME: and the p2p multicast being ??? */ static int isis_multicast_join (int fd, int registerto, int if_num) { struct packet_mreq mreq; memset (&mreq, 0, sizeof (mreq)); mreq.mr_ifindex = if_num; if (registerto) { mreq.mr_type = PACKET_MR_MULTICAST; mreq.mr_alen = ETH_ALEN; if (registerto == 1) memcpy (&mreq.mr_address, ALL_L1_ISS, ETH_ALEN); else if (registerto == 2) memcpy (&mreq.mr_address, ALL_L2_ISS, ETH_ALEN); else if (registerto == 3) memcpy (&mreq.mr_address, ALL_ISS, ETH_ALEN); else memcpy (&mreq.mr_address, ALL_ESS, ETH_ALEN); } else { mreq.mr_type = PACKET_MR_ALLMULTI; } #ifdef EXTREME_DEBUG zlog_debug ("isis_multicast_join(): fd=%d, reg_to=%d, if_num=%d, " "address = %02x:%02x:%02x:%02x:%02x:%02x", fd, registerto, if_num, mreq.mr_address[0], mreq.mr_address[1], mreq.mr_address[2], mreq.mr_address[3], mreq.mr_address[4], mreq.mr_address[5]); #endif /* EXTREME_DEBUG */ if (setsockopt (fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof (struct packet_mreq))) { zlog_warn ("isis_multicast_join(): setsockopt(): %s", safe_strerror (errno)); return ISIS_WARNING; } return ISIS_OK; } static int open_packet_socket (struct isis_circuit *circuit) { struct sockaddr_ll s_addr; int fd, retval = ISIS_OK; fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL)); if (fd < 0) { zlog_warn ("open_packet_socket(): socket() failed %s", safe_strerror (errno)); return ISIS_WARNING; } /* * Bind to the physical interface */ memset (&s_addr, 0, sizeof (struct sockaddr_ll)); s_addr.sll_family = AF_PACKET; s_addr.sll_protocol = htons (ETH_P_ALL); s_addr.sll_ifindex = circuit->interface->ifindex; if (bind (fd, (struct sockaddr *) (&s_addr), sizeof (struct sockaddr_ll)) < 0) { zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno)); close (fd); return ISIS_WARNING; } circuit->fd = fd; if (if_is_broadcast (circuit->interface)) { /* * Join to multicast groups * according to * 8.4.2 - Broadcast subnetwork IIH PDUs * FIXME: is there a case only one will fail?? */ /* joining ALL_L1_ISS */ retval |= isis_multicast_join (circuit->fd, 1, circuit->interface->ifindex); /* joining ALL_L2_ISS */ retval |= isis_multicast_join (circuit->fd, 2, circuit->interface->ifindex); /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */ retval |= isis_multicast_join (circuit->fd, 3, circuit->interface->ifindex); } else { retval = isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex); } return retval; } /* * Create the socket and set the tx/rx funcs */ int isis_sock_init (struct isis_circuit *circuit) { int retval = ISIS_OK; if (isisd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno)); retval = open_packet_socket (circuit); if (retval != ISIS_OK) { zlog_warn ("%s: could not initialize the socket", __func__); goto end; } /* Assign Rx and Tx callbacks are based on real if type */ if (if_is_broadcast (circuit->interface)) { circuit->tx = isis_send_pdu_bcast; circuit->rx = isis_recv_pdu_bcast; } else if (if_is_pointopoint (circuit->interface)) { circuit->tx = isis_send_pdu_p2p; circuit->rx = isis_recv_pdu_p2p; } else { zlog_warn ("isis_sock_init(): unknown circuit type"); retval = ISIS_WARNING; goto end; } end: if (isisd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno)); return retval; } static inline int llc_check (u_char * llc) { if (*llc != ISO_SAP || *(llc + 1) != ISO_SAP || *(llc + 2) != 3) return 0; return 1; } int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) { int bytesread, addr_len; struct sockaddr_ll s_addr; u_char llc[LLC_LEN]; addr_len = sizeof (s_addr); memset (&s_addr, 0, sizeof (struct sockaddr_ll)); bytesread = recvfrom (circuit->fd, (void *) &llc, LLC_LEN, MSG_PEEK, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if ((bytesread < 0) || (s_addr.sll_ifindex != (int)circuit->interface->ifindex)) { if (bytesread < 0) { zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, " "bytesread %d, recvfrom(): %s", circuit->interface->name, circuit->fd, bytesread, safe_strerror (errno)); } if (s_addr.sll_ifindex != (int)circuit->interface->ifindex) { zlog_warn("packet is received on multiple interfaces: " "socket interface %d, circuit interface %d, " "packet type %u", s_addr.sll_ifindex, circuit->interface->ifindex, s_addr.sll_pkttype); } /* get rid of the packet */ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); return ISIS_WARNING; } /* * Filtering by llc field, discard packets sent by this host (other circuit) */ if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING) { /* Read the packet into discard buff */ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (bytesread < 0) zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed"); return ISIS_WARNING; } /* on lan we have to read to the static buff first */ bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (bytesread < 0) { zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed"); return ISIS_WARNING; } /* then we lose the LLC */ stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN); memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen); return ISIS_OK; } int isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa) { int bytesread, addr_len; struct sockaddr_ll s_addr; memset (&s_addr, 0, sizeof (struct sockaddr_ll)); addr_len = sizeof (s_addr); /* we can read directly to the stream */ bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd, circuit->interface->mtu, 0, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (s_addr.sll_pkttype == PACKET_OUTGOING) { /* Read the packet into discard buff */ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (bytesread < 0) zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed"); return ISIS_WARNING; } /* If we don't have protocol type 0x00FE which is * ISO over GRE we exit with pain :) */ if (ntohs (s_addr.sll_protocol) != 0x00FE) { zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X", ntohs (s_addr.sll_protocol)); return ISIS_WARNING; } memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen); return ISIS_OK; } int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { struct msghdr msg; struct iovec iov[2]; /* we need to do the LLC in here because of P2P circuits, which will * not need it */ struct sockaddr_ll sa; stream_set_getp (circuit->snd_stream, 0); memset (&sa, 0, sizeof (struct sockaddr_ll)); sa.sll_family = AF_PACKET; sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); sa.sll_ifindex = circuit->interface->ifindex; sa.sll_halen = ETH_ALEN; /* RFC5309 section 4.1 recommends ALL_ISS */ if (circuit->circ_type == CIRCUIT_T_P2P) memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN); else if (level == 1) memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN); else memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN); /* on a broadcast circuit */ /* first we put the LLC in */ sock_buff[0] = 0xFE; sock_buff[1] = 0xFE; sock_buff[2] = 0x03; memset (&msg, 0, sizeof (msg)); msg.msg_name = &sa; msg.msg_namelen = sizeof (struct sockaddr_ll); msg.msg_iov = iov; msg.msg_iovlen = 2; iov[0].iov_base = sock_buff; iov[0].iov_len = LLC_LEN; iov[1].iov_base = circuit->snd_stream->data; iov[1].iov_len = stream_get_endp (circuit->snd_stream); if (sendmsg(circuit->fd, &msg, 0) < 0) { zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s", circuit->interface->name, safe_strerror(errno)); if (ERRNO_IO_RETRY(errno)) return ISIS_WARNING; return ISIS_ERROR; } return ISIS_OK; } int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { struct sockaddr_ll sa; ssize_t rv; stream_set_getp (circuit->snd_stream, 0); memset (&sa, 0, sizeof (struct sockaddr_ll)); sa.sll_family = AF_PACKET; sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); sa.sll_ifindex = circuit->interface->ifindex; sa.sll_halen = ETH_ALEN; if (level == 1) memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN); else memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN); /* lets try correcting the protocol */ sa.sll_protocol = htons (0x00FE); rv = sendto(circuit->fd, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream), 0, (struct sockaddr *) &sa, sizeof (struct sockaddr_ll)); if (rv < 0) { zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s", circuit->interface->name, safe_strerror(errno)); if (ERRNO_IO_RETRY(errno)) return ISIS_WARNING; return ISIS_ERROR; } return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_PFPACKET */ quagga-1.2.4/isisd/isis_redist.c000066400000000000000000000516221325323223500165710ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_redist.c * * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "if.h" #include "linklist.h" #include "memory.h" #include "memtypes.h" #include "prefix.h" #include "routemap.h" #include "stream.h" #include "table.h" #include "vty.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_misc.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_lsp.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" static int redist_protocol(int family) { if (family == AF_INET) return 0; if (family == AF_INET6) return 1; assert(!"Unsupported address family!"); return 0; } static int is_default(struct prefix *p) { if (p->family == AF_INET) if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0) return 1; if (p->family == AF_INET6) if (IN6_IS_ADDR_UNSPECIFIED(&p->u.prefix6) && p->prefixlen == 0) return 1; return 0; } static struct route_table* get_ext_info(struct isis *i, int family) { int protocol = redist_protocol(family); return i->ext_info[protocol]; } static struct isis_redist* get_redist_settings(struct isis_area *area, int family, int type, int level) { int protocol = redist_protocol(family); return &area->redist_settings[protocol][type][level-1]; } struct route_table* get_ext_reach(struct isis_area *area, int family, int level) { int protocol = redist_protocol(family); return area->ext_reach[protocol][level-1]; } static struct route_node * isis_redist_route_node_create(route_table_delegate_t *delegate, struct route_table *table) { struct route_node *node; node = XCALLOC(MTYPE_ROUTE_NODE, sizeof(*node)); return node; } static void isis_redist_route_node_destroy(route_table_delegate_t *delegate, struct route_table *table, struct route_node *node) { if (node->info) XFREE(MTYPE_ISIS, node->info); XFREE (MTYPE_ROUTE_NODE, node); } static route_table_delegate_t isis_redist_rt_delegate = { .create_node = isis_redist_route_node_create, .destroy_node = isis_redist_route_node_destroy }; /* Install external reachability information into a * specific area for a specific level. * Schedule an lsp regenerate if necessary */ static void isis_redist_install(struct isis_area *area, int level, struct prefix *p, struct isis_ext_info *info) { int family = p->family; struct route_table *er_table = get_ext_reach(area, family, level); struct route_node *er_node; if (!er_table) { zlog_warn("%s: External reachability table of area %s" " is not initialized.", __func__, area->area_tag); return; } er_node = route_node_get(er_table, p); if (er_node->info) { route_unlock_node(er_node); /* Don't update/reschedule lsp generation if nothing changed. */ if (!memcmp(er_node->info, info, sizeof(*info))) return; } else { er_node->info = XMALLOC(MTYPE_ISIS, sizeof(*info)); } memcpy(er_node->info, info, sizeof(*info)); lsp_regenerate_schedule(area, level, 0); } /* Remove external reachability information from a * specific area for a specific level. * Schedule an lsp regenerate if necessary. */ static void isis_redist_uninstall(struct isis_area *area, int level, struct prefix *p) { int family = p->family; struct route_table *er_table = get_ext_reach(area, family, level); struct route_node *er_node; if (!er_table) { zlog_warn("%s: External reachability table of area %s" " is not initialized.", __func__, area->area_tag); return; } er_node = route_node_lookup(er_table, p); if (!er_node) return; else route_unlock_node(er_node); if (!er_node->info) return; XFREE(MTYPE_ISIS, er_node->info); route_unlock_node(er_node); lsp_regenerate_schedule(area, level, 0); } /* Update external reachability info of area for a given level * and prefix, using the given redistribution settings. */ static void isis_redist_update_ext_reach(struct isis_area *area, int level, struct isis_redist *redist, struct prefix *p, struct isis_ext_info *info) { struct isis_ext_info area_info; route_map_result_t map_ret; memcpy(&area_info, info, sizeof(area_info)); if (redist->metric != 0xffffffff) area_info.metric = redist->metric; if (redist->map_name) { map_ret = route_map_apply(redist->map, p, RMAP_ISIS, &area_info); if (map_ret == RMAP_DENYMATCH) area_info.distance = 255; } /* Allow synthesized default routes only on always orignate */ if (area_info.origin == DEFAULT_ROUTE && redist->redist != DEFAULT_ORIGINATE_ALWAYS) area_info.distance = 255; if (area_info.distance < 255) isis_redist_install(area, level, p, &area_info); else isis_redist_uninstall(area, level, p); } static void isis_redist_ensure_default(struct isis *isis, int family) { struct prefix p; struct route_table *ei_table = get_ext_info(isis, family); struct route_node *ei_node; struct isis_ext_info *info; if (family == AF_INET) { p.family = AF_INET; p.prefixlen = 0; memset(&p.u.prefix4, 0, sizeof(p.u.prefix4)); } else if (family == AF_INET6) { p.family = AF_INET6; p.prefixlen = 0; memset(&p.u.prefix6, 0, sizeof(p.u.prefix6)); } else assert(!"Unknown family!"); ei_node = route_node_get(ei_table, &p); if (ei_node->info) { route_unlock_node(ei_node); return; } ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info)); info = ei_node->info; info->origin = DEFAULT_ROUTE; info->distance = 254; info->metric = MAX_WIDE_PATH_METRIC; } /* Handle notification about route being added */ void isis_redist_add(int type, struct prefix *p, u_char distance, uint32_t metric) { int family = p->family; struct route_table *ei_table = get_ext_info(isis, family); struct route_node *ei_node; struct isis_ext_info *info; struct listnode *node; struct isis_area *area; int level; struct isis_redist *redist; char debug_buf[BUFSIZ]; prefix2str(p, debug_buf, sizeof(debug_buf)); zlog_debug("%s: New route %s from %s.", __func__, debug_buf, zebra_route_string(type)); if (!ei_table) { zlog_warn("%s: External information table not initialized.", __func__); return; } ei_node = route_node_get(ei_table, p); if (ei_node->info) route_unlock_node(ei_node); else ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info)); info = ei_node->info; info->origin = type; info->distance = distance; info->metric = metric; if (is_default(p)) type = DEFAULT_ROUTE; for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) for (level = 1; level <= ISIS_LEVELS; level++) { redist = get_redist_settings(area, family, type, level); if (!redist->redist) continue; isis_redist_update_ext_reach(area, level, redist, p, info); } } void isis_redist_delete(int type, struct prefix *p) { int family = p->family; struct route_table *ei_table = get_ext_info(isis, family); struct route_node *ei_node; struct listnode *node; struct isis_area *area; int level; struct isis_redist *redist; char debug_buf[BUFSIZ]; prefix2str(p, debug_buf, sizeof(debug_buf)); zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf, zebra_route_string(type)); if (is_default(p)) { /* Don't remove default route but add synthetic route for use * by "default-information originate always". Areas without the * "always" setting will ignore routes with origin DEFAULT_ROUTE. */ isis_redist_add(DEFAULT_ROUTE, p, 254, MAX_WIDE_PATH_METRIC); return; } if (!ei_table) { zlog_warn("%s: External information table not initialized.", __func__); return; } ei_node = route_node_lookup(ei_table, p); if (!ei_node || !ei_node->info) { char buf[BUFSIZ]; prefix2str(p, buf, sizeof(buf)); zlog_warn("%s: Got a delete for %s route %s, but that route" " was never added.", __func__, zebra_route_string(type), buf); if (ei_node) route_unlock_node(ei_node); return; } route_unlock_node(ei_node); for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) for (level = 1; level < ISIS_LEVELS; level++) { redist = get_redist_settings(area, family, type, level); if (!redist->redist) continue; isis_redist_uninstall(area, level, p); } XFREE(MTYPE_ISIS, ei_node->info); route_unlock_node(ei_node); } static void isis_redist_routemap_set(struct isis_redist *redist, const char *routemap) { if (redist->map_name) { XFREE(MTYPE_ISIS, redist->map_name); redist->map = NULL; } if (routemap && strlen(routemap)) { redist->map_name = XSTRDUP(MTYPE_ISIS, routemap); redist->map = route_map_lookup_by_name(routemap); } } static void isis_redist_update_zebra_subscriptions(struct isis *isis) { struct listnode *node; struct isis_area *area; int type; int level; int protocol; char do_subscribe[ZEBRA_ROUTE_MAX + 1]; memset(do_subscribe, 0, sizeof(do_subscribe)); for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) for (level = 0; level < ISIS_LEVELS; level++) if (area->redist_settings[protocol][type][level].redist) do_subscribe[type] = 1; for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) { /* This field is actually controlling transmission of the IS-IS * routes to Zebra and has nothing to do with redistribution, * so skip it. */ if (type == ZEBRA_ROUTE_ISIS) continue; if (do_subscribe[type]) isis_zebra_redistribute_set(type); else isis_zebra_redistribute_unset(type); } } static void isis_redist_set(struct isis_area *area, int level, int family, int type, uint32_t metric, const char *routemap, int originate_type) { int protocol = redist_protocol(family); struct isis_redist *redist = get_redist_settings(area, family, type, level); int i; struct route_table *ei_table; struct route_node *rn; struct isis_ext_info *info; redist->redist = (type == DEFAULT_ROUTE) ? originate_type : 1; redist->metric = metric; isis_redist_routemap_set(redist, routemap); if (!area->ext_reach[protocol][level-1]) { area->ext_reach[protocol][level-1] = route_table_init_with_delegate(&isis_redist_rt_delegate); } for (i = 0; i < REDIST_PROTOCOL_COUNT; i++) if (!area->isis->ext_info[i]) { area->isis->ext_info[i] = route_table_init_with_delegate(&isis_redist_rt_delegate); } isis_redist_update_zebra_subscriptions(area->isis); if (type == DEFAULT_ROUTE && originate_type == DEFAULT_ORIGINATE_ALWAYS) isis_redist_ensure_default(area->isis, family); ei_table = get_ext_info(area->isis, family); for (rn = route_top(ei_table); rn; rn = route_next(rn)) { if (!rn->info) continue; info = rn->info; if (type == DEFAULT_ROUTE) { if (!is_default(&rn->p)) continue; } else { if (info->origin != type) continue; } isis_redist_update_ext_reach(area, level, redist, &rn->p, info); } } static void isis_redist_unset(struct isis_area *area, int level, int family, int type) { struct isis_redist *redist = get_redist_settings(area, family, type, level); struct route_table *er_table = get_ext_reach(area, family, level); struct route_node *rn; struct isis_ext_info *info; if (!redist->redist) return; redist->redist = 0; if (!er_table) { zlog_warn("%s: External reachability table uninitialized.", __func__); return; } for (rn = route_top(er_table); rn; rn = route_next(rn)) { if (!rn->info) continue; info = rn->info; if (type == DEFAULT_ROUTE) { if (!is_default(&rn->p)) continue; } else { if (info->origin != type) continue; } XFREE(MTYPE_ISIS, rn->info); route_unlock_node(rn); } lsp_regenerate_schedule(area, level, 0); isis_redist_update_zebra_subscriptions(area->isis); } void isis_redist_area_finish(struct isis_area *area) { int protocol; int level; int type; for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++) for (level = 0; level < ISIS_LEVELS; level++) { for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) { struct isis_redist *redist; redist = &area->redist_settings[protocol][type][level]; redist->redist = 0; if (redist->map_name) XFREE(MTYPE_ISIS, redist->map_name); } route_table_finish(area->ext_reach[protocol][level]); } isis_redist_update_zebra_subscriptions(area->isis); } DEFUN(isis_redistribute, isis_redistribute_cmd, "redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD " (level-1|level-2) {metric <0-16777215>|route-map WORD}", REDIST_STR "Redistribute IPv4 routes\n" "Redistribute IPv6 routes\n" QUAGGA_REDIST_HELP_STR_ISISD "Redistribute into level-1\n" "Redistribute into level-2\n" "Metric for redistributed routes\n" "ISIS default metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct isis_area *area = vty->index; int family; int afi; int type; int level; unsigned long metric; const char *routemap; if (argc < 5) return CMD_WARNING; family = str2family(argv[0]); if (family < 0) return CMD_WARNING; afi = family2afi(family); if (!afi) return CMD_WARNING; type = proto_redistnum(afi, argv[1]); if (type < 0 || type == ZEBRA_ROUTE_ISIS) return CMD_WARNING; if (!strcmp("level-1", argv[2])) level = 1; else if (!strcmp("level-2", argv[2])) level = 2; else return CMD_WARNING; if ((area->is_type & level) != level) { vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE); return CMD_WARNING; } if (argv[3]) { char *endp; metric = strtoul(argv[3], &endp, 10); if (argv[3][0] == '\0' || *endp != '\0') return CMD_WARNING; } else { metric = 0xffffffff; } routemap = argv[4]; isis_redist_set(area, level, family, type, metric, routemap, 0); return 0; } DEFUN(no_isis_redistribute, no_isis_redistribute_cmd, "no redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD " (level-1|level-2)", NO_STR REDIST_STR "Redistribute IPv4 routes\n" "Redistribute IPv6 routes\n" QUAGGA_REDIST_HELP_STR_ISISD "Redistribute into level-1\n" "Redistribute into level-2\n") { struct isis_area *area = vty->index; int type; int level; int family; int afi; if (argc < 3) return CMD_WARNING; family = str2family(argv[0]); if (family < 0) return CMD_WARNING; afi = family2afi(family); if (!afi) return CMD_WARNING; type = proto_redistnum(afi, argv[1]); if (type < 0 || type == ZEBRA_ROUTE_ISIS) return CMD_WARNING; if (!strcmp("level-1", argv[2])) level = 1; else if (!strcmp("level-2", argv[2])) level = 2; else return CMD_WARNING; isis_redist_unset(area, level, family, type); return 0; } DEFUN(isis_default_originate, isis_default_originate_cmd, "default-information originate (ipv4|ipv6) (level-1|level-2) " "{always|metric <0-16777215>|route-map WORD}", "Control distribution of default information\n" "Distribute a default route\n" "Distribute default route for IPv4\n" "Distribute default route for IPv6\n" "Distribute default route into level-1\n" "Distribute default route into level-2\n" "Always advertise default route\n" "Metric for default route\n" "ISIS default metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct isis_area *area = vty->index; int family; int originate_type; int level; unsigned long metric; const char *routemap; if (argc < 5) return CMD_WARNING; family = str2family(argv[0]); if (family < 0) return CMD_WARNING; if (!strcmp("level-1", argv[1])) level = 1; else if (!strcmp("level-2", argv[1])) level = 2; else return CMD_WARNING; if ((area->is_type & level) != level) { vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE); return CMD_WARNING; } if (argv[2] && *argv[2] != '\0') originate_type = DEFAULT_ORIGINATE_ALWAYS; else originate_type = DEFAULT_ORIGINATE; if (family == AF_INET6 && originate_type != DEFAULT_ORIGINATE_ALWAYS) { vty_out(vty, "Zebra doesn't implement default-originate for IPv6 yet%s", VTY_NEWLINE); vty_out(vty, "so use with care or use default-originate always.%s", VTY_NEWLINE); } if (argv[3]) { char *endp; metric = strtoul(argv[3], &endp, 10); if (argv[3][0] == '\0' || *endp != '\0') return CMD_WARNING; } else { metric = 0xffffffff; } routemap = argv[4]; isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, originate_type); return 0; } DEFUN(no_isis_default_originate, no_isis_default_originate_cmd, "no default-information originate (ipv4|ipv6) (level-1|level-2)", NO_STR "Control distribution of default information\n" "Distribute a default route\n" "Distribute default route for IPv4\n" "Distribute default route for IPv6\n" "Distribute default route into level-1\n" "Distribute default route into level-2\n") { struct isis_area *area = vty->index; int family; int level; if (argc < 2) return CMD_WARNING; family = str2family(argv[0]); if (family < 0) return CMD_WARNING; if (!strcmp("level-1", argv[1])) level = 1; else if (!strcmp("level-2", argv[1])) level = 2; else return CMD_WARNING; isis_redist_unset(area, level, family, DEFAULT_ROUTE); return 0; } int isis_redist_config_write(struct vty *vty, struct isis_area *area, int family) { int type; int level; int write = 0; struct isis_redist *redist; const char *family_str; if (family == AF_INET) family_str = "ipv4"; else if (family == AF_INET6) family_str = "ipv6"; else return 0; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { if (type == ZEBRA_ROUTE_ISIS) continue; for (level = 1; level <= ISIS_LEVELS; level++) { redist = get_redist_settings(area, family, type, level); if (!redist->redist) continue; vty_out(vty, " redistribute %s %s level-%d", family_str, zebra_route_string(type), level); if (redist->metric != 0xffffffff) vty_out(vty, " metric %u", redist->metric); if (redist->map_name) vty_out(vty, " route-map %s", redist->map_name); vty_out(vty, "%s", VTY_NEWLINE); write++; } } for (level = 1; level <= ISIS_LEVELS; level++) { redist = get_redist_settings(area, family, DEFAULT_ROUTE, level); if (!redist->redist) continue; vty_out(vty, " default-information originate %s level-%d", family_str, level); if (redist->redist == DEFAULT_ORIGINATE_ALWAYS) vty_out(vty, " always"); if (redist->metric != 0xffffffff) vty_out(vty, " metric %u", redist->metric); if (redist->map_name) vty_out(vty, " route-map %s", redist->map_name); vty_out(vty, "%s", VTY_NEWLINE); write++; } return write; } void isis_redist_init(void) { install_element(ISIS_NODE, &isis_redistribute_cmd); install_element(ISIS_NODE, &no_isis_redistribute_cmd); install_element(ISIS_NODE, &isis_default_originate_cmd); install_element(ISIS_NODE, &no_isis_default_originate_cmd); } quagga-1.2.4/isisd/isis_redist.h000066400000000000000000000033101325323223500165650ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_redist.h * * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ISIS_REDIST_H #define ISIS_REDIST_H #define REDIST_PROTOCOL_COUNT 2 #define DEFAULT_ROUTE ZEBRA_ROUTE_MAX #define DEFAULT_ORIGINATE 1 #define DEFAULT_ORIGINATE_ALWAYS 2 struct isis_ext_info { int origin; uint32_t metric; u_char distance; }; struct isis_redist { int redist; uint32_t metric; char *map_name; struct route_map *map; }; struct isis_area; struct prefix; struct vty; struct route_table *get_ext_reach(struct isis_area *area, int family, int level); void isis_redist_add(int type, struct prefix *p, u_char distance, uint32_t metric); void isis_redist_delete(int type, struct prefix *p); int isis_redist_config_write(struct vty *vty, struct isis_area *area, int family); void isis_redist_init(void); void isis_redist_area_finish(struct isis_area *area); #endif quagga-1.2.4/isisd/isis_route.c000066400000000000000000000432311325323223500164320ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_route.c * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * based on ../ospf6d/ospf6_route.[ch] * by Yasuhiro Ohara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "thread.h" #include "linklist.h" #include "vty.h" #include "log.h" #include "memory.h" #include "prefix.h" #include "hash.h" #include "if.h" #include "table.h" #include "isis_constants.h" #include "isis_common.h" #include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" #include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_spf.h" #include "isis_route.h" #include "isis_zebra.h" static struct isis_nexthop * isis_nexthop_create (struct in_addr *ip, ifindex_t ifindex) { struct listnode *node; struct isis_nexthop *nexthop; for (ALL_LIST_ELEMENTS_RO (isis->nexthops, node, nexthop)) { if (nexthop->ifindex != ifindex) continue; if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0) continue; nexthop->lock++; return nexthop; } nexthop = XCALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop)); nexthop->ifindex = ifindex; memcpy (&nexthop->ip, ip, sizeof (struct in_addr)); listnode_add (isis->nexthops, nexthop); nexthop->lock++; return nexthop; } static void isis_nexthop_delete (struct isis_nexthop *nexthop) { nexthop->lock--; if (nexthop->lock == 0) { listnode_delete (isis->nexthops, nexthop); XFREE (MTYPE_ISIS_NEXTHOP, nexthop); } return; } static int nexthoplookup (struct list *nexthops, struct in_addr *ip, ifindex_t ifindex) { struct listnode *node; struct isis_nexthop *nh; for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh)) { if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) && ifindex == nh->ifindex) return 1; } return 0; } #ifdef EXTREME_DEBUG static void nexthop_print (struct isis_nexthop *nh) { u_char buf[BUFSIZ]; inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ); zlog_debug (" %s %u", buf, nh->ifindex); } static void nexthops_print (struct list *nhs) { struct listnode *node; struct isis_nexthop *nh; for (ALL_LIST_ELEMENTS_RO (nhs, node, nh)) nexthop_print (nh); } #endif /* EXTREME_DEBUG */ #ifdef HAVE_IPV6 static struct isis_nexthop6 * isis_nexthop6_new (struct in6_addr *ip6, ifindex_t ifindex) { struct isis_nexthop6 *nexthop6; nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6)); nexthop6->ifindex = ifindex; memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr)); nexthop6->lock++; return nexthop6; } static struct isis_nexthop6 * isis_nexthop6_create (struct in6_addr *ip6, ifindex_t ifindex) { struct listnode *node; struct isis_nexthop6 *nexthop6; for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6)) { if (nexthop6->ifindex != ifindex) continue; if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0) continue; nexthop6->lock++; return nexthop6; } nexthop6 = isis_nexthop6_new (ip6, ifindex); return nexthop6; } static void isis_nexthop6_delete (struct isis_nexthop6 *nexthop6) { nexthop6->lock--; if (nexthop6->lock == 0) { listnode_delete (isis->nexthops6, nexthop6); XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6); } return; } static int nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6, ifindex_t ifindex) { struct listnode *node; struct isis_nexthop6 *nh6; for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6)) { if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) && ifindex == nh6->ifindex) return 1; } return 0; } #ifdef EXTREME_DEBUG static void nexthop6_print (struct isis_nexthop6 *nh6) { u_char buf[BUFSIZ]; inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ); zlog_debug (" %s %u", buf, nh6->ifindex); } static void nexthops6_print (struct list *nhs6) { struct listnode *node; struct isis_nexthop6 *nh6; for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6)) nexthop6_print (nh6); } #endif /* EXTREME_DEBUG */ #endif /* HAVE_IPV6 */ static void adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj) { struct isis_nexthop *nh; struct listnode *node; struct in_addr *ipv4_addr; if (adj->ipv4_addrs == NULL) return; for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr)) { if (!nexthoplookup (nexthops, ipv4_addr, adj->circuit->interface->ifindex)) { nh = isis_nexthop_create (ipv4_addr, adj->circuit->interface->ifindex); nh->router_address = adj->router_address; listnode_add (nexthops, nh); } } } #ifdef HAVE_IPV6 static void adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj) { struct listnode *node; struct in6_addr *ipv6_addr; struct isis_nexthop6 *nh6; if (!adj->ipv6_addrs) return; for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr)) { if (!nexthop6lookup (nexthops6, ipv6_addr, adj->circuit->interface->ifindex)) { nh6 = isis_nexthop6_create (ipv6_addr, adj->circuit->interface->ifindex); nh6->router_address6 = adj->router_address6; listnode_add (nexthops6, nh6); } } } #endif /* HAVE_IPV6 */ static struct isis_route_info * isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth, struct list *adjacencies) { struct isis_route_info *rinfo; struct isis_adjacency *adj; struct listnode *node; rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info)); if (prefix->family == AF_INET) { rinfo->nexthops = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) { /* check for force resync this route */ if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); /* update neighbor router address */ if (depth == 2 && prefix->prefixlen == 32) adj->router_address = prefix->u.prefix4; adjinfo2nexthop (rinfo->nexthops, adj); } } #ifdef HAVE_IPV6 if (prefix->family == AF_INET6) { rinfo->nexthops6 = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) { /* check for force resync this route */ if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); /* update neighbor router address */ if (depth == 2 && prefix->prefixlen == 128) adj->router_address6 = prefix->u.prefix6; adjinfo2nexthop6 (rinfo->nexthops6, adj); } } #endif /* HAVE_IPV6 */ rinfo->cost = cost; rinfo->depth = depth; return rinfo; } static void isis_route_info_delete (struct isis_route_info *route_info) { if (route_info->nexthops) { route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete; list_delete (route_info->nexthops); } #ifdef HAVE_IPV6 if (route_info->nexthops6) { route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete; list_delete (route_info->nexthops6); } #endif /* HAVE_IPV6 */ XFREE (MTYPE_ISIS_ROUTE_INFO, route_info); } static int isis_route_info_same_attrib (struct isis_route_info *new, struct isis_route_info *old) { if (new->cost != old->cost) return 0; if (new->depth != old->depth) return 0; return 1; } static int isis_route_info_same (struct isis_route_info *new, struct isis_route_info *old, u_char family) { struct listnode *node; struct isis_nexthop *nexthop; #ifdef HAVE_IPV6 struct isis_nexthop6 *nexthop6; #endif /* HAVE_IPV6 */ if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return 0; if (CHECK_FLAG (new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) return 0; if (!isis_route_info_same_attrib (new, old)) return 0; if (family == AF_INET) { for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop)) if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) == 0) return 0; for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop)) if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) == 0) return 0; } #ifdef HAVE_IPV6 else if (family == AF_INET6) { for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6)) if (nexthop6lookup (old->nexthops6, &nexthop6->ip6, nexthop6->ifindex) == 0) return 0; for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6)) if (nexthop6lookup (new->nexthops6, &nexthop6->ip6, nexthop6->ifindex) == 0) return 0; } #endif /* HAVE_IPV6 */ return 1; } struct isis_route_info * isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, struct list *adjacencies, struct isis_area *area, int level) { struct route_node *route_node; struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL; u_char buff[BUFSIZ]; u_char family; family = prefix->family; /* for debugs */ prefix2str (prefix, (char *) buff, BUFSIZ); rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies); if (family == AF_INET) route_node = route_node_get (area->route_table[level - 1], prefix); #ifdef HAVE_IPV6 else if (family == AF_INET6) route_node = route_node_get (area->route_table6[level - 1], prefix); #endif /* HAVE_IPV6 */ else { isis_route_info_delete (rinfo_new); return NULL; } rinfo_old = route_node->info; if (!rinfo_old) { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff); route_info = rinfo_new; UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } else { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag, buff); if (isis_route_info_same (rinfo_new, rinfo_old, family)) { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff); isis_route_info_delete (rinfo_new); route_info = rinfo_old; } else { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag, buff); isis_route_info_delete (rinfo_old); route_info = rinfo_new; UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } } SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE); route_node->info = route_info; return route_info; } static void isis_route_delete (struct prefix *prefix, struct route_table *table) { struct route_node *rode; struct isis_route_info *rinfo; char buff[BUFSIZ]; /* for log */ prefix2str (prefix, buff, BUFSIZ); rode = route_node_get (table, prefix); rinfo = rode->info; if (rinfo == NULL) { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff); return; } if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) { UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte: route delete %s", buff); isis_zebra_route_update (prefix, rinfo); } isis_route_info_delete (rinfo); rode->info = NULL; return; } /* Validating routes in particular table. */ static void isis_route_validate_table (struct isis_area *area, struct route_table *table) { struct route_node *rnode, *drnode; struct isis_route_info *rinfo; u_char buff[BUFSIZ]; for (rnode = route_top (table); rnode; rnode = route_next (rnode)) { if (rnode->info == NULL) continue; rinfo = rnode->info; if (isis->debugs & DEBUG_RTE_EVENTS) { prefix2str (&rnode->p, (char *) buff, BUFSIZ); zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s %s", area->area_tag, (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED) ? "synced" : "not-synced"), (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC) ? "resync" : "not-resync"), (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ? "active" : "inactive"), buff); } isis_zebra_route_update (&rnode->p, rinfo); if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) { /* Area is either L1 or L2 => we use level route tables directly for * validating => no problems with deleting routes. */ if (area->is_type != IS_LEVEL_1_AND_2) { isis_route_delete (&rnode->p, table); continue; } /* If area is L1L2, we work with merge table and therefore must * delete node from level tables as well before deleting route info. * FIXME: Is it performance problem? There has to be the better way. * Like not to deal with it here at all (see the next comment)? */ if (rnode->p.family == AF_INET) { drnode = route_node_get (area->route_table[0], &rnode->p); if (drnode->info == rnode->info) drnode->info = NULL; drnode = route_node_get (area->route_table[1], &rnode->p); if (drnode->info == rnode->info) drnode->info = NULL; } #ifdef HAVE_IPV6 if (rnode->p.family == AF_INET6) { drnode = route_node_get (area->route_table6[0], &rnode->p); if (drnode->info == rnode->info) drnode->info = NULL; drnode = route_node_get (area->route_table6[1], &rnode->p); if (drnode->info == rnode->info) drnode->info = NULL; } #endif isis_route_delete (&rnode->p, table); } } } /* Function to validate route tables for L1L2 areas. In this case we can't use * level route tables directly, we have to merge them at first. L1 routes are * preferred over the L2 ones. * * Merge algorithm is trivial (at least for now). All L1 paths are copied into * merge table at first, then L2 paths are added if L1 path for same prefix * doesn't already exists there. * * FIXME: Is it right place to do it at all? Maybe we should push both levels * to the RIB with different zebra route types and let RIB handle this? */ static void isis_route_validate_merge (struct isis_area *area, int family) { struct route_table *table = NULL; struct route_table *merge; struct route_node *rnode, *mrnode; merge = route_table_init (); if (family == AF_INET) table = area->route_table[0]; #ifdef HAVE_IPV6 else if (family == AF_INET6) table = area->route_table6[0]; #endif for (rnode = route_top (table); rnode; rnode = route_next (rnode)) { if (rnode->info == NULL) continue; mrnode = route_node_get (merge, &rnode->p); mrnode->info = rnode->info; } if (family == AF_INET) table = area->route_table[1]; #ifdef HAVE_IPV6 else if (family == AF_INET6) table = area->route_table6[1]; #endif for (rnode = route_top (table); rnode; rnode = route_next (rnode)) { if (rnode->info == NULL) continue; mrnode = route_node_get (merge, &rnode->p); if (mrnode->info != NULL) continue; mrnode->info = rnode->info; } isis_route_validate_table (area, merge); route_table_finish (merge); } /* Walk through route tables and propagate necessary changes into RIB. In case * of L1L2 area, level tables have to be merged at first. */ void isis_route_validate (struct isis_area *area) { struct listnode *node; struct isis_circuit *circuit; if (area->is_type == IS_LEVEL_1) isis_route_validate_table (area, area->route_table[0]); else if (area->is_type == IS_LEVEL_2) isis_route_validate_table (area, area->route_table[1]); else isis_route_validate_merge (area, AF_INET); #ifdef HAVE_IPV6 if (area->is_type == IS_LEVEL_1) isis_route_validate_table (area, area->route_table6[0]); else if (area->is_type == IS_LEVEL_2) isis_route_validate_table (area, area->route_table6[1]); else isis_route_validate_merge (area, AF_INET6); #endif if (!area->circuit_list) { return; } /* walk all circuits and reset any spf specific flags */ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); return; } void isis_route_invalidate_table (struct isis_area *area, struct route_table *table) { struct route_node *rode; struct isis_route_info *rinfo; for (rode = route_top (table); rode; rode = route_next (rode)) { if (rode->info == NULL) continue; rinfo = rode->info; UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); } } void isis_route_invalidate (struct isis_area *area) { if (area->is_type & IS_LEVEL_1) isis_route_invalidate_table (area, area->route_table[0]); if (area->is_type & IS_LEVEL_2) isis_route_invalidate_table (area, area->route_table[1]); } quagga-1.2.4/isisd/isis_route.h000066400000000000000000000044121325323223500164350ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_route.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * based on ../ospf6d/ospf6_route.[ch] * by Yasuhiro Ohara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_ROUTE_H #define _ZEBRA_ISIS_ROUTE_H #ifdef HAVE_IPV6 struct isis_nexthop6 { ifindex_t ifindex; struct in6_addr ip6; struct in6_addr router_address6; unsigned int lock; }; #endif /* HAVE_IPV6 */ struct isis_nexthop { ifindex_t ifindex; struct in_addr ip; struct in_addr router_address; unsigned int lock; }; struct isis_route_info { #define ISIS_ROUTE_FLAG_ACTIVE 0x01 /* active route for the prefix */ #define ISIS_ROUTE_FLAG_ZEBRA_SYNCED 0x02 /* set when route synced to zebra */ #define ISIS_ROUTE_FLAG_ZEBRA_RESYNC 0x04 /* set when route needs to sync */ u_char flag; u_int32_t cost; u_int32_t depth; struct list *nexthops; #ifdef HAVE_IPV6 struct list *nexthops6; #endif /* HAVE_IPV6 */ }; struct isis_route_info *isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, struct list *adjacencies, struct isis_area *area, int level); void isis_route_validate (struct isis_area *area); void isis_route_invalidate_table (struct isis_area *area, struct route_table *table); void isis_route_invalidate (struct isis_area *area); #endif /* _ZEBRA_ISIS_ROUTE_H */ quagga-1.2.4/isisd/isis_routemap.c000066400000000000000000000347451325323223500171420ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_routemap.c * * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "filter.h" #include "hash.h" #include "if.h" #include "linklist.h" #include "log.h" #include "memory.h" #include "prefix.h" #include "plist.h" #include "routemap.h" #include "table.h" #include "thread.h" #include "vty.h" #include "isis_constants.h" #include "isis_common.h" #include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" #include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_spf.h" #include "isis_route.h" #include "isis_zebra.h" #include "isis_routemap.h" static 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_ISIS) return RMAP_NOMATCH; alist = access_list_lookup(AFI_IP, (char*)rule); if (access_list_apply(alist, prefix) != FILTER_DENY) return RMAP_MATCH; return RMAP_NOMATCH; } static void * route_match_ip_address_compile(const char *arg) { return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_address_free(void *rule) { XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } static 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 }; /* ------------------------------------------------------------*/ static 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_ISIS) return RMAP_NOMATCH; plist = prefix_list_lookup(AFI_IP, (char*)rule); if (prefix_list_apply(plist, prefix) != PREFIX_DENY) return RMAP_MATCH; return RMAP_NOMATCH; } static void * route_match_ip_address_prefix_list_compile(const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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 }; /* ------------------------------------------------------------*/ static 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_ISIS) return RMAP_NOMATCH; alist = access_list_lookup(AFI_IP6, (char*)rule); if (access_list_apply(alist, prefix) != FILTER_DENY) return RMAP_MATCH; return RMAP_NOMATCH; } static void * route_match_ipv6_address_compile(const char *arg) { return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ipv6_address_free(void *rule) { XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } static 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 }; /* ------------------------------------------------------------*/ static 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_ISIS) return RMAP_NOMATCH; plist = prefix_list_lookup(AFI_IP6, (char*)rule); if (prefix_list_apply(plist, prefix) != PREFIX_DENY) return RMAP_MATCH; return RMAP_NOMATCH; } static void * route_match_ipv6_address_prefix_list_compile(const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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 }; /* ------------------------------------------------------------*/ static route_map_result_t route_set_metric(void *rule, struct prefix *prefix, route_map_object_t type, void *object) { uint32_t *metric; struct isis_ext_info *info; if (type == RMAP_ISIS) { metric = rule; info = object; info->metric = *metric; } return RMAP_OKAY; } static void * route_set_metric_compile(const char *arg) { unsigned long metric; char *endp; uint32_t *ret; metric = strtoul(arg, &endp, 10); if (arg[0] == '\0' || *endp != '\0' || metric > MAX_WIDE_PATH_METRIC) return NULL; ret = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*ret)); *ret = metric; return ret; } static void route_set_metric_free(void *rule) { XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_set_metric_compile, route_set_metric_free }; /* ------------------------------------------------------------*/ static int isis_route_match_add(struct vty *vty, struct route_map_index *index, const char *command, const 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; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int isis_route_match_delete(struct vty *vty, struct route_map_index *index, const char *command, const 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; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int isis_route_set_add(struct vty *vty, struct route_map_index *index, const char *command, const 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; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int isis_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const 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; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* ------------------------------------------------------------*/ 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 isis_route_match_add(vty, vty->index, "ip address", argv[0]); } DEFUN(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") { if (argc == 0) return isis_route_match_delete(vty, vty->index, "ip address", NULL); return isis_route_match_delete(vty, vty->index, "ip address", argv[0]); } ALIAS(no_match_ip_address, no_match_ip_address_cmd, "no match ip address", NO_STR MATCH_STR IP_STR "Match address of route\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 isis_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 isis_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); return isis_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_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 isis_route_match_add(vty, vty->index, "ipv6 address", argv[0]); } DEFUN(no_match_ipv6_address, no_match_ipv6_address_val_cmd, "no match ipv6 address WORD", NO_STR MATCH_STR IPV6_STR "Match IPv6 address of route\n" "IPv6 access-list name\n") { if (argc == 0) return isis_route_match_delete(vty, vty->index, "ipv6 address", NULL); return isis_route_match_delete(vty, vty->index, "ipv6 address", argv[0]); } ALIAS(no_match_ipv6_address, no_match_ipv6_address_cmd, "no match ipv6 address", NO_STR MATCH_STR IPV6_STR "Match IPv6 address of route\n" ); /* ------------------------------------------------------------*/ 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 isis_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", NO_STR MATCH_STR IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return isis_route_match_delete (vty, vty->index, "ipv6 address prefix-list", NULL); return isis_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); } ALIAS(no_match_ipv6_address_prefix_list, no_match_ipv6_address_prefix_list_val_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" ); /* ------------------------------------------------------------*/ /* set metric already exists e.g. in the ospf routemap. vtysh doesn't cope well with different * commands at the same node, therefore add set metric with the same 32-bit range as ospf and * verify that the input is a valid isis metric */ DEFUN(set_metric, set_metric_cmd, "set metric <0-4294967295>", SET_STR "Metric vale for destination routing protocol\n" "Metric value\n") { return isis_route_set_add(vty, vty->index, "metric", argv[0]); } DEFUN(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") { if (argc == 0) return isis_route_set_delete(vty, vty->index, "metric", NULL); return isis_route_set_delete(vty, vty->index, "metric", argv[0]); } ALIAS(no_set_metric, no_set_metric_cmd, "no set metric", NO_STR SET_STR "Metric vale for destination routing protocol\n" ); void isis_route_map_init(void) { route_map_init(); route_map_init_vty(); route_map_install_match(&route_match_ip_address_cmd); install_element(RMAP_NODE, &match_ip_address_cmd); install_element(RMAP_NODE, &no_match_ip_address_val_cmd); install_element(RMAP_NODE, &no_match_ip_address_cmd); route_map_install_match(&route_match_ip_address_prefix_list_cmd); install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element(RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd); route_map_install_match(&route_match_ipv6_address_cmd); install_element(RMAP_NODE, &match_ipv6_address_cmd); install_element(RMAP_NODE, &no_match_ipv6_address_val_cmd); install_element(RMAP_NODE, &no_match_ipv6_address_cmd); route_map_install_match(&route_match_ipv6_address_prefix_list_cmd); install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd); install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_val_cmd); install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); route_map_install_set(&route_set_metric_cmd); install_element(RMAP_NODE, &set_metric_cmd); install_element(RMAP_NODE, &no_set_metric_val_cmd); install_element(RMAP_NODE, &no_set_metric_cmd); } quagga-1.2.4/isisd/isis_routemap.h000066400000000000000000000016571325323223500171430ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_routemap.h * * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ISIS_ROUTEMAP_H #define ISIS_ROUTEMAP_H void isis_route_map_init(void); #endif quagga-1.2.4/isisd/isis_spf.c000066400000000000000000001326251325323223500160720ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_spf.c * The SPT algorithm * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "thread.h" #include "linklist.h" #include "vty.h" #include "log.h" #include "command.h" #include "memory.h" #include "prefix.h" #include "hash.h" #include "if.h" #include "table.h" #include "isis_constants.h" #include "isis_common.h" #include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" #include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_dynhn.h" #include "isis_spf.h" #include "isis_route.h" #include "isis_csm.h" int isis_run_spf_l1 (struct thread *thread); int isis_run_spf_l2 (struct thread *thread); /* 7.2.7 */ static void remove_excess_adjs (struct list *adjs) { struct listnode *node, *excess = NULL; struct isis_adjacency *adj, *candidate = NULL; int comp; for (ALL_LIST_ELEMENTS_RO (adjs, node, adj)) { if (excess == NULL) excess = node; candidate = listgetdata (excess); if (candidate->sys_type < adj->sys_type) { excess = node; candidate = adj; continue; } if (candidate->sys_type > adj->sys_type) continue; comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN); if (comp > 0) { excess = node; candidate = adj; continue; } if (comp < 0) continue; if (candidate->circuit->circuit_id > adj->circuit->circuit_id) { excess = node; candidate = adj; continue; } if (candidate->circuit->circuit_id < adj->circuit->circuit_id) continue; comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN); if (comp > 0) { excess = node; candidate = adj; continue; } } list_delete_node (adjs, excess); return; } static const char * vtype2string (enum vertextype vtype) { switch (vtype) { case VTYPE_PSEUDO_IS: return "pseudo_IS"; break; case VTYPE_PSEUDO_TE_IS: return "pseudo_TE-IS"; break; case VTYPE_NONPSEUDO_IS: return "IS"; break; case VTYPE_NONPSEUDO_TE_IS: return "TE-IS"; break; case VTYPE_ES: return "ES"; break; case VTYPE_IPREACH_INTERNAL: return "IP internal"; break; case VTYPE_IPREACH_EXTERNAL: return "IP external"; break; case VTYPE_IPREACH_TE: return "IP TE"; break; #ifdef HAVE_IPV6 case VTYPE_IP6REACH_INTERNAL: return "IP6 internal"; break; case VTYPE_IP6REACH_EXTERNAL: return "IP6 external"; break; #endif /* HAVE_IPV6 */ default: return "UNKNOWN"; } return NULL; /* Not reached */ } static const char * vid2string (struct isis_vertex *vertex, u_char * buff) { switch (vertex->type) { case VTYPE_PSEUDO_IS: case VTYPE_PSEUDO_TE_IS: return print_sys_hostname (vertex->N.id); break; case VTYPE_NONPSEUDO_IS: case VTYPE_NONPSEUDO_TE_IS: case VTYPE_ES: return print_sys_hostname (vertex->N.id); break; case VTYPE_IPREACH_INTERNAL: case VTYPE_IPREACH_EXTERNAL: case VTYPE_IPREACH_TE: #ifdef HAVE_IPV6 case VTYPE_IP6REACH_INTERNAL: case VTYPE_IP6REACH_EXTERNAL: #endif /* HAVE_IPV6 */ prefix2str ((struct prefix *) &vertex->N.prefix, (char *) buff, BUFSIZ); break; default: return "UNKNOWN"; } return (char *) buff; } static struct isis_vertex * isis_vertex_new (void *id, enum vertextype vtype) { struct isis_vertex *vertex; vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); vertex->type = vtype; switch (vtype) { case VTYPE_ES: case VTYPE_NONPSEUDO_IS: case VTYPE_NONPSEUDO_TE_IS: memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN); break; case VTYPE_PSEUDO_IS: case VTYPE_PSEUDO_TE_IS: memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1); break; case VTYPE_IPREACH_INTERNAL: case VTYPE_IPREACH_EXTERNAL: case VTYPE_IPREACH_TE: #ifdef HAVE_IPV6 case VTYPE_IP6REACH_INTERNAL: case VTYPE_IP6REACH_EXTERNAL: #endif /* HAVE_IPV6 */ memcpy (&vertex->N.prefix, (struct prefix *) id, sizeof (struct prefix)); break; default: zlog_err ("WTF!"); } vertex->Adj_N = list_new (); vertex->parents = list_new (); vertex->children = list_new (); return vertex; } static void isis_vertex_del (struct isis_vertex *vertex) { list_delete (vertex->Adj_N); vertex->Adj_N = NULL; list_delete (vertex->parents); vertex->parents = NULL; list_delete (vertex->children); vertex->children = NULL; memset(vertex, 0, sizeof(struct isis_vertex)); XFREE (MTYPE_ISIS_VERTEX, vertex); return; } static void isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj) { struct listnode *node, *nextnode; if (!vertex) return; for (node = listhead (vertex->Adj_N); node; node = nextnode) { nextnode = listnextnode(node); if (listgetdata(node) == adj) list_delete_node(vertex->Adj_N, node); } return; } struct isis_spftree * isis_spftree_new (struct isis_area *area) { struct isis_spftree *tree; tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree)); if (tree == NULL) { zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!"); return NULL; } tree->tents = list_new (); tree->paths = list_new (); tree->area = area; tree->last_run_timestamp = 0; tree->last_run_duration = 0; tree->runcount = 0; tree->pending = 0; return tree; } void isis_spftree_del (struct isis_spftree *spftree) { THREAD_TIMER_OFF (spftree->t_spf); spftree->tents->del = (void (*)(void *)) isis_vertex_del; list_delete (spftree->tents); spftree->tents = NULL; spftree->paths->del = (void (*)(void *)) isis_vertex_del; list_delete (spftree->paths); spftree->paths = NULL; XFREE (MTYPE_ISIS_SPFTREE, spftree); return; } void isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj) { struct listnode *node; if (!adj) return; for (node = listhead (spftree->tents); node; node = listnextnode (node)) isis_vertex_adj_del (listgetdata (node), adj); for (node = listhead (spftree->paths); node; node = listnextnode (node)) isis_vertex_adj_del (listgetdata (node), adj); return; } void spftree_area_init (struct isis_area *area) { if (area->is_type & IS_LEVEL_1) { if (area->spftree[0] == NULL) area->spftree[0] = isis_spftree_new (area); #ifdef HAVE_IPV6 if (area->spftree6[0] == NULL) area->spftree6[0] = isis_spftree_new (area); #endif } if (area->is_type & IS_LEVEL_2) { if (area->spftree[1] == NULL) area->spftree[1] = isis_spftree_new (area); #ifdef HAVE_IPV6 if (area->spftree6[1] == NULL) area->spftree6[1] = isis_spftree_new (area); #endif } return; } void spftree_area_del (struct isis_area *area) { if (area->is_type & IS_LEVEL_1) { if (area->spftree[0] != NULL) { isis_spftree_del (area->spftree[0]); area->spftree[0] = NULL; } #ifdef HAVE_IPV6 if (area->spftree6[0]) { isis_spftree_del (area->spftree6[0]); area->spftree6[0] = NULL; } #endif } if (area->is_type & IS_LEVEL_2) { if (area->spftree[1] != NULL) { isis_spftree_del (area->spftree[1]); area->spftree[1] = NULL; } #ifdef HAVE_IPV6 if (area->spftree6[1] != NULL) { isis_spftree_del (area->spftree6[1]); area->spftree6[1] = NULL; } #endif } return; } void spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj) { if (area->is_type & IS_LEVEL_1) { if (area->spftree[0] != NULL) isis_spftree_adj_del (area->spftree[0], adj); #ifdef HAVE_IPV6 if (area->spftree6[0] != NULL) isis_spftree_adj_del (area->spftree6[0], adj); #endif } if (area->is_type & IS_LEVEL_2) { if (area->spftree[1] != NULL) isis_spftree_adj_del (area->spftree[1], adj); #ifdef HAVE_IPV6 if (area->spftree6[1] != NULL) isis_spftree_adj_del (area->spftree6[1], adj); #endif } return; } /* * Find the system LSP: returns the LSP in our LSP database * associated with the given system ID. */ static struct isis_lsp * isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid) { struct isis_lsp *lsp; u_char lspid[ISIS_SYS_ID_LEN + 2]; memcpy (lspid, sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lspid) = 0; LSP_FRAGMENT (lspid) = 0; lsp = lsp_search (lspid, area->lspdb[level - 1]); if (lsp && lsp->lsp_header->rem_lifetime != 0) return lsp; return NULL; } /* * Add this IS to the root of SPT */ static struct isis_vertex * isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid) { struct isis_vertex *vertex; struct isis_lsp *lsp; #ifdef EXTREME_DEBUG u_char buff[BUFSIZ]; #endif /* EXTREME_DEBUG */ lsp = isis_root_system_lsp (spftree->area, level, sysid); if (lsp == NULL) zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level); if (!spftree->area->oldmetric) vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS); else vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS); listnode_add (spftree->paths, vertex); #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS", vtype2string (vertex->type), vid2string (vertex, buff), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ return vertex; } static struct isis_vertex * isis_find_vertex (struct list *list, void *id, enum vertextype vtype) { struct listnode *node; struct isis_vertex *vertex; struct prefix *p1, *p2; for (ALL_LIST_ELEMENTS_RO (list, node, vertex)) { if (vertex->type != vtype) continue; switch (vtype) { case VTYPE_ES: case VTYPE_NONPSEUDO_IS: case VTYPE_NONPSEUDO_TE_IS: if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0) return vertex; break; case VTYPE_PSEUDO_IS: case VTYPE_PSEUDO_TE_IS: if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0) return vertex; break; case VTYPE_IPREACH_INTERNAL: case VTYPE_IPREACH_EXTERNAL: case VTYPE_IPREACH_TE: #ifdef HAVE_IPV6 case VTYPE_IP6REACH_INTERNAL: case VTYPE_IP6REACH_EXTERNAL: #endif /* HAVE_IPV6 */ p1 = (struct prefix *) id; p2 = (struct prefix *) &vertex->N.id; if (p1->family == p2->family && p1->prefixlen == p2->prefixlen && memcmp (&p1->u.prefix, &p2->u.prefix, PSIZE (p1->prefixlen)) == 0) return vertex; break; } } return NULL; } /* * Add a vertex to TENT sorted by cost and by vertextype on tie break situation */ static struct isis_vertex * isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, void *id, uint32_t cost, int depth, int family, struct isis_adjacency *adj, struct isis_vertex *parent) { struct isis_vertex *vertex, *v; struct listnode *node; struct isis_adjacency *parent_adj; #ifdef EXTREME_DEBUG u_char buff[BUFSIZ]; #endif assert (isis_find_vertex (spftree->paths, id, vtype) == NULL); assert (isis_find_vertex (spftree->tents, id, vtype) == NULL); vertex = isis_vertex_new (id, vtype); vertex->d_N = cost; vertex->depth = depth; if (parent) { listnode_add (vertex->parents, parent); if (listnode_lookup (parent->children, vertex) == NULL) listnode_add (parent->children, vertex); } if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) { for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj)) listnode_add (vertex->Adj_N, parent_adj); } else if (adj) { listnode_add (vertex->Adj_N, adj); } #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d", print_sys_hostname (vertex->N.id), vtype2string (vertex->type), vid2string (vertex, buff), vertex->depth, vertex->d_N, listcount(vertex->Adj_N)); #endif /* EXTREME_DEBUG */ if (list_isempty (spftree->tents)) { listnode_add (spftree->tents, vertex); return vertex; } /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */ for (node = listhead (spftree->tents); node; node = listnextnode (node)) { v = listgetdata (node); if (v->d_N > vertex->d_N) { list_add_node_prev (spftree->tents, node, vertex); break; } else if (v->d_N == vertex->d_N && v->type > vertex->type) { /* Tie break, add according to type */ list_add_node_prev (spftree->tents, node, vertex); break; } } if (node == NULL) listnode_add (spftree->tents, vertex); return vertex; } static void isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype, void *id, struct isis_adjacency *adj, uint32_t cost, int family, struct isis_vertex *parent) { struct isis_vertex *vertex; vertex = isis_find_vertex (spftree->tents, id, vtype); if (vertex) { /* C.2.5 c) */ if (vertex->d_N == cost) { if (adj) listnode_add (vertex->Adj_N, adj); /* d) */ if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) remove_excess_adjs (vertex->Adj_N); if (parent && (listnode_lookup (vertex->parents, parent) == NULL)) listnode_add (vertex->parents, parent); if (parent && (listnode_lookup (parent->children, vertex) == NULL)) listnode_add (parent->children, vertex); return; } else if (vertex->d_N < cost) { /* e) do nothing */ return; } else { /* vertex->d_N > cost */ /* f) */ struct listnode *pnode, *pnextnode; struct isis_vertex *pvertex; listnode_delete (spftree->tents, vertex); assert (listcount (vertex->children) == 0); for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex)) listnode_delete(pvertex->children, vertex); isis_vertex_del (vertex); } } isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent); return; } static void process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, uint32_t dist, uint16_t depth, int family, struct isis_vertex *parent) { struct isis_vertex *vertex; #ifdef EXTREME_DEBUG u_char buff[255]; #endif assert (spftree && parent); /* RFC3787 section 5.1 */ if (spftree->area->newmetric == 1) { if (dist > MAX_WIDE_PATH_METRIC) return; } /* C.2.6 b) */ else if (spftree->area->oldmetric == 1) { if (dist > MAX_NARROW_PATH_METRIC) return; } /* c) */ vertex = isis_find_vertex (spftree->paths, id, vtype); if (vertex) { #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH", print_sys_hostname (vertex->N.id), vtype2string (vtype), vid2string (vertex, buff), dist); #endif /* EXTREME_DEBUG */ assert (dist >= vertex->d_N); return; } vertex = isis_find_vertex (spftree->tents, id, vtype); /* d) */ if (vertex) { /* 1) */ #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d", print_sys_hostname (vertex->N.id), vtype2string (vtype), vid2string (vertex, buff), dist, (parent ? print_sys_hostname (parent->N.id) : "null"), (parent ? listcount (parent->Adj_N) : 0)); #endif /* EXTREME_DEBUG */ if (vertex->d_N == dist) { struct listnode *node; struct isis_adjacency *parent_adj; for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj)) if (listnode_lookup(vertex->Adj_N, parent_adj) == NULL) listnode_add (vertex->Adj_N, parent_adj); /* 2) */ if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) remove_excess_adjs (vertex->Adj_N); if (listnode_lookup (vertex->parents, parent) == NULL) listnode_add (vertex->parents, parent); if (listnode_lookup (parent->children, vertex) == NULL) listnode_add (parent->children, vertex); /* 3) */ return; } else if (vertex->d_N < dist) { return; /* 4) */ } else { struct listnode *pnode, *pnextnode; struct isis_vertex *pvertex; listnode_delete (spftree->tents, vertex); assert (listcount (vertex->children) == 0); for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex)) listnode_delete(pvertex->children, vertex); isis_vertex_del (vertex); } } #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s", print_sys_hostname(id), vtype2string (vtype), dist, (parent ? print_sys_hostname (parent->N.id) : "null")); #endif /* EXTREME_DEBUG */ isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent); return; } /* * C.2.6 Step 1 */ static int isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, uint32_t cost, uint16_t depth, int family, u_char *root_sysid, struct isis_vertex *parent) { struct listnode *node, *fragnode = NULL; uint32_t dist; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct ipv4_reachability *ipreach; struct te_ipv4_reachability *te_ipv4_reach; enum vertextype vtype; struct prefix prefix; #ifdef HAVE_IPV6 struct ipv6_reachability *ip6reach; #endif /* HAVE_IPV6 */ static const u_char null_sysid[ISIS_SYS_ID_LEN]; if (!speaks (lsp->tlv_data.nlpids, family)) return ISIS_OK; lspfragloop: if (lsp->lsp_header->seq_num == 0) { zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore"); return ISIS_WARNING; } #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id)); #endif /* EXTREME_DEBUG */ if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) { if (lsp->tlv_data.is_neighs) { for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) { /* C.2.6 a) */ /* Two way connectivity */ if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + is_neigh->metrics.metric_default; vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS : VTYPE_NONPSEUDO_IS; process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, depth + 1, family, parent); } } if (lsp->tlv_data.te_is_neighs) { for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh)) { if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + GET_TE_METRIC(te_is_neigh); vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS : VTYPE_NONPSEUDO_TE_IS; process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, depth + 1, family, parent); } } } if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach)) { dist = cost + ipreach->metrics.metric_default; vtype = VTYPE_IPREACH_INTERNAL; prefix.u.prefix4 = ipreach->prefix; prefix.prefixlen = ip_masklen (ipreach->mask); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, family, parent); } } if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach)) { dist = cost + ipreach->metrics.metric_default; vtype = VTYPE_IPREACH_EXTERNAL; prefix.u.prefix4 = ipreach->prefix; prefix.prefixlen = ip_masklen (ipreach->mask); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, family, parent); } } if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, node, te_ipv4_reach)) { assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN); dist = cost + ntohl (te_ipv4_reach->te_metric); vtype = VTYPE_IPREACH_TE; prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start, te_ipv4_reach->control); prefix.prefixlen = (te_ipv4_reach->control & 0x3F); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, family, parent); } } #ifdef HAVE_IPV6 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs) { prefix.family = AF_INET6; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach)) { assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN); dist = cost + ntohl(ip6reach->metric); vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ? VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; prefix.prefixlen = ip6reach->prefix_len; memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix, PSIZE (ip6reach->prefix_len)); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, family, parent); } } #endif /* HAVE_IPV6 */ if (fragnode == NULL) fragnode = listhead (lsp->lspu.frags); else fragnode = listnextnode (fragnode); if (fragnode) { lsp = listgetdata (fragnode); goto lspfragloop; } return ISIS_OK; } static int isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, uint32_t cost, uint16_t depth, int family, u_char *root_sysid, struct isis_vertex *parent) { struct listnode *node, *fragnode = NULL; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; enum vertextype vtype; uint32_t dist; pseudofragloop: if (lsp->lsp_header->seq_num == 0) { zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num" " - do not process"); return ISIS_WARNING; } #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_pseudo_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id)); #endif /* EXTREME_DEBUG */ /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ if (lsp->tlv_data.is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) { /* Two way connectivity */ if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + is_neigh->metrics.metric_default; vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS : VTYPE_NONPSEUDO_IS; process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, depth + 1, family, parent); } if (lsp->tlv_data.te_is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh)) { /* Two way connectivity */ if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + GET_TE_METRIC(te_is_neigh); vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS : VTYPE_NONPSEUDO_TE_IS; process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, depth + 1, family, parent); } if (fragnode == NULL) fragnode = listhead (lsp->lspu.frags); else fragnode = listnextnode (fragnode); if (fragnode) { lsp = listgetdata (fragnode); goto pseudofragloop; } return ISIS_OK; } static int isis_spf_preload_tent (struct isis_spftree *spftree, int level, int family, u_char *root_sysid, struct isis_vertex *parent) { struct isis_circuit *circuit; struct listnode *cnode, *anode, *ipnode; struct isis_adjacency *adj; struct isis_lsp *lsp; struct list *adj_list; struct list *adjdb; struct prefix_ipv4 *ipv4; struct prefix prefix; int retval = ISIS_OK; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2]; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6; #endif /* HAVE_IPV6 */ for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit)) { if (circuit->state != C_STATE_UP) continue; if (!(circuit->is_type & level)) continue; if (family == AF_INET && !circuit->ip_router) continue; #ifdef HAVE_IPV6 if (family == AF_INET6 && !circuit->ipv6_router) continue; #endif /* HAVE_IPV6 */ /* * Add IP(v6) addresses of this circuit */ if (family == AF_INET) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4)) { prefix.u.prefix4 = ipv4->prefix; prefix.prefixlen = ipv4->prefixlen; apply_mask (&prefix); isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix, NULL, 0, family, parent); } } #ifdef HAVE_IPV6 if (family == AF_INET6) { prefix.family = AF_INET6; for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6)) { prefix.prefixlen = ipv6->prefixlen; prefix.u.prefix6 = ipv6->prefix; apply_mask (&prefix); isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL, &prefix, NULL, 0, family, parent); } } #endif /* HAVE_IPV6 */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { /* * Add the adjacencies */ adj_list = list_new (); adjdb = circuit->u.bc.adjdb[level - 1]; isis_adj_build_up_list (adjdb, adj_list); if (listcount (adj_list) == 0) { list_delete (adj_list); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s", level, circuit->interface->name); continue; } for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj)) { if (!speaks (&adj->nlpids, family)) continue; switch (adj->sys_type) { case ISIS_SYSTYPE_ES: isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj, circuit->te_metric[level - 1], family, parent); break; case ISIS_SYSTYPE_IS: case ISIS_SYSTYPE_L1_IS: case ISIS_SYSTYPE_L2_IS: isis_spf_add_local (spftree, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS : VTYPE_NONPSEUDO_TE_IS, adj->sysid, adj, circuit->te_metric[level - 1], family, parent); memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = 0; LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency " "L%d on %s (ID %u)", rawlspid_print (lsp_id), level, circuit->interface->name, circuit->circuit_id); break; case ISIS_SYSTYPE_UNKNOWN: default: zlog_warn ("isis_spf_preload_tent unknown adj type"); } } list_delete (adj_list); /* * Add the pseudonode */ if (level == 1) memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); /* can happen during DR reboot */ if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)", level, circuit->interface->name, circuit->circuit_id); continue; } adj = isis_adj_lookup (lsp_id, adjdb); /* if no adj, we are the dis or error */ if (!adj && !circuit->u.bc.is_dr[level - 1]) { zlog_warn ("ISIS-Spf: No adjacency found from root " "to L%d DR %s on %s (ID %d)", level, rawlspid_print (lsp_id), circuit->interface->name, circuit->circuit_id); continue; } lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) { zlog_warn ("ISIS-Spf: No lsp (%p) found from root " "to L%d DR %s on %s (ID %d)", (void *)lsp, level, rawlspid_print (lsp_id), circuit->interface->name, circuit->circuit_id); continue; } isis_spf_process_pseudo_lsp (spftree, lsp, circuit->te_metric[level - 1], 0, family, root_sysid, parent); } else if (circuit->circ_type == CIRCUIT_T_P2P) { adj = circuit->u.p2p.neighbor; if (!adj) continue; switch (adj->sys_type) { case ISIS_SYSTYPE_ES: isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj, circuit->te_metric[level - 1], family, parent); break; case ISIS_SYSTYPE_IS: case ISIS_SYSTYPE_L1_IS: case ISIS_SYSTYPE_L2_IS: if (speaks (&adj->nlpids, family)) isis_spf_add_local (spftree, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS : VTYPE_NONPSEUDO_TE_IS, adj->sysid, adj, circuit->te_metric[level - 1], family, parent); break; case ISIS_SYSTYPE_UNKNOWN: default: zlog_warn ("isis_spf_preload_tent unknown adj type"); break; } } else if (circuit->circ_type == CIRCUIT_T_LOOPBACK) { continue; } else { zlog_warn ("isis_spf_preload_tent unsupported media"); retval = ISIS_WARNING; } } return retval; } /* * The parent(s) for vertex is set when added to TENT list * now we just put the child pointer(s) in place */ static void add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex, int level) { u_char buff[BUFSIZ]; if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type)) return; listnode_add (spftree->paths, vertex); #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS", print_sys_hostname (vertex->N.id), vtype2string (vertex->type), vid2string (vertex, buff), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ if (vertex->type > VTYPE_ES) { if (listcount (vertex->Adj_N) > 0) isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N, vertex->depth, vertex->Adj_N, spftree->area, level); else if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: no adjacencies do not install route for " "%s depth %d dist %d", vid2string (vertex, buff), vertex->depth, vertex->d_N); } return; } static void init_spt (struct isis_spftree *spftree) { spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del; list_delete_all_node (spftree->tents); list_delete_all_node (spftree->paths); spftree->tents->del = spftree->paths->del = NULL; return; } static int isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) { int retval = ISIS_OK; struct listnode *node; struct isis_vertex *vertex; struct isis_vertex *root_vertex; struct isis_spftree *spftree = NULL; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; struct route_table *table = NULL; struct timeval time_now; unsigned long long start_time, end_time; /* Get time that can't roll backwards. */ quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now); start_time = time_now.tv_sec; start_time = (start_time * 1000000) + time_now.tv_usec; if (family == AF_INET) spftree = area->spftree[level - 1]; #ifdef HAVE_IPV6 else if (family == AF_INET6) spftree = area->spftree6[level - 1]; #endif assert (spftree); assert (sysid); /* Make all routes in current route table inactive. */ if (family == AF_INET) table = area->route_table[level - 1]; #ifdef HAVE_IPV6 else if (family == AF_INET6) table = area->route_table6[level - 1]; #endif isis_route_invalidate_table (area, table); /* * C.2.5 Step 0 */ init_spt (spftree); /* a) */ root_vertex = isis_spf_add_root (spftree, level, sysid); /* b) */ retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex); if (retval != ISIS_OK) { zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid)); goto out; } /* * C.2.7 Step 2 */ if (listcount (spftree->tents) == 0) { zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid)); goto out; } while (listcount (spftree->tents) > 0) { node = listhead (spftree->tents); vertex = listgetdata (node); #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS", print_sys_hostname (vertex->N.id), vtype2string (vertex->type), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ /* Remove from tent list and add to paths list */ list_delete_node (spftree->tents, node); add_to_paths (spftree, vertex, level); switch (vertex->type) { case VTYPE_PSEUDO_IS: case VTYPE_NONPSEUDO_IS: case VTYPE_PSEUDO_TE_IS: case VTYPE_NONPSEUDO_TE_IS: memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, area->lspdb[level - 1]); if (lsp && lsp->lsp_header->rem_lifetime != 0) { if (LSP_PSEUDO_ID (lsp_id)) { isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N, vertex->depth, family, sysid, vertex); } else { isis_spf_process_lsp (spftree, lsp, vertex->d_N, vertex->depth, family, sysid, vertex); } } else { zlog_warn ("ISIS-Spf: No LSP found for %s", rawlspid_print (lsp_id)); } break; default:; } } out: isis_route_validate (area); spftree->pending = 0; spftree->runcount++; spftree->last_run_timestamp = time (NULL); quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now); end_time = time_now.tv_sec; end_time = (end_time * 1000000) + time_now.tv_usec; spftree->last_run_duration = end_time - start_time; return retval; } int isis_run_spf_l1 (struct thread *thread) { struct isis_area *area; int retval = ISIS_OK; area = THREAD_ARG (thread); assert (area); area->spftree[0]->t_spf = NULL; area->spftree[0]->pending = 0; if (!(area->is_type & IS_LEVEL_1)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag); if (area->ip_circuits) retval = isis_run_spf (area, 1, AF_INET, isis->sysid); return retval; } int isis_run_spf_l2 (struct thread *thread) { struct isis_area *area; int retval = ISIS_OK; area = THREAD_ARG (thread); assert (area); area->spftree[1]->t_spf = NULL; area->spftree[1]->pending = 0; if (!(area->is_type & IS_LEVEL_2)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag); if (area->ip_circuits) retval = isis_run_spf (area, 2, AF_INET, isis->sysid); return retval; } int isis_spf_schedule (struct isis_area *area, int level) { struct isis_spftree *spftree = area->spftree[level - 1]; time_t now = time (NULL); int diff = now - spftree->last_run_timestamp; assert (diff >= 0); assert (area->is_type & level); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago", area->area_tag, level, diff); if (spftree->pending) return ISIS_OK; THREAD_TIMER_OFF (spftree->t_spf); /* wait configured min_spf_interval before doing the SPF */ if (diff >= area->min_spf_interval[level-1]) return isis_run_spf (area, level, AF_INET, isis->sysid); if (level == 1) THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, area->min_spf_interval[0] - diff); else THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, area->min_spf_interval[1] - diff); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", area->area_tag, level, area->min_spf_interval[level-1] - diff); spftree->pending = 1; return ISIS_OK; } #ifdef HAVE_IPV6 static int isis_run_spf6_l1 (struct thread *thread) { struct isis_area *area; int retval = ISIS_OK; area = THREAD_ARG (thread); assert (area); area->spftree6[0]->t_spf = NULL; area->spftree6[0]->pending = 0; if (!(area->is_type & IS_LEVEL_1)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag); if (area->ipv6_circuits) retval = isis_run_spf (area, 1, AF_INET6, isis->sysid); return retval; } static int isis_run_spf6_l2 (struct thread *thread) { struct isis_area *area; int retval = ISIS_OK; area = THREAD_ARG (thread); assert (area); area->spftree6[1]->t_spf = NULL; area->spftree6[1]->pending = 0; if (!(area->is_type & IS_LEVEL_2)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag); if (area->ipv6_circuits) retval = isis_run_spf (area, 2, AF_INET6, isis->sysid); return retval; } int isis_spf_schedule6 (struct isis_area *area, int level) { int retval = ISIS_OK; struct isis_spftree *spftree = area->spftree6[level - 1]; time_t now = time (NULL); time_t diff = now - spftree->last_run_timestamp; assert (diff >= 0); assert (area->is_type & level); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %lld sec ago", area->area_tag, level, (long long)diff); if (spftree->pending) return ISIS_OK; THREAD_TIMER_OFF (spftree->t_spf); /* wait configured min_spf_interval before doing the SPF */ if (diff >= area->min_spf_interval[level-1]) return isis_run_spf (area, level, AF_INET6, isis->sysid); if (level == 1) THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, area->min_spf_interval[0] - diff); else THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, area->min_spf_interval[1] - diff); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %lld sec from now", area->area_tag, level, (long long)(area->min_spf_interval[level-1] - diff)); spftree->pending = 1; return retval; } #endif static void isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid) { struct listnode *node; struct listnode *anode; struct isis_vertex *vertex; struct isis_adjacency *adj; u_char buff[BUFSIZ]; vty_out (vty, "Vertex Type Metric " "Next-Hop Interface Parent%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) { if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { vty_out (vty, "%-20s %-12s %-6s", print_sys_hostname (root_sysid), "", ""); vty_out (vty, "%-30s", ""); } else { int rows = 0; vty_out (vty, "%-20s %-12s %-6u ", vid2string (vertex, buff), vtype2string (vertex->type), vertex->d_N); for (ALL_LIST_ELEMENTS_RO (vertex->Adj_N, anode, adj)) { if (adj) { if (rows) { vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%-20s %-12s %-6s ", "", "", ""); } vty_out (vty, "%-20s %-9s ", print_sys_hostname (adj->sysid), adj->circuit->interface->name); ++rows; } } if (rows == 0) vty_out (vty, "%-30s ", ""); } /* Print list of parents for the ECMP DAG */ if (listcount (vertex->parents) > 0) { struct listnode *pnode; struct isis_vertex *pvertex; int rows = 0; for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) { if (rows) { vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%-72s", ""); } vty_out (vty, "%s(%d)", vid2string (pvertex, buff), pvertex->type); ++rows; } } else { vty_out (vty, " NULL "); } #if 0 if (listcount (vertex->children) > 0) { struct listnode *cnode; struct isis_vertex *cvertex; for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex)) { vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%-72s", ""); vty_out (vty, "%s(%d) ", vid2string (cvertex, buff), cvertex->type); } } #endif vty_out (vty, "%s", VTY_NEWLINE); } } DEFUN (show_isis_topology, show_isis_topology_cmd, "show isis topology", SHOW_STR "IS-IS information\n" "IS-IS paths to Intermediate Systems\n") { struct listnode *node; struct isis_area *area; int level; if (!isis->area_list || isis->area_list->count == 0) return CMD_SUCCESS; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); for (level = 0; level < ISIS_LEVELS; level++) { if (area->ip_circuits > 0 && area->spftree[level] && area->spftree[level]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s", level + 1, VTY_NEWLINE); isis_print_paths (vty, area->spftree[level]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[level] && area->spftree6[level]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-%d routers that speak IPv6%s", level + 1, VTY_NEWLINE); isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ } vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (show_isis_topology_l1, show_isis_topology_l1_cmd, "show isis topology level-1", SHOW_STR "IS-IS information\n" "IS-IS paths to Intermediate Systems\n" "Paths to all level-1 routers in the area\n") { struct listnode *node; struct isis_area *area; if (!isis->area_list || isis->area_list->count == 0) return CMD_SUCCESS; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); if (area->ip_circuits > 0 && area->spftree[0] && area->spftree[0]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s", VTY_NEWLINE); isis_print_paths (vty, area->spftree[0]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[0] && area->spftree6[0]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s", VTY_NEWLINE); isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (show_isis_topology_l2, show_isis_topology_l2_cmd, "show isis topology level-2", SHOW_STR "IS-IS information\n" "IS-IS paths to Intermediate Systems\n" "Paths to all level-2 routers in the domain\n") { struct listnode *node; struct isis_area *area; if (!isis->area_list || isis->area_list->count == 0) return CMD_SUCCESS; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); if (area->ip_circuits > 0 && area->spftree[1] && area->spftree[1]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s", VTY_NEWLINE); isis_print_paths (vty, area->spftree[1]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[1] && area->spftree6[1]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s", VTY_NEWLINE); isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } void isis_spf_cmds_init () { install_element (VIEW_NODE, &show_isis_topology_cmd); install_element (VIEW_NODE, &show_isis_topology_l1_cmd); install_element (VIEW_NODE, &show_isis_topology_l2_cmd); } quagga-1.2.4/isisd/isis_spf.h000066400000000000000000000055771325323223500161040ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_spf.h * IS-IS Shortest Path First algorithm * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_SPF_H #define _ZEBRA_ISIS_SPF_H enum vertextype { VTYPE_PSEUDO_IS = 1, VTYPE_PSEUDO_TE_IS, VTYPE_NONPSEUDO_IS, VTYPE_NONPSEUDO_TE_IS, VTYPE_ES, VTYPE_IPREACH_INTERNAL, VTYPE_IPREACH_EXTERNAL, VTYPE_IPREACH_TE #ifdef HAVE_IPV6 , VTYPE_IP6REACH_INTERNAL, VTYPE_IP6REACH_EXTERNAL #endif /* HAVE_IPV6 */ }; /* * Triple */ struct isis_vertex { enum vertextype type; union { u_char id[ISIS_SYS_ID_LEN + 1]; struct prefix prefix; } N; u_int32_t d_N; /* d(N) Distance from this IS */ u_int16_t depth; /* The depth in the imaginary tree */ struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ struct list *parents; /* list of parents for ECMP */ struct list *children; /* list of children used for tree dump */ }; struct isis_spftree { struct thread *t_spf; /* spf threads */ struct list *paths; /* the SPT */ struct list *tents; /* TENT */ struct isis_area *area; /* back pointer to area */ int pending; /* already scheduled */ unsigned int runcount; /* number of runs since uptime */ time_t last_run_timestamp; /* last run timestamp for scheduling */ time_t last_run_duration; /* last run duration in msec */ }; struct isis_spftree * isis_spftree_new (struct isis_area *area); void isis_spftree_del (struct isis_spftree *spftree); void isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj); void spftree_area_init (struct isis_area *area); void spftree_area_del (struct isis_area *area); void spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj); int isis_spf_schedule (struct isis_area *area, int level); void isis_spf_cmds_init (void); #ifdef HAVE_IPV6 int isis_spf_schedule6 (struct isis_area *area, int level); #endif #endif /* _ZEBRA_ISIS_SPF_H */ quagga-1.2.4/isisd/isis_te.c000066400000000000000000001143701325323223500157070ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_te.c * * This is an implementation of RFC5305 * * Copyright (C) 2014 Orange Labs * http://www.orange.com * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "linklist.h" #include "thread.h" #include "vty.h" #include "stream.h" #include "memory.h" #include "log.h" #include "prefix.h" #include "command.h" #include "hash.h" #include "if.h" #include "checksum.h" #include "md5.h" #include "sockunion.h" #include "network.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" #include "isisd/isis_te.h" /* Global varial for MPLS TE management */ struct isis_mpls_te isisMplsTE; const char *mode2text[] = { "Disable", "Area", "AS", "Emulate" }; /*------------------------------------------------------------------------* * Followings are control functions for MPLS-TE parameters management. *------------------------------------------------------------------------*/ /* Search MPLS TE Circuit context from Interface */ static struct mpls_te_circuit * lookup_mpls_params_by_ifp (struct interface *ifp) { struct isis_circuit *circuit; if ((circuit = circuit_scan_by_ifp (ifp)) == NULL) return NULL; return circuit->mtc; } /* Create new MPLS TE Circuit context */ struct mpls_te_circuit * mpls_te_circuit_new() { struct mpls_te_circuit *mtc; zlog_debug ("ISIS MPLS-TE: Create new MPLS TE Circuit context"); mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof (struct mpls_te_circuit)); if (mtc == NULL) return NULL; mtc->status = disable; mtc->type = STD_TE; mtc->length = 0; return mtc; } /* Copy SUB TLVs parameters into a buffer - No space verification are performed */ /* Caller must verify before that there is enough free space in the buffer */ u_char add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc) { u_char size, *tlvs = buf; zlog_debug ("ISIS MPLS-TE: Add TE Sub TLVs to buffer"); if (mtc == NULL) { zlog_debug("ISIS MPLS-TE: Abort! No MPLS TE Circuit available has been specified"); return 0; } /* Create buffer if not provided */ if (buf == NULL) { zlog_debug("ISIS MPLS-TE: Abort! No Buffer has been specified"); return 0; } /* TE_SUBTLV_ADMIN_GRP */ if (SUBTLV_TYPE(mtc->admin_grp) != 0) { size = SUBTLV_SIZE (&(mtc->admin_grp.header)); memcpy(tlvs, &(mtc->admin_grp), size); tlvs += size; } /* TE_SUBTLV_LLRI */ if (SUBTLV_TYPE(mtc->llri) != 0) { size = SUBTLV_SIZE (&(mtc->llri.header)); memcpy(tlvs, &(mtc->llri), size); tlvs += size; } /* TE_SUBTLV_LCLIF_IPADDR */ if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) { size = SUBTLV_SIZE (&(mtc->local_ipaddr.header)); memcpy(tlvs, &(mtc->local_ipaddr), size); tlvs += size; } /* TE_SUBTLV_RMTIF_IPADDR */ if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) { size = SUBTLV_SIZE (&(mtc->rmt_ipaddr.header)); memcpy(tlvs, &(mtc->rmt_ipaddr), size); tlvs += size; } /* TE_SUBTLV_MAX_BW */ if (SUBTLV_TYPE(mtc->max_bw) != 0) { size = SUBTLV_SIZE (&(mtc->max_bw.header)); memcpy(tlvs, &(mtc->max_bw), size); tlvs += size; } /* TE_SUBTLV_MAX_RSV_BW */ if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) { size = SUBTLV_SIZE (&(mtc->max_rsv_bw.header)); memcpy(tlvs, &(mtc->max_rsv_bw), size); tlvs += size; } /* TE_SUBTLV_UNRSV_BW */ if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) { size = SUBTLV_SIZE (&(mtc->unrsv_bw.header)); memcpy(tlvs, &(mtc->unrsv_bw), size); tlvs += size; } /* TE_SUBTLV_TE_METRIC */ if (SUBTLV_TYPE(mtc->te_metric) != 0) { size = SUBTLV_SIZE (&(mtc->te_metric.header)); memcpy(tlvs, &(mtc->te_metric), size); tlvs += size; } /* TE_SUBTLV_AV_DELAY */ if (SUBTLV_TYPE(mtc->av_delay) != 0) { size = SUBTLV_SIZE (&(mtc->av_delay.header)); memcpy(tlvs, &(mtc->av_delay), size); tlvs += size; } /* TE_SUBTLV_MM_DELAY */ if (SUBTLV_TYPE(mtc->mm_delay) != 0) { size = SUBTLV_SIZE (&(mtc->mm_delay.header)); memcpy(tlvs, &(mtc->mm_delay), size); tlvs += size; } /* TE_SUBTLV_DELAY_VAR */ if (SUBTLV_TYPE(mtc->delay_var) != 0) { size = SUBTLV_SIZE (&(mtc->delay_var.header)); memcpy(tlvs, &(mtc->delay_var), size); tlvs += size; } /* TE_SUBTLV_PKT_LOSS */ if (SUBTLV_TYPE(mtc->pkt_loss) != 0) { size = SUBTLV_SIZE (&(mtc->pkt_loss.header)); memcpy(tlvs, &(mtc->pkt_loss), size); tlvs += size; } /* TE_SUBTLV_RES_BW */ if (SUBTLV_TYPE(mtc->res_bw) != 0) { size = SUBTLV_SIZE (&(mtc->res_bw.header)); memcpy(tlvs, &(mtc->res_bw), size); tlvs += size; } /* TE_SUBTLV_AVA_BW */ if (SUBTLV_TYPE(mtc->ava_bw) != 0) { size = SUBTLV_SIZE (&(mtc->ava_bw.header)); memcpy(tlvs, &(mtc->ava_bw), size); tlvs += size; } /* TE_SUBTLV_USE_BW */ if (SUBTLV_TYPE(mtc->use_bw) != 0) { size = SUBTLV_SIZE (&(mtc->use_bw.header)); memcpy(tlvs, &(mtc->use_bw), size); tlvs += size; } /* Update SubTLVs length */ mtc->length = subtlvs_len(mtc); zlog_debug("ISIS MPLS-TE: Add %d bytes length SubTLVs", mtc->length); return mtc->length; } /* Compute total Sub-TLVs size */ u_char subtlvs_len (struct mpls_te_circuit *mtc) { int length = 0; /* Sanity Check */ if (mtc == NULL) return 0; /* TE_SUBTLV_ADMIN_GRP */ if (SUBTLV_TYPE(mtc->admin_grp) != 0) length += SUBTLV_SIZE (&(mtc->admin_grp.header)); /* TE_SUBTLV_LLRI */ if (SUBTLV_TYPE(mtc->llri) != 0) length += SUBTLV_SIZE (&mtc->llri.header); /* TE_SUBTLV_LCLIF_IPADDR */ if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) length += SUBTLV_SIZE (&mtc->local_ipaddr.header); /* TE_SUBTLV_RMTIF_IPADDR */ if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) length += SUBTLV_SIZE (&mtc->rmt_ipaddr.header); /* TE_SUBTLV_MAX_BW */ if (SUBTLV_TYPE(mtc->max_bw) != 0) length += SUBTLV_SIZE (&mtc->max_bw.header); /* TE_SUBTLV_MAX_RSV_BW */ if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) length += SUBTLV_SIZE (&mtc->max_rsv_bw.header); /* TE_SUBTLV_UNRSV_BW */ if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) length += SUBTLV_SIZE (&mtc->unrsv_bw.header); /* TE_SUBTLV_TE_METRIC */ if (SUBTLV_TYPE(mtc->te_metric) != 0) length += SUBTLV_SIZE (&mtc->te_metric.header); /* TE_SUBTLV_AV_DELAY */ if (SUBTLV_TYPE(mtc->av_delay) != 0) length += SUBTLV_SIZE (&mtc->av_delay.header); /* TE_SUBTLV_MM_DELAY */ if (SUBTLV_TYPE(mtc->mm_delay) != 0) length += SUBTLV_SIZE (&mtc->mm_delay.header); /* TE_SUBTLV_DELAY_VAR */ if (SUBTLV_TYPE(mtc->delay_var) != 0) length += SUBTLV_SIZE (&mtc->delay_var.header); /* TE_SUBTLV_PKT_LOSS */ if (SUBTLV_TYPE(mtc->pkt_loss) != 0) length += SUBTLV_SIZE (&mtc->pkt_loss.header); /* TE_SUBTLV_RES_BW */ if (SUBTLV_TYPE(mtc->res_bw) != 0) length += SUBTLV_SIZE (&mtc->res_bw.header); /* TE_SUBTLV_AVA_BW */ if (SUBTLV_TYPE(mtc->ava_bw) != 0) length += SUBTLV_SIZE (&mtc->ava_bw.header); /* TE_SUBTLV_USE_BW */ if (SUBTLV_TYPE(mtc->use_bw) != 0) length += SUBTLV_SIZE (&mtc->use_bw.header); /* Check that length is lower than the MAXIMUM SUBTLV size i.e. 256 */ if (length > MAX_SUBTLV_SIZE) { mtc->length = 0; return 0; } mtc->length = (u_char)length; return mtc->length; } /* Following are various functions to set MPLS TE parameters */ static void set_circuitparams_admin_grp (struct mpls_te_circuit *mtc, u_int32_t admingrp) { SUBTLV_TYPE(mtc->admin_grp) = TE_SUBTLV_ADMIN_GRP; SUBTLV_LEN(mtc->admin_grp) = SUBTLV_DEF_SIZE; mtc->admin_grp.value = htonl(admingrp); return; } static void __attribute__ ((unused)) set_circuitparams_llri (struct mpls_te_circuit *mtc, u_int32_t local, u_int32_t remote) { SUBTLV_TYPE(mtc->llri) = TE_SUBTLV_LLRI; SUBTLV_LEN(mtc->llri) = TE_SUBTLV_LLRI_SIZE; mtc->llri.local = htonl(local); mtc->llri.remote = htonl(remote); } void set_circuitparams_local_ipaddr (struct mpls_te_circuit *mtc, struct in_addr addr) { SUBTLV_TYPE(mtc->local_ipaddr) = TE_SUBTLV_LOCAL_IPADDR; SUBTLV_LEN(mtc->local_ipaddr) = SUBTLV_DEF_SIZE; mtc->local_ipaddr.value.s_addr = addr.s_addr; return; } void set_circuitparams_rmt_ipaddr (struct mpls_te_circuit *mtc, struct in_addr addr) { SUBTLV_TYPE(mtc->rmt_ipaddr) = TE_SUBTLV_RMT_IPADDR; SUBTLV_LEN(mtc->rmt_ipaddr) = SUBTLV_DEF_SIZE; mtc->rmt_ipaddr.value.s_addr = addr.s_addr; return; } static void set_circuitparams_max_bw (struct mpls_te_circuit *mtc, float fp) { SUBTLV_TYPE(mtc->max_bw) = TE_SUBTLV_MAX_BW; SUBTLV_LEN(mtc->max_bw) = SUBTLV_DEF_SIZE; mtc->max_bw.value = htonf(fp); return; } static void set_circuitparams_max_rsv_bw (struct mpls_te_circuit *mtc, float fp) { SUBTLV_TYPE(mtc->max_rsv_bw) = TE_SUBTLV_MAX_RSV_BW; SUBTLV_LEN(mtc->max_rsv_bw) = SUBTLV_DEF_SIZE; mtc->max_rsv_bw.value = htonf(fp); return; } static void set_circuitparams_unrsv_bw (struct mpls_te_circuit *mtc, int priority, float fp) { /* Note that TLV-length field is the size of array. */ SUBTLV_TYPE(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_BW; SUBTLV_LEN(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_SIZE; mtc->unrsv_bw.value[priority] = htonf(fp); return; } static void set_circuitparams_te_metric (struct mpls_te_circuit *mtc, u_int32_t te_metric) { SUBTLV_TYPE(mtc->te_metric) = TE_SUBTLV_TE_METRIC; SUBTLV_LEN(mtc->te_metric) = TE_SUBTLV_TE_METRIC_SIZE; mtc->te_metric.value[0] = (te_metric >> 16) & 0xFF; mtc->te_metric.value[1] = (te_metric >> 8) & 0xFF; mtc->te_metric.value[2] = te_metric & 0xFF; return; } static void set_circuitparams_inter_as (struct mpls_te_circuit *mtc, struct in_addr addr, u_int32_t as) { /* Set the Remote ASBR IP address and then the associated AS number */ SUBTLV_TYPE(mtc->rip) = TE_SUBTLV_RIP; SUBTLV_LEN(mtc->rip) = SUBTLV_DEF_SIZE; mtc->rip.value.s_addr = addr.s_addr; SUBTLV_TYPE(mtc->ras) = TE_SUBTLV_RAS; SUBTLV_LEN(mtc->ras) = SUBTLV_DEF_SIZE; mtc->ras.value = htonl(as); } static void unset_circuitparams_inter_as (struct mpls_te_circuit *mtc) { /* Reset the Remote ASBR IP address and then the associated AS number */ SUBTLV_TYPE(mtc->rip) = 0; SUBTLV_LEN(mtc->rip) = 0; mtc->rip.value.s_addr = 0; SUBTLV_TYPE(mtc->ras) = 0; SUBTLV_LEN(mtc->ras) = 0; mtc->ras.value = 0; } static void set_circuitparams_av_delay (struct mpls_te_circuit *mtc, u_int32_t delay, u_char anormal) { u_int32_t tmp; /* Note that TLV-length field is the size of array. */ SUBTLV_TYPE(mtc->av_delay) = TE_SUBTLV_AV_DELAY; SUBTLV_LEN(mtc->av_delay) = SUBTLV_DEF_SIZE; tmp = delay & TE_EXT_MASK; if (anormal) tmp |= TE_EXT_ANORMAL; mtc->av_delay.value = htonl(tmp); return; } static void set_circuitparams_mm_delay (struct mpls_te_circuit *mtc, u_int32_t low, u_int32_t high, u_char anormal) { u_int32_t tmp; /* Note that TLV-length field is the size of array. */ SUBTLV_TYPE(mtc->mm_delay) = TE_SUBTLV_MM_DELAY; SUBTLV_LEN(mtc->mm_delay) = TE_SUBTLV_MM_DELAY_SIZE; tmp = low & TE_EXT_MASK; if (anormal) tmp |= TE_EXT_ANORMAL; mtc->mm_delay.low = htonl(tmp); mtc->mm_delay.high = htonl(high); return; } static void set_circuitparams_delay_var (struct mpls_te_circuit *mtc, u_int32_t jitter) { /* Note that TLV-length field is the size of array. */ SUBTLV_TYPE(mtc->delay_var) = TE_SUBTLV_DELAY_VAR; SUBTLV_LEN(mtc->delay_var) = SUBTLV_DEF_SIZE; mtc->delay_var.value = htonl(jitter & TE_EXT_MASK); return; } static void set_circuitparams_pkt_loss (struct mpls_te_circuit *mtc, u_int32_t loss, u_char anormal) { u_int32_t tmp; /* Note that TLV-length field is the size of array. */ SUBTLV_TYPE(mtc->pkt_loss) = TE_SUBTLV_PKT_LOSS; SUBTLV_LEN(mtc->pkt_loss) = SUBTLV_DEF_SIZE; tmp = loss & TE_EXT_MASK; if (anormal) tmp |= TE_EXT_ANORMAL; mtc->pkt_loss.value = htonl(tmp); return; } static void set_circuitparams_res_bw (struct mpls_te_circuit *mtc, float fp) { /* Note that TLV-length field is the size of array. */ SUBTLV_TYPE(mtc->res_bw) = TE_SUBTLV_RES_BW; SUBTLV_LEN(mtc->res_bw) = SUBTLV_DEF_SIZE; mtc->res_bw.value = htonf(fp); return; } static void set_circuitparams_ava_bw (struct mpls_te_circuit *mtc, float fp) { /* Note that TLV-length field is the size of array. */ SUBTLV_TYPE(mtc->ava_bw) = TE_SUBTLV_AVA_BW; SUBTLV_LEN(mtc->ava_bw) = SUBTLV_DEF_SIZE; mtc->ava_bw.value = htonf(fp); return; } static void set_circuitparams_use_bw (struct mpls_te_circuit *mtc, float fp) { /* Note that TLV-length field is the size of array. */ SUBTLV_TYPE(mtc->use_bw) = TE_SUBTLV_USE_BW; SUBTLV_LEN(mtc->use_bw) = SUBTLV_DEF_SIZE; mtc->use_bw.value = htonf(fp); return; } /* Main initialization / update function of the MPLS TE Circuit context */ /* Call when interface TE Link parameters are modified */ void isis_link_params_update (struct isis_circuit *circuit, struct interface *ifp) { int i; struct prefix_ipv4 *addr; struct mpls_te_circuit *mtc; /* Sanity Check */ if ((circuit == NULL) || (ifp == NULL)) return; zlog_info ("MPLS-TE: Initialize circuit parameters for interface %s", ifp->name); /* Check if MPLS TE Circuit context has not been already created */ if (circuit->mtc == NULL) circuit->mtc = mpls_te_circuit_new(); mtc = circuit->mtc; /* Fulfil MTC TLV from ifp TE Link parameters */ if (HAS_LINK_PARAMS(ifp)) { mtc->status = enable; /* STD_TE metrics */ if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) set_circuitparams_admin_grp (mtc, ifp->link_params->admin_grp); else SUBTLV_TYPE(mtc->admin_grp) = 0; /* If not already set, register local IP addr from ip_addr list if it exists */ if (SUBTLV_TYPE(mtc->local_ipaddr) == 0) { if (circuit->ip_addrs != NULL && listcount(circuit->ip_addrs) != 0) { addr = (struct prefix_ipv4 *)listgetdata ((struct listnode *)listhead (circuit->ip_addrs)); set_circuitparams_local_ipaddr (mtc, addr->prefix); } } /* If not already set, try to determine Remote IP addr if circuit is P2P */ if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) && (circuit->circ_type == CIRCUIT_T_P2P)) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0) { struct in_addr *ip_addr; ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs)); set_circuitparams_rmt_ipaddr (mtc, *ip_addr); } } if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) set_circuitparams_max_bw (mtc, ifp->link_params->max_bw); else SUBTLV_TYPE(mtc->max_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) set_circuitparams_max_rsv_bw (mtc, ifp->link_params->max_rsv_bw); else SUBTLV_TYPE(mtc->max_rsv_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) for (i = 0; i < MAX_CLASS_TYPE; i++) set_circuitparams_unrsv_bw (mtc, i, ifp->link_params->unrsv_bw[i]); else SUBTLV_TYPE(mtc->unrsv_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_TE)) set_circuitparams_te_metric(mtc, ifp->link_params->te_metric); else SUBTLV_TYPE(mtc->te_metric) = 0; /* TE metric Extensions */ if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) set_circuitparams_av_delay(mtc, ifp->link_params->av_delay, 0); else SUBTLV_TYPE(mtc->av_delay) = 0; if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) set_circuitparams_mm_delay(mtc, ifp->link_params->min_delay, ifp->link_params->max_delay, 0); else SUBTLV_TYPE(mtc->mm_delay) = 0; if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) set_circuitparams_delay_var(mtc, ifp->link_params->delay_var); else SUBTLV_TYPE(mtc->delay_var) = 0; if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) set_circuitparams_pkt_loss(mtc, ifp->link_params->pkt_loss, 0); else SUBTLV_TYPE(mtc->pkt_loss) = 0; if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) set_circuitparams_res_bw(mtc, ifp->link_params->res_bw); else SUBTLV_TYPE(mtc->res_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) set_circuitparams_ava_bw(mtc, ifp->link_params->ava_bw); else SUBTLV_TYPE(mtc->ava_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) set_circuitparams_use_bw(mtc, ifp->link_params->use_bw); else SUBTLV_TYPE(mtc->use_bw) = 0; /* INTER_AS */ if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) set_circuitparams_inter_as(mtc, ifp->link_params->rmt_ip, ifp->link_params->rmt_as); else /* reset inter-as TE params */ unset_circuitparams_inter_as (mtc); /* Compute total length of SUB TLVs */ mtc->length = subtlvs_len(mtc); } else mtc->status = disable; /* Finally Update LSP */ #if 0 if (IS_MPLS_TE(isisMplsTE) && circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); #endif return; } void isis_mpls_te_update (struct interface *ifp) { struct isis_circuit *circuit; /* Sanity Check */ if (ifp == NULL) return; /* Get circuit context from interface */ if ((circuit = circuit_scan_by_ifp(ifp)) == NULL) return; /* Update TE TLVs ... */ isis_link_params_update(circuit, ifp); /* ... and LSP */ if (IS_MPLS_TE(isisMplsTE) && circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); return; } /*------------------------------------------------------------------------* * Followings are vty session control functions. *------------------------------------------------------------------------*/ static u_char show_vty_subtlv_admin_grp (struct vty *vty, struct te_subtlv_admin_grp *tlv) { if (vty != NULL) vty_out (vty, " Administrative Group: 0x%x%s", (u_int32_t) ntohl (tlv->value), VTY_NEWLINE); else zlog_debug (" Administrative Group: 0x%x", (u_int32_t) ntohl (tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_llri (struct vty *vty, struct te_subtlv_llri *tlv) { if (vty != NULL) { vty_out (vty, " Link Local ID: %d%s", (u_int32_t) ntohl (tlv->local), VTY_NEWLINE); vty_out (vty, " Link Remote ID: %d%s", (u_int32_t) ntohl (tlv->remote), VTY_NEWLINE); } else { zlog_debug (" Link Local ID: %d", (u_int32_t) ntohl (tlv->local)); zlog_debug (" Link Remote ID: %d", (u_int32_t) ntohl (tlv->remote)); } return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE); } static u_char show_vty_subtlv_local_ipaddr (struct vty *vty, struct te_subtlv_local_ipaddr *tlv) { if (vty != NULL) vty_out (vty, " Local Interface IP Address(es): %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); else zlog_debug (" Local Interface IP Address(es): %s", inet_ntoa (tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_rmt_ipaddr (struct vty *vty, struct te_subtlv_rmt_ipaddr *tlv) { if (vty != NULL) vty_out (vty, " Remote Interface IP Address(es): %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); else zlog_debug (" Remote Interface IP Address(es): %s", inet_ntoa (tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_max_bw (struct vty *vty, struct te_subtlv_max_bw *tlv) { float fval; fval = ntohf (tlv->value); if (vty != NULL) vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Maximum Bandwidth: %g (Bytes/sec)", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_max_rsv_bw (struct vty *vty, struct te_subtlv_max_rsv_bw *tlv) { float fval; fval = ntohf (tlv->value); if (vty != NULL) vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_unrsv_bw (struct vty *vty, struct te_subtlv_unrsv_bw *tlv) { float fval1, fval2; int i; if (vty != NULL) vty_out (vty, " Unreserved Bandwidth:%s",VTY_NEWLINE); else zlog_debug (" Unreserved Bandwidth:"); for (i = 0; i < MAX_CLASS_TYPE; i+=2) { fval1 = ntohf (tlv->value[i]); fval2 = ntohf (tlv->value[i+1]); if (vty != NULL) vty_out (vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", i, fval1, i+1, fval2, VTY_NEWLINE); else zlog_debug (" [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", i, fval1, i+1, fval2); } return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE); } static u_char show_vty_subtlv_te_metric (struct vty *vty, struct te_subtlv_te_metric *tlv) { u_int32_t te_metric; te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16; if (vty != NULL) vty_out (vty, " Traffic Engineering Metric: %u%s", te_metric, VTY_NEWLINE); else zlog_debug (" Traffic Engineering Metric: %u", te_metric); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_ras (struct vty *vty, struct te_subtlv_ras *tlv) { if (vty != NULL) vty_out (vty, " Inter-AS TE Remote AS number: %u%s", ntohl (tlv->value), VTY_NEWLINE); else zlog_debug (" Inter-AS TE Remote AS number: %u", ntohl (tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_rip (struct vty *vty, struct te_subtlv_rip *tlv) { if (vty != NULL) vty_out (vty, " Inter-AS TE Remote ASBR IP address: %s%s", inet_ntoa (tlv->value), VTY_NEWLINE); else zlog_debug (" Inter-AS TE Remote ASBR IP address: %s", inet_ntoa (tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_av_delay (struct vty *vty, struct te_subtlv_av_delay *tlv) { u_int32_t delay; u_int32_t A; delay = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; A = (u_int32_t) ntohl (tlv->value) & TE_EXT_ANORMAL; if (vty != NULL) vty_out (vty, " %s Average Link Delay: %d (micro-sec)%s", A ? "Anomalous" : "Normal", delay, VTY_NEWLINE); else zlog_debug (" %s Average Link Delay: %d (micro-sec)", A ? "Anomalous" : "Normal", delay); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_mm_delay (struct vty *vty, struct te_subtlv_mm_delay *tlv) { u_int32_t low, high; u_int32_t A; low = (u_int32_t) ntohl (tlv->low) & TE_EXT_MASK; A = (u_int32_t) ntohl (tlv->low) & TE_EXT_ANORMAL; high = (u_int32_t) ntohl (tlv->high) & TE_EXT_MASK; if (vty != NULL) vty_out (vty, " %s Min/Max Link Delay: %d / %d (micro-sec)%s", A ? "Anomalous" : "Normal", low, high, VTY_NEWLINE); else zlog_debug (" %s Min/Max Link Delay: %d / %d (micro-sec)", A ? "Anomalous" : "Normal", low, high); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_delay_var (struct vty *vty, struct te_subtlv_delay_var *tlv) { u_int32_t jitter; jitter = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; if (vty != NULL) vty_out (vty, " Delay Variation: %d (micro-sec)%s", jitter, VTY_NEWLINE); else zlog_debug (" Delay Variation: %d (micro-sec)", jitter); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_pkt_loss (struct vty *vty, struct te_subtlv_pkt_loss *tlv) { u_int32_t loss; u_int32_t A; float fval; loss = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK; fval = (float) (loss * LOSS_PRECISION); A = (u_int32_t) ntohl (tlv->value) & TE_EXT_ANORMAL; if (vty != NULL) vty_out (vty, " %s Link Packet Loss: %g (%%)%s", A ? "Anomalous" : "Normal", fval, VTY_NEWLINE); else zlog_debug (" %s Link Packet Loss: %g (%%)", A ? "Anomalous" : "Normal", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_res_bw (struct vty *vty, struct te_subtlv_res_bw *tlv) { float fval; fval = ntohf(tlv->value); if (vty != NULL) vty_out (vty, " Unidirectional Residual Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Unidirectional Residual Bandwidth: %g (Bytes/sec)", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_ava_bw (struct vty *vty, struct te_subtlv_ava_bw *tlv) { float fval; fval = ntohf (tlv->value); if (vty != NULL) vty_out (vty, " Unidirectional Available Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Unidirectional Available Bandwidth: %g (Bytes/sec)", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_subtlv_use_bw (struct vty *vty, struct te_subtlv_use_bw *tlv) { float fval; fval = ntohf (tlv->value); if (vty != NULL) vty_out (vty, " Unidirectional Utilized Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Unidirectional Utilized Bandwidth: %g (Bytes/sec)", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } static u_char show_vty_unknown_tlv (struct vty *vty, struct subtlv_header *tlvh) { int i, rtn = 1; u_char *v = (u_char *)tlvh; if (vty != NULL) { if (tlvh->length != 0) { vty_out (vty, " Unknown TLV: [type(%#.2x), length(%#.2x)]%s", tlvh->type, tlvh->length, VTY_NEWLINE); vty_out(vty, " Dump: [00]"); rtn = 1; /* initialize end of line counter */ for (i = 0; i < tlvh->length; i++) { vty_out (vty, " %#.2x", v[i]); if (rtn == 8) { vty_out (vty, "%s [%.2x]", VTY_NEWLINE, i + 1); rtn = 1; } else rtn++; } vty_out (vty, "%s", VTY_NEWLINE); } else vty_out (vty, " Unknown TLV: [type(%#.2x), length(%#.2x)]%s", tlvh->type, tlvh->length, VTY_NEWLINE); } else { zlog_debug (" Unknown TLV: [type(%#.2x), length(%#.2x)]", tlvh->type, tlvh->length); } return SUBTLV_SIZE(tlvh); } /* Main Show function */ void mpls_te_print_detail(struct vty *vty, struct te_is_neigh *te) { struct subtlv_header *tlvh, *next; u_int16_t sum = 0; zlog_debug ("ISIS MPLS-TE: Show database TE detail"); if (te->sub_tlvs == NULL) return; tlvh = (struct subtlv_header *)te->sub_tlvs; for (; sum < te->sub_tlvs_length; tlvh = (next ? next : SUBTLV_HDR_NEXT (tlvh))) { next = NULL; switch (tlvh->type) { case TE_SUBTLV_ADMIN_GRP: sum += show_vty_subtlv_admin_grp (vty, (struct te_subtlv_admin_grp *)tlvh); break; case TE_SUBTLV_LLRI: sum += show_vty_subtlv_llri (vty, (struct te_subtlv_llri *)tlvh); break; case TE_SUBTLV_LOCAL_IPADDR: sum += show_vty_subtlv_local_ipaddr (vty, (struct te_subtlv_local_ipaddr *)tlvh); break; case TE_SUBTLV_RMT_IPADDR: sum += show_vty_subtlv_rmt_ipaddr (vty, (struct te_subtlv_rmt_ipaddr *)tlvh); break; case TE_SUBTLV_MAX_BW: sum += show_vty_subtlv_max_bw (vty, (struct te_subtlv_max_bw *)tlvh); break; case TE_SUBTLV_MAX_RSV_BW: sum += show_vty_subtlv_max_rsv_bw (vty, (struct te_subtlv_max_rsv_bw *)tlvh); break; case TE_SUBTLV_UNRSV_BW: sum += show_vty_subtlv_unrsv_bw (vty, (struct te_subtlv_unrsv_bw *)tlvh); break; case TE_SUBTLV_TE_METRIC: sum += show_vty_subtlv_te_metric (vty, (struct te_subtlv_te_metric *)tlvh); break; case TE_SUBTLV_RAS: sum += show_vty_subtlv_ras (vty, (struct te_subtlv_ras *)tlvh); break; case TE_SUBTLV_RIP: sum += show_vty_subtlv_rip (vty, (struct te_subtlv_rip *)tlvh); break; case TE_SUBTLV_AV_DELAY: sum += show_vty_subtlv_av_delay (vty, (struct te_subtlv_av_delay *)tlvh); break; case TE_SUBTLV_MM_DELAY: sum += show_vty_subtlv_mm_delay (vty, (struct te_subtlv_mm_delay *)tlvh); break; case TE_SUBTLV_DELAY_VAR: sum += show_vty_subtlv_delay_var (vty, (struct te_subtlv_delay_var *)tlvh); break; case TE_SUBTLV_PKT_LOSS: sum += show_vty_subtlv_pkt_loss (vty, (struct te_subtlv_pkt_loss *)tlvh); break; case TE_SUBTLV_RES_BW: sum += show_vty_subtlv_res_bw (vty, (struct te_subtlv_res_bw *)tlvh); break; case TE_SUBTLV_AVA_BW: sum += show_vty_subtlv_ava_bw (vty, (struct te_subtlv_ava_bw *)tlvh); break; case TE_SUBTLV_USE_BW: sum += show_vty_subtlv_use_bw (vty, (struct te_subtlv_use_bw *)tlvh); break; default: sum += show_vty_unknown_tlv (vty, tlvh); break; } } return; } /* Specific MPLS TE router parameters write function */ void isis_mpls_te_config_write_router (struct vty *vty) { zlog_debug ("ISIS MPLS-TE: Write ISIS router configuration"); if (IS_MPLS_TE(isisMplsTE)) { vty_out (vty, " mpls-te on%s", VTY_NEWLINE); vty_out (vty, " mpls-te router-address %s%s", inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE); } return; } /*------------------------------------------------------------------------* * Followings are vty command functions. *------------------------------------------------------------------------*/ DEFUN (isis_mpls_te_on, isis_mpls_te_on_cmd, "mpls-te on", MPLS_TE_STR "Enable MPLS-TE functionality\n") { struct listnode *node; struct isis_circuit *circuit; if (IS_MPLS_TE(isisMplsTE)) return CMD_SUCCESS; if (IS_DEBUG_ISIS(DEBUG_TE)) zlog_debug ("ISIS MPLS-TE: OFF -> ON"); isisMplsTE.status = enable; /* * Following code is intended to handle two cases; * * 1) MPLS-TE was disabled at startup time, but now become enabled. * In this case, we must enable MPLS-TE Circuit regarding interface MPLS_TE flag * 2) MPLS-TE was once enabled then disabled, and now enabled again. */ for (ALL_LIST_ELEMENTS_RO (isisMplsTE.cir_list, node, circuit)) { if (circuit->mtc == NULL || IS_FLOOD_AS (circuit->mtc->type)) continue; if ((circuit->mtc->status == disable) && HAS_LINK_PARAMS(circuit->interface)) circuit->mtc->status = enable; else continue; /* Reoriginate STD_TE & GMPLS circuits */ if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); } return CMD_SUCCESS; } DEFUN (no_isis_mpls_te_on, no_isis_mpls_te_on_cmd, "no mpls-te", NO_STR "Disable the MPLS-TE functionality\n") { struct listnode *node; struct isis_circuit *circuit; if (isisMplsTE.status == disable) return CMD_SUCCESS; if (IS_DEBUG_ISIS(DEBUG_TE)) zlog_debug ("ISIS MPLS-TE: ON -> OFF"); isisMplsTE.status = disable; /* Flush LSP if circuit engage */ for (ALL_LIST_ELEMENTS_RO (isisMplsTE.cir_list, node, circuit)) { if (circuit->mtc == NULL || (circuit->mtc->status == disable)) continue; /* disable MPLS_TE Circuit */ circuit->mtc->status = disable; /* Re-originate circuit without STD_TE & GMPLS parameters */ if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); } return CMD_SUCCESS; } DEFUN (isis_mpls_te_router_addr, isis_mpls_te_router_addr_cmd, "mpls-te router-address A.B.C.D", MPLS_TE_STR "Stable IP address of the advertising router\n" "MPLS-TE router address in IPv4 address format\n") { struct in_addr value; struct listnode *node; struct isis_area *area; if (! inet_aton (argv[0], &value)) { vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } isisMplsTE.router_id.s_addr = value.s_addr; if (isisMplsTE.status == disable) return CMD_SUCCESS; /* Update main Router ID in isis global structure */ isis->router_id = value.s_addr; /* And re-schedule LSP update */ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) if (listcount (area->area_addrs) > 0) lsp_regenerate_schedule (area, area->is_type, 0); return CMD_SUCCESS; } DEFUN (isis_mpls_te_inter_as, isis_mpls_te_inter_as_cmd, "mpls-te inter-as (level-1|level-1-2|level-2-only)", MPLS_TE_STR "Configure MPLS-TE Inter-AS support\n" "AREA native mode self originate INTER-AS LSP with L1 only flooding scope)\n" "AREA native mode self originate INTER-AS LSP with L1 and L2 flooding scope)\n" "AS native mode self originate INTER-AS LSP with L2 only flooding scope\n") { vty_out (vty, "Not yet supported%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (no_isis_mpls_te_inter_as, no_isis_mpls_te_inter_as_cmd, "no mpls-te inter-as", NO_STR "Disable the MPLS-TE functionality\n" "Disable MPLS-TE Inter-AS support\n") { vty_out (vty, "Not yet supported%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (show_isis_mpls_te_router, show_isis_mpls_te_router_cmd, "show isis mpls-te router", SHOW_STR ISIS_STR MPLS_TE_STR "Router information\n") { if (IS_MPLS_TE(isisMplsTE)) { vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE); if (vty != NULL) { if (ntohs (isisMplsTE.router_id.s_addr) != 0) vty_out (vty, " Router-Address: %s%s", inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE); else vty_out (vty, " N/A%s", VTY_NEWLINE); } } else vty_out (vty, " MPLS-TE is disable on this router%s", VTY_NEWLINE); return CMD_SUCCESS; } static void show_mpls_te_sub (struct vty *vty, struct interface *ifp) { struct mpls_te_circuit *mtc; if ((IS_MPLS_TE(isisMplsTE)) && ((mtc = lookup_mpls_params_by_ifp (ifp)) != NULL)) { /* Continue only if interface is not passive or support Inter-AS TEv2 */ if (mtc->status != enable) { if (IS_INTER_AS(mtc->type)) { vty_out (vty, "-- Inter-AS TEv2 link parameters for %s --%s", ifp->name, VTY_NEWLINE); } else { /* MPLS-TE is not activate on this interface */ /* or this interface is passive and Inter-AS TEv2 is not activate */ vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", ifp->name, VTY_NEWLINE); return; } } else { vty_out (vty, "-- MPLS-TE link parameters for %s --%s", ifp->name, VTY_NEWLINE); } show_vty_subtlv_admin_grp (vty, &mtc->admin_grp); if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) show_vty_subtlv_local_ipaddr (vty, &mtc->local_ipaddr); if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) show_vty_subtlv_rmt_ipaddr (vty, &mtc->rmt_ipaddr); show_vty_subtlv_max_bw (vty, &mtc->max_bw); show_vty_subtlv_max_rsv_bw (vty, &mtc->max_rsv_bw); show_vty_subtlv_unrsv_bw (vty, &mtc->unrsv_bw); show_vty_subtlv_te_metric (vty, &mtc->te_metric); if (IS_INTER_AS(mtc->type)) { if (SUBTLV_TYPE(mtc->ras) != 0) show_vty_subtlv_ras (vty, &mtc->ras); if (SUBTLV_TYPE(mtc->rip) != 0) show_vty_subtlv_rip (vty, &mtc->rip); } show_vty_subtlv_av_delay (vty, &mtc->av_delay); show_vty_subtlv_mm_delay (vty, &mtc->mm_delay); show_vty_subtlv_delay_var (vty, &mtc->delay_var); show_vty_subtlv_pkt_loss (vty, &mtc->pkt_loss); show_vty_subtlv_res_bw (vty, &mtc->res_bw); show_vty_subtlv_ava_bw (vty, &mtc->ava_bw); show_vty_subtlv_use_bw (vty, &mtc->use_bw); vty_out (vty, "---------------%s%s", VTY_NEWLINE, VTY_NEWLINE); } else { vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", ifp->name, VTY_NEWLINE); } return; } DEFUN (show_isis_mpls_te_interface, show_isis_mpls_te_interface_cmd, "show isis mpls-te interface [INTERFACE]", SHOW_STR ISIS_STR MPLS_TE_STR "Interface information\n" "Interface name\n") { struct interface *ifp; struct listnode *node; /* Show All Interfaces. */ if (argc == 0) { for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) show_mpls_te_sub (vty, ifp); } /* 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_sub (vty, ifp); } return CMD_SUCCESS; } /* Initialize MPLS_TE */ void isis_mpls_te_init (void) { zlog_debug("ISIS MPLS-TE: Initialize"); /* Initialize MPLS_TE structure */ isisMplsTE.status = disable; isisMplsTE.level = 0; isisMplsTE.inter_as = off; isisMplsTE.interas_areaid.s_addr = 0; isisMplsTE.cir_list = list_new(); isisMplsTE.router_id.s_addr = 0; /* Register new VTY commands */ install_element (VIEW_NODE, &show_isis_mpls_te_router_cmd); install_element (VIEW_NODE, &show_isis_mpls_te_interface_cmd); install_element (ISIS_NODE, &isis_mpls_te_on_cmd); install_element (ISIS_NODE, &no_isis_mpls_te_on_cmd); install_element (ISIS_NODE, &isis_mpls_te_router_addr_cmd); install_element (ISIS_NODE, &isis_mpls_te_inter_as_cmd); install_element (ISIS_NODE, &no_isis_mpls_te_inter_as_cmd); return; } quagga-1.2.4/isisd/isis_te.h000066400000000000000000000262151325323223500157140ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_te.c * * This is an implementation of RFC5305, RFC 5307 and draft-ietf-isis-te-metric-extensions-11 * * Copyright (C) 2014 Orange Labs * http://www.orange.com * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_ISIS_MPLS_TE_H #define _ZEBRA_ISIS_MPLS_TE_H /* * Traffic Engineering information are transport through LSP: * - Extended IS Reachability TLV = 22 * - Traffic Engineering Router ID TLV = 134 * - Extended IP Reachability TLV = 135 * - Inter-AS Reachability Information TLV = 141 * * and support following sub-TLV: * * Name Value Status * _________________________________________________ * Administartive group (color) 3 RFC5305 * Link Local/Remote Identifiers 4 RFC5307 * IPv4 interface address 6 RFC5305 * IPv4 neighbor address 8 RFC5305 * Maximum link bandwidth 9 RFC5305 * Reservable link bandwidth 10 RFC5305 * Unreserved bandwidth 11 RFC5305 * TE Default metric 18 RFC5305 * Link Protection Type 20 RFC5307 * Interface Switching Capability 21 RFC5307 * Remote AS number 24 RFC5316 * IPv4 Remote ASBR identifier 25 RFC5316 * */ /* NOTE: RFC5316 is not yet supported in this version */ /* Following define the type of TE link regarding the various RFC */ #define STD_TE 0x01 #define GMPLS 0x02 #define INTER_AS 0x04 #define FLOOD_L1 0x10 #define FLOOD_L2 0x20 #define FLOOD_AS 0x40 #define EMULATED 0x80 #define IS_STD_TE(x) (x & STD_TE) #define IS_INTER_AS(x) (x & INTER_AS) #define IS_EMULATED(x) (x & EMULATED) #define IS_FLOOD_L1(x) (x & FLOOD_L1) #define IS_FLOOD_L2(x) (x & FLOOD_L2) #define IS_FLOOD_AS(x) (x & FLOOD_AS) #define IS_INTER_AS_EMU(x) (x & INTER_AS & EMULATED) #define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) /* * Following section defines subTLV (tag, length, value) structures, * used for Traffic Engineering. */ struct subtlv_header { u_char type; /* sub_TLV_XXX type (see above) */ u_char length; /* Value portion only, in byte */ }; #define SUBTLV_HDR_SIZE 2 /* (sizeof (struct sub_tlv_header)) */ #define SUBTLV_SIZE(stlvh) (SUBTLV_HDR_SIZE + (stlvh)->length) #define SUBTLV_HDR_TOP(lsph) (struct subtlv_header *)((char *)(lsph) + ISIS_LSP_HEADER_SIZE) #define SUBTLV_HDR_NEXT(stlvh) (struct subtlv_header *)((char *)(stlvh) + SUBTLV_SIZE(stlvh)) #define SUBTLV_TYPE(stlvh) stlvh.header.type #define SUBTLV_LEN(stlvh) stlvh.header.length #define SUBTLV_VAL(stlvh) stlvh.value #define SUBTLV_DATA(stlvh) stlvh + SUBTLV_HDR_SIZE #define SUBTLV_DEF_SIZE 4 /* Link Sub-TLV: Resource Class/Color - RFC 5305 */ #define TE_SUBTLV_ADMIN_GRP 3 struct te_subtlv_admin_grp { struct subtlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Admin. group membership. */ } __attribute__((__packed__)); /* Link Local/Remote Identifiers - RFC 5307 */ #define TE_SUBTLV_LLRI 4 #define TE_SUBTLV_LLRI_SIZE 8 struct te_subtlv_llri { struct subtlv_header header; /* Value length is 8 octets. */ u_int32_t local; /* Link Local Identifier */ u_int32_t remote; /* Link Remote Identifier */ } __attribute__((__packed__)); /* Link Sub-TLV: Local Interface IP Address - RFC 5305 */ #define TE_SUBTLV_LOCAL_IPADDR 6 struct te_subtlv_local_ipaddr { struct subtlv_header header; /* Value length is 4 x N octets. */ struct in_addr value; /* Local IP address(es). */ } __attribute__((__packed__)); /* Link Sub-TLV: Neighbor Interface IP Address - RFC 5305 */ #define TE_SUBTLV_RMT_IPADDR 8 struct te_subtlv_rmt_ipaddr { struct subtlv_header header; /* Value length is 4 x N octets. */ struct in_addr value; /* Neighbor's IP address(es). */ } __attribute__((__packed__)); /* Link Sub-TLV: Maximum Bandwidth - RFC 5305 */ #define TE_SUBTLV_MAX_BW 9 struct te_subtlv_max_bw { struct subtlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ } __attribute__((__packed__)); /* Link Sub-TLV: Maximum Reservable Bandwidth - RFC 5305 */ #define TE_SUBTLV_MAX_RSV_BW 10 struct te_subtlv_max_rsv_bw { struct subtlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ } __attribute__((__packed__)); /* Link Sub-TLV: Unreserved Bandwidth - RFC 5305 */ #define TE_SUBTLV_UNRSV_BW 11 #define TE_SUBTLV_UNRSV_SIZE 32 struct te_subtlv_unrsv_bw { struct subtlv_header header; /* Value length is 32 octets. */ float value[8]; /* One for each priority level. */ } __attribute__((__packed__)); /* Link Sub-TLV: Traffic Engineering Metric - RFC 5305 */ #define TE_SUBTLV_TE_METRIC 18 #define TE_SUBTLV_TE_METRIC_SIZE 3 struct te_subtlv_te_metric { struct subtlv_header header; /* Value length is 4 octets. */ u_char value[3]; /* Link metric for TE purpose. */ } __attribute__((__packed__)); /* Remote AS Number sub-TLV - RFC5316 */ #define TE_SUBTLV_RAS 24 struct te_subtlv_ras { struct subtlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Remote AS number */ } __attribute__((__packed__)); /* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */ #define TE_SUBTLV_RIP 25 struct te_subtlv_rip { struct subtlv_header header; /* Value length is 4 octets. */ struct in_addr value; /* Remote ASBR IP address */ } __attribute__((__packed__)); /* draft-ietf-isis-te-metric-extensions-11.txt */ /* Link Sub-TLV: Average Link Delay */ #define TE_SUBTLV_AV_DELAY 33 struct te_subtlv_av_delay { struct subtlv_header header; /* Value length is 4 bytes. */ u_int32_t value; /* Average delay in micro-seconds only 24 bits => 0 ... 16777215 with Anomalous Bit (A) as Upper most bit */ } __attribute__((__packed__)); /* Link Sub-TLV: Low/High Link Delay */ #define TE_SUBTLV_MM_DELAY 34 #define TE_SUBTLV_MM_DELAY_SIZE 8 struct te_subtlv_mm_delay { struct subtlv_header header; /* Value length is 8 bytes. */ u_int32_t low; /* low delay in micro-seconds only 24 bits => 0 ... 16777215 with Anomalous Bit (A) as Upper most bit */ u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */ } __attribute__((__packed__)); /* Link Sub-TLV: Link Delay Variation i.e. Jitter */ #define TE_SUBTLV_DELAY_VAR 35 struct te_subtlv_delay_var { struct subtlv_header header; /* Value length is 4 bytes. */ u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ... 16777215 */ } __attribute__((__packed__)); /* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ #define TE_SUBTLV_PKT_LOSS 36 struct te_subtlv_pkt_loss { struct subtlv_header header; /* Value length is 4 bytes. */ u_int32_t value; /* in percentage of total traffic only 24 bits (2^24 - 2) with Anomalous Bit (A) as Upper most bit */ } __attribute__((__packed__)); /* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ #define TE_SUBTLV_RES_BW 37 struct te_subtlv_res_bw { struct subtlv_header header; /* Value length is 4 bytes. */ float value; /* bandwidth in IEEE floating point format with units in bytes per second */ } __attribute__((__packed__)); /* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ #define TE_SUBTLV_AVA_BW 38 struct te_subtlv_ava_bw { struct subtlv_header header; /* Value length is 4 octets. */ float value; /* bandwidth in IEEE floating point format with units in bytes per second */ } __attribute__((__packed__)); /* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ #define TE_SUBTLV_USE_BW 39 struct te_subtlv_use_bw { struct subtlv_header header; /* Value length is 4 octets. */ float value; /* bandwidth in IEEE floating point format with units in bytes per second */ } __attribute__((__packed__)); #define TE_SUBTLV_MAX 40 /* Last SUBTLV + 1 */ /* Following declaration concerns the MPLS-TE and LINk-TE management */ typedef enum _status_t { disable, enable, learn } status_t; /* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */ typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t; #define IS_MPLS_TE(m) (m.status == enable) #define IS_CIRCUIT_TE(c) (c->status == enable) /* Following structure are internal use only. */ struct isis_mpls_te { /* Status of MPLS-TE: enable or disable */ status_t status; /* L1, L1-L2, L2-Only */ u_int8_t level; /* RFC5316 */ interas_mode_t inter_as; struct in_addr interas_areaid; /* Circuit list on which TE are enable */ struct list *cir_list; /* MPLS_TE router ID */ struct in_addr router_id; }; extern struct isis_mpls_te isisMplsTE; struct mpls_te_circuit { /* Status of MPLS-TE on this interface */ status_t status; /* Type of MPLS-TE circuit: STD_TE(RFC5305), INTER_AS(RFC5316), INTER_AS_EMU(RFC5316 emulated) */ u_int8_t type; /* Total size of sub_tlvs */ u_char length; /* Store subTLV in network byte order. */ /* RFC5305 */ struct te_subtlv_admin_grp admin_grp; /* RFC5307 */ struct te_subtlv_llri llri; /* RFC5305 */ struct te_subtlv_local_ipaddr local_ipaddr; struct te_subtlv_rmt_ipaddr rmt_ipaddr; struct te_subtlv_max_bw max_bw; struct te_subtlv_max_rsv_bw max_rsv_bw; struct te_subtlv_unrsv_bw unrsv_bw; struct te_subtlv_te_metric te_metric; /* RFC5316 */ struct te_subtlv_ras ras; struct te_subtlv_rip rip; /* draft-ietf-isis-te-metric-extension */ struct te_subtlv_av_delay av_delay; struct te_subtlv_mm_delay mm_delay; struct te_subtlv_delay_var delay_var; struct te_subtlv_pkt_loss pkt_loss; struct te_subtlv_res_bw res_bw; struct te_subtlv_ava_bw ava_bw; struct te_subtlv_use_bw use_bw; }; /* Prototypes. */ void isis_mpls_te_init (void); struct mpls_te_circuit *mpls_te_circuit_new(void); void mpls_te_print_detail(struct vty *, struct te_is_neigh *); void set_circuitparams_local_ipaddr (struct mpls_te_circuit *, struct in_addr); void set_circuitparams_rmt_ipaddr (struct mpls_te_circuit *, struct in_addr); u_char subtlvs_len (struct mpls_te_circuit *); u_char add_te_subtlvs(u_char *, struct mpls_te_circuit *); u_char build_te_subtlvs(u_char *, struct isis_circuit *); void isis_link_params_update(struct isis_circuit *, struct interface *); void isis_mpls_te_update(struct interface *); void isis_mpls_te_config_write_router (struct vty *); #endif /* _ZEBRA_ISIS_MPLS_TE_H */ quagga-1.2.4/isisd/isis_tlv.c000066400000000000000000001105561325323223500161060ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_tlv.c * IS-IS TLV related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "log.h" #include "linklist.h" #include "stream.h" #include "memory.h" #include "prefix.h" #include "vty.h" #include "if.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" #include "isisd/isis_pdu.h" #include "isisd/isis_lsp.h" #include "isisd/isis_te.h" void free_tlv (void *val) { XFREE (MTYPE_ISIS_TLV, val); return; } /* * Called after parsing of a PDU. There shouldn't be any tlv's left, so this * is only a caution to avoid memory leaks */ void free_tlvs (struct tlvs *tlvs) { if (tlvs->area_addrs) list_delete (tlvs->area_addrs); if (tlvs->is_neighs) list_delete (tlvs->is_neighs); if (tlvs->te_is_neighs) list_delete (tlvs->te_is_neighs); if (tlvs->es_neighs) list_delete (tlvs->es_neighs); if (tlvs->lsp_entries) list_delete (tlvs->lsp_entries); if (tlvs->prefix_neighs) list_delete (tlvs->prefix_neighs); if (tlvs->lan_neighs) list_delete (tlvs->lan_neighs); if (tlvs->ipv4_addrs) list_delete (tlvs->ipv4_addrs); if (tlvs->ipv4_int_reachs) list_delete (tlvs->ipv4_int_reachs); if (tlvs->ipv4_ext_reachs) list_delete (tlvs->ipv4_ext_reachs); if (tlvs->te_ipv4_reachs) list_delete (tlvs->te_ipv4_reachs); #ifdef HAVE_IPV6 if (tlvs->ipv6_addrs) list_delete (tlvs->ipv6_addrs); if (tlvs->ipv6_reachs) list_delete (tlvs->ipv6_reachs); #endif /* HAVE_IPV6 */ memset (tlvs, 0, sizeof (struct tlvs)); return; } /* * Parses the tlvs found in the variant length part of the PDU. * Caller tells with flags in "expected" which TLV's it is interested in. */ int parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset) { u_char type, length; struct lan_neigh *lan_nei; struct area_addr *area_addr; struct is_neigh *is_nei; struct te_is_neigh *te_is_nei; struct es_neigh *es_nei; struct lsp_entry *lsp_entry; struct in_addr *ipv4_addr; struct ipv4_reachability *ipv4_reach; struct te_ipv4_reachability *te_ipv4_reach; #ifdef HAVE_IPV6 struct in6_addr *ipv6_addr; struct ipv6_reachability *ipv6_reach; int prefix_octets; #endif /* HAVE_IPV6 */ int value_len, retval = ISIS_OK; u_char *start = stream, *pnt = stream, *endpnt; *found = 0; memset (tlvs, 0, sizeof (struct tlvs)); while (pnt < stream + size - 2) { type = *pnt; length = *(pnt + 1); pnt += 2; value_len = 0; if (pnt + length > stream + size) { zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet " "boundaries", areatag, type, length); retval = ISIS_WARNING; break; } switch (type) { case AREA_ADDRESSES: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Address Length | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Area Address | * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_AREA_ADDRS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("TLV Area Adresses len %d", length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_AREA_ADDRS) { while (length > value_len) { area_addr = (struct area_addr *) pnt; value_len += area_addr->addr_len + 1; pnt += area_addr->addr_len + 1; if (!tlvs->area_addrs) tlvs->area_addrs = list_new (); listnode_add (tlvs->area_addrs, area_addr); } } else { pnt += length; } break; case IS_NEIGHBOURS: *found |= TLVFLAG_IS_NEIGHS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (TLVFLAG_IS_NEIGHS & *expected) { /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Virtual Flag | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ pnt++; value_len++; /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | I/E | Default Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Delay Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Expense Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Error Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Neighbour ID | * +---------------------------------------------------------------+ * : : */ while (length > value_len) { is_nei = (struct is_neigh *) pnt; value_len += 4 + ISIS_SYS_ID_LEN + 1; pnt += 4 + ISIS_SYS_ID_LEN + 1; if (!tlvs->is_neighs) tlvs->is_neighs = list_new (); listnode_add (tlvs->is_neighs, is_nei); } } else { pnt += length; } break; case TE_IS_NEIGHBOURS: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Neighbour ID | 7 * +---------------------------------------------------------------+ * | TE Metric | 3 * +---------------------------------------------------------------+ * | SubTLVs Length | 1 * +---------------------------------------------------------------+ * : : */ *found |= TLVFLAG_TE_IS_NEIGHS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (TLVFLAG_TE_IS_NEIGHS & *expected) { while (length > value_len) { te_is_nei = (struct te_is_neigh *) pnt; value_len += IS_NEIGHBOURS_LEN; pnt += IS_NEIGHBOURS_LEN; /* FIXME - subtlvs are handled here, for now we skip */ /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */ /* So, it must be copied in a new te_is_neigh structure */ /* rather than just initialize pointer to the original LSP PDU */ /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */ if (IS_MPLS_TE(isisMplsTE)) { struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh)); memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1); memcpy(new->te_metric, te_is_nei->te_metric, 3); new->sub_tlvs_length = te_is_nei->sub_tlvs_length; memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length); te_is_nei = new; } /* Skip SUB TLVs payload */ value_len += te_is_nei->sub_tlvs_length; pnt += te_is_nei->sub_tlvs_length; if (!tlvs->te_is_neighs) tlvs->te_is_neighs = list_new (); listnode_add (tlvs->te_is_neighs, te_is_nei); } } else { pnt += length; } break; case ES_NEIGHBOURS: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | I/E | Default Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Delay Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Expense Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Error Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Neighbour ID | * +---------------------------------------------------------------+ * | Neighbour ID | * +---------------------------------------------------------------+ * : : */ #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ *found |= TLVFLAG_ES_NEIGHS; if (*expected & TLVFLAG_ES_NEIGHS) { es_nei = (struct es_neigh *) pnt; value_len += 4; pnt += 4; while (length > value_len) { /* FIXME FIXME FIXME - add to the list */ /* sys_id->id = pnt; */ value_len += ISIS_SYS_ID_LEN; pnt += ISIS_SYS_ID_LEN; /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */ } if (!tlvs->es_neighs) tlvs->es_neighs = list_new (); listnode_add (tlvs->es_neighs, es_nei); } else { pnt += length; } break; case LAN_NEIGHBOURS: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | LAN Address | * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_LAN_NEIGHS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (TLVFLAG_LAN_NEIGHS & *expected) { while (length > value_len) { lan_nei = (struct lan_neigh *) pnt; if (!tlvs->lan_neighs) tlvs->lan_neighs = list_new (); listnode_add (tlvs->lan_neighs, lan_nei); value_len += ETH_ALEN; pnt += ETH_ALEN; } } else { pnt += length; } break; case PADDING: #ifdef EXTREME_TLV_DEBUG zlog_debug ("TLV padding %d", length); #endif /* EXTREME_TLV_DEBUG */ pnt += length; break; case LSP_ENTRIES: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Remaining Lifetime | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | LSP ID | id+2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | LSP Sequence Number | 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Checksum | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ *found |= TLVFLAG_LSP_ENTRIES; if (TLVFLAG_LSP_ENTRIES & *expected) { while (length > value_len) { lsp_entry = (struct lsp_entry *) pnt; value_len += 10 + ISIS_SYS_ID_LEN; pnt += 10 + ISIS_SYS_ID_LEN; if (!tlvs->lsp_entries) tlvs->lsp_entries = list_new (); listnode_add (tlvs->lsp_entries, lsp_entry); } } else { pnt += length; } break; case CHECKSUM: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 16 bit fletcher CHECKSUM | * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_CHECKSUM; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_CHECKSUM) { tlvs->checksum = (struct checksum *) pnt; } pnt += length; break; case PROTOCOLS_SUPPORTED: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | NLPID | * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_NLPID; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_NLPID) { tlvs->nlpids = (struct nlpids *) (pnt - 1); } pnt += length; break; case IPV4_ADDR: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * + IP version 4 address + 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_IPV4_ADDR; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV4_ADDR) { while (length > value_len) { ipv4_addr = (struct in_addr *) pnt; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag, inet_ntoa (*ipv4_addr), pnt); #endif /* EXTREME_TLV_DEBUG */ if (!tlvs->ipv4_addrs) tlvs->ipv4_addrs = list_new (); listnode_add (tlvs->ipv4_addrs, ipv4_addr); value_len += 4; pnt += 4; } } else { pnt += length; } break; case AUTH_INFO: *found |= TLVFLAG_AUTH_INFO; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information", areatag); #endif if (*expected & TLVFLAG_AUTH_INFO) { tlvs->auth_info.type = *pnt; if (length == 0) { zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) " "incorrect.", areatag, type, length); return ISIS_WARNING; } --length; tlvs->auth_info.len = length; pnt++; memcpy (tlvs->auth_info.passwd, pnt, length); /* Return the authentication tlv pos for later computation * of MD5 (RFC 5304, 2) */ if (auth_tlv_offset) *auth_tlv_offset += (pnt - start - 3); pnt += length; } else { pnt += length; } break; case DYNAMIC_HOSTNAME: *found |= TLVFLAG_DYN_HOSTNAME; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_DYN_HOSTNAME) { /* the length is also included in the pointed struct */ tlvs->hostname = (struct hostname *) (pnt - 1); } pnt += length; break; case TE_ROUTER_ID: /* +---------------------------------------------------------------+ * + Router ID + 4 * +---------------------------------------------------------------+ */ *found |= TLVFLAG_TE_ROUTER_ID; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_TE_ROUTER_ID) tlvs->router_id = (struct te_router_id *) (pnt); pnt += length; break; case IPV4_INT_REACHABILITY: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | I/E | Default Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Delay Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Expense Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Error Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | ip address | 4 * +---------------------------------------------------------------+ * | address mask | 4 * +---------------------------------------------------------------+ * : : */ *found |= TLVFLAG_IPV4_INT_REACHABILITY; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV4_INT_REACHABILITY) { while (length > value_len) { ipv4_reach = (struct ipv4_reachability *) pnt; if (!tlvs->ipv4_int_reachs) tlvs->ipv4_int_reachs = list_new (); listnode_add (tlvs->ipv4_int_reachs, ipv4_reach); value_len += 12; pnt += 12; } } else { pnt += length; } break; case IPV4_EXT_REACHABILITY: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | I/E | Default Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Delay Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Expense Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Error Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | ip address | 4 * +---------------------------------------------------------------+ * | address mask | 4 * +---------------------------------------------------------------+ * : : */ *found |= TLVFLAG_IPV4_EXT_REACHABILITY; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY) { while (length > value_len) { ipv4_reach = (struct ipv4_reachability *) pnt; if (!tlvs->ipv4_ext_reachs) tlvs->ipv4_ext_reachs = list_new (); listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach); value_len += 12; pnt += 12; } } else { pnt += length; } break; case TE_IPV4_REACHABILITY: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | TE Metric | 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | U/D | sTLV? | Prefix Mask Len | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Prefix | 0-4 * +---------------------------------------------------------------+ * | sub tlvs | * +---------------------------------------------------------------+ * : : */ *found |= TLVFLAG_TE_IPV4_REACHABILITY; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ endpnt = pnt + length; if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) { while (length > value_len) { te_ipv4_reach = (struct te_ipv4_reachability *) pnt; if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN) { zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach" "ability prefix length %d", areatag, te_ipv4_reach->control & 0x3F); retval = ISIS_WARNING; break; } if (!tlvs->te_ipv4_reachs) tlvs->te_ipv4_reachs = list_new (); listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach); /* this trickery is permitable since no subtlvs are defined */ value_len += 5 + ((te_ipv4_reach->control & 0x3F) ? ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0); pnt += 5 + ((te_ipv4_reach->control & 0x3F) ? ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0); } } pnt = endpnt; break; #ifdef HAVE_IPV6 case IPV6_ADDR: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * + IP version 6 address + 16 * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_IPV6_ADDR; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV6_ADDR) { while (length > value_len) { ipv6_addr = (struct in6_addr *) pnt; if (!tlvs->ipv6_addrs) tlvs->ipv6_addrs = list_new (); listnode_add (tlvs->ipv6_addrs, ipv6_addr); value_len += 16; pnt += 16; } } else { pnt += length; } break; case IPV6_REACHABILITY: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Default Metric | 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Control Informantion | * +---------------------------------------------------------------+ * | IPv6 Prefix Length |--+ * +---------------------------------------------------------------+ | * | IPv6 Prefix |<-+ * +---------------------------------------------------------------+ */ *found |= TLVFLAG_IPV6_REACHABILITY; endpnt = pnt + length; if (*expected & TLVFLAG_IPV6_REACHABILITY) { while (length > value_len) { ipv6_reach = (struct ipv6_reachability *) pnt; if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN) { zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach" "ability prefix length %d", areatag, ipv6_reach->prefix_len); retval = ISIS_WARNING; break; } prefix_octets = ((ipv6_reach->prefix_len + 7) / 8); value_len += prefix_octets + 6; pnt += prefix_octets + 6; /* FIXME: sub-tlvs */ if (!tlvs->ipv6_reachs) tlvs->ipv6_reachs = list_new (); listnode_add (tlvs->ipv6_reachs, ipv6_reach); } } pnt = endpnt; break; #endif /* HAVE_IPV6 */ case WAY3_HELLO: /* +---------------------------------------------------------------+ * | Adjacency state | 1 * +---------------------------------------------------------------+ * | Extended Local Circuit ID | 4 * +---------------------------------------------------------------+ * | Neighbor System ID (If known) | 0-8 * (probably 6) * +---------------------------------------------------------------+ * | Neighbor Local Circuit ID (If known) | 4 * +---------------------------------------------------------------+ */ *found |= TLVFLAG_3WAY_HELLO; if (*expected & TLVFLAG_3WAY_HELLO) { while (length > value_len) { /* FIXME: make this work */ /* Adjacency State (one octet): 0 = Up 1 = Initializing 2 = Down Extended Local Circuit ID (four octets) Neighbor System ID if known (zero to eight octets) Neighbor Extended Local Circuit ID (four octets, if Neighbor System ID is present) */ pnt += length; value_len += length; } } else { pnt += length; } break; case GRACEFUL_RESTART: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved | SA | RA | RR | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Remaining Time | 2 * +---------------------------------------------------------------+ * | Restarting Neighbor ID (If known) | 0-8 * +---------------------------------------------------------------+ */ *found |= TLVFLAG_GRACEFUL_RESTART; if (*expected & TLVFLAG_GRACEFUL_RESTART) { /* FIXME: make this work */ } pnt += length; break; default: zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d", areatag, type, length); pnt += length; break; } } return retval; } int add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream) { if ((stream_get_size (stream) - stream_get_endp (stream)) < (((unsigned)len) + 2)) { zlog_warn ("No room for TLV of type %d " "(total size %d available %d required %d)", tag, (int)stream_get_size (stream), (int)(stream_get_size (stream) - stream_get_endp (stream)), len+2); return ISIS_WARNING; } stream_putc (stream, tag); /* TAG */ stream_putc (stream, len); /* LENGTH */ stream_put (stream, value, (int) len); /* VALUE */ #ifdef EXTREME_DEBUG zlog_debug ("Added TLV %d len %d", tag, len); #endif /* EXTREME DEBUG */ return ISIS_OK; } int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream) { struct listnode *node; struct area_addr *area_addr; u_char value[255]; u_char *pos = value; for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr)) { if (pos - value + area_addr->addr_len > 255) goto err; *pos = area_addr->addr_len; pos++; memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len); pos += area_addr->addr_len; } return add_tlv (AREA_ADDRESSES, pos - value, value, stream); err: zlog_warn ("tlv_add_area_addrs(): TLV longer than 255"); return ISIS_WARNING; } int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream) { struct listnode *node; struct is_neigh *is_neigh; u_char value[255]; u_char *pos = value; int retval; *pos = 0; /*is_neigh->virtual; */ pos++; for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh)) { if (pos - value + IS_NEIGHBOURS_LEN > 255) { retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *pos = is_neigh->metrics.metric_default; pos++; *pos = is_neigh->metrics.metric_delay; pos++; *pos = is_neigh->metrics.metric_expense; pos++; *pos = is_neigh->metrics.metric_error; pos++; memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1); pos += ISIS_SYS_ID_LEN + 1; } return add_tlv (IS_NEIGHBOURS, pos - value, value, stream); } int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) { struct listnode *node; struct te_is_neigh *te_is_neigh; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh)) { /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */ if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255) { retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1); pos += ISIS_SYS_ID_LEN + 1; memcpy (pos, te_is_neigh->te_metric, 3); pos += 3; /* Set the total size of Sub TLVs */ *pos = te_is_neigh->sub_tlvs_length; pos++; /* Copy Sub TLVs if any */ if (te_is_neigh->sub_tlvs_length > 0) { memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length); pos += te_is_neigh->sub_tlvs_length; } } return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); } int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream) { struct listnode *node; u_char *snpa; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa)) { if (pos - value + ETH_ALEN > 255) { retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } memcpy (pos, snpa, ETH_ALEN); pos += ETH_ALEN; } return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream); } int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream) { return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream); } int tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value, struct stream *stream) { u_char value[255]; u_char *pos = value; *pos++ = auth_type; memcpy (pos, auth_value, auth_len); return add_tlv (AUTH_INFO, auth_len + 1, value, stream); } int tlv_add_checksum (struct checksum *checksum, struct stream *stream) { u_char value[255]; u_char *pos = value; return add_tlv (CHECKSUM, pos - value, value, stream); } int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream) { struct listnode *node; struct prefix_ipv4 *ipv4; u_char value[255]; u_char *pos = value; for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4)) { if (pos - value + IPV4_MAX_BYTELEN > 255) { /* RFC 1195 s4.2: only one tuple of 63 allowed. */ zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses"); break; } *(u_int32_t *) pos = ipv4->prefix.s_addr; pos += IPV4_MAX_BYTELEN; } return add_tlv (IPV4_ADDR, pos - value, value, stream); } /* Used to add TLV containing just one IPv4 address - either IPv4 address TLV * (in case of LSP) or TE router ID TLV. */ int tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag) { u_char value[255]; u_char *pos = value; memcpy (pos, addr, IPV4_MAX_BYTELEN); pos += IPV4_MAX_BYTELEN; return add_tlv (tag, pos - value, value, stream); } int tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream) { return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name, stream); } int tlv_add_lsp_entries (struct list *lsps, struct stream *stream) { struct listnode *node; struct isis_lsp *lsp; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp)) { if (pos - value + LSP_ENTRIES_LEN > 255) { retval = add_tlv (LSP_ENTRIES, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime; pos += 2; memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2); pos += ISIS_SYS_ID_LEN + 2; *((u_int32_t *) pos) = lsp->lsp_header->seq_num; pos += 4; *((u_int16_t *) pos) = lsp->lsp_header->checksum; pos += 2; } return add_tlv (LSP_ENTRIES, pos - value, value, stream); } static int tlv_add_ipv4_reachs (u_char tag, struct list *ipv4_reachs, struct stream *stream) { struct listnode *node; struct ipv4_reachability *reach; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach)) { if (pos - value + IPV4_REACH_LEN > 255) { retval = add_tlv (tag, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *pos = reach->metrics.metric_default; pos++; *pos = reach->metrics.metric_delay; pos++; *pos = reach->metrics.metric_expense; pos++; *pos = reach->metrics.metric_error; pos++; *(u_int32_t *) pos = reach->prefix.s_addr; pos += IPV4_MAX_BYTELEN; *(u_int32_t *) pos = reach->mask.s_addr; pos += IPV4_MAX_BYTELEN; } return add_tlv (tag, pos - value, value, stream); } int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream) { return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream); } int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream) { return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream); } int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream) { struct listnode *node; struct te_ipv4_reachability *te_reach; u_char value[255]; u_char *pos = value; u_char prefix_size; int retval; for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach)) { prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1); if (pos - value + (5 + prefix_size) > 255) { retval = add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *(u_int32_t *) pos = te_reach->te_metric; pos += 4; *pos = te_reach->control; pos++; memcpy (pos, &te_reach->prefix_start, prefix_size); pos += prefix_size; } return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream); } #ifdef HAVE_IPV6 int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream) { struct listnode *node; struct prefix_ipv6 *ipv6; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6)) { if (pos - value + IPV6_MAX_BYTELEN > 255) { retval = add_tlv (IPV6_ADDR, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN); pos += IPV6_MAX_BYTELEN; } return add_tlv (IPV6_ADDR, pos - value, value, stream); } int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream) { struct listnode *node; struct ipv6_reachability *ip6reach; u_char value[255]; u_char *pos = value; int retval, prefix_octets; for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach)) { if (pos - value + IPV6_MAX_BYTELEN + 6 > 255) { retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *(uint32_t *) pos = ip6reach->metric; pos += 4; *pos = ip6reach->control_info; pos++; prefix_octets = ((ip6reach->prefix_len + 7) / 8); *pos = ip6reach->prefix_len; pos++; memcpy (pos, ip6reach->prefix, prefix_octets); pos += prefix_octets; } return add_tlv (IPV6_REACHABILITY, pos - value, value, stream); } #endif /* HAVE_IPV6 */ int tlv_add_padding (struct stream *stream) { int fullpads, i, left; /* * How many times can we add full padding ? */ fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257; for (i = 0; i < fullpads; i++) { if (!stream_putc (stream, (u_char) PADDING)) /* TAG */ goto err; if (!stream_putc (stream, (u_char) 255)) /* LENGHT */ goto err; stream_put (stream, NULL, 255); /* zero padding */ } left = stream_get_size (stream) - stream_get_endp (stream); if (left < 2) return ISIS_OK; if (left == 2) { stream_putc (stream, PADDING); stream_putc (stream, 0); return ISIS_OK; } stream_putc (stream, PADDING); stream_putc (stream, left - 2); stream_put (stream, NULL, left-2); return ISIS_OK; err: zlog_warn ("tlv_add_padding(): no room for tlv"); return ISIS_WARNING; } quagga-1.2.4/isisd/isis_tlv.h000066400000000000000000000264531325323223500161150ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_tlv.h * IS-IS TLV related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_TLV_H #define _ZEBRA_ISIS_TLV_H /* * The list of TLVs we (should) support. * ____________________________________________________________________________ * Name Value IIH LSP SNP Status * LAN * ____________________________________________________________________________ * * Area Addresses 1 y y n ISO10589 * IIS Neighbors 2 n y n ISO10589 * ES Neighbors 3 n y n ISO10589 * IIS Neighbors 6 y n n ISO10589 * Padding 8 y n n ISO10589 * LSP Entries 9 n n y ISO10589 * Authentication 10 y y y ISO10589, RFC3567 * Checksum 12 y n y RFC3358 * Extended IS Reachability 22 n y n RFC5305 * IS Alias 24 n y n RFC3786 * IP Int. Reachability 128 n y n RFC1195 * Protocols Supported 129 y y n RFC1195 * IP Ext. Reachability 130 n y n RFC1195 * IDRPI 131 n y y RFC1195 * IP Interface Address 132 y y n RFC1195 * TE Router ID 134 n y n RFC5305 * Extended IP Reachability 135 n y n RFC5305 * Dynamic Hostname 137 n y n RFC2763 * Shared Risk Link Group 138 n y y RFC5307 * Inter-AS Reachability 141 n y n RFC5316 * Restart TLV 211 y n n RFC3847 * MT IS Reachability 222 n y n RFC5120 * MT Supported 229 y y n RFC5120 * IPv6 Interface Address 232 y y n RFC5308 * MT IP Reachability 235 n y n RFC5120 * IPv6 IP Reachability 236 n y n RFC5308 * MT IPv6 IP Reachability 237 n y n RFC5120 * P2P Adjacency State 240 y n n RFC3373 * IIH Sequence Number 241 y n n draft-shen-isis-iih-sequence * Router Capability 242 n y n RFC4971 * * * IS Reachability sub-TLVs we support (See isis_te.[c,h]) * ____________________________________________________________________________ * Name Value Status * ____________________________________________________________________________ * Administartive group (color) 3 RFC5305 * Link Local/Remote Identifiers 4 RFC5307 * IPv4 interface address 6 RFC5305 * IPv4 neighbor address 8 RFC5305 * Maximum link bandwidth 9 RFC5305 * Reservable link bandwidth 10 RFC5305 * Unreserved bandwidth 11 RFC5305 * TE Default metric 18 RFC5305 * Link Protection Type 20 RFC5307 * Interface Switching Capability 21 RFC5307 * Remote AS number 24 RFC5316 * IPv4 Remote ASBR identifier 25 RFC5316 * * * IP Reachability sub-TLVs we (should) support. * ____________________________________________________________________________ * Name Value Status * ____________________________________________________________________________ * 32bit administrative tag 1 RFC5130 * 64bit administrative tag 2 RFC5130 * Management prefix color 117 RFC5120 */ #define AREA_ADDRESSES 1 #define IS_NEIGHBOURS 2 #define ES_NEIGHBOURS 3 #define LAN_NEIGHBOURS 6 #define PADDING 8 #define LSP_ENTRIES 9 #define AUTH_INFO 10 #define CHECKSUM 12 #define TE_IS_NEIGHBOURS 22 #define IS_ALIAS 24 #define IPV4_INT_REACHABILITY 128 #define PROTOCOLS_SUPPORTED 129 #define IPV4_EXT_REACHABILITY 130 #define IDRP_INFO 131 #define IPV4_ADDR 132 #define TE_ROUTER_ID 134 #define TE_IPV4_REACHABILITY 135 #define DYNAMIC_HOSTNAME 137 #define GRACEFUL_RESTART 211 #define IPV6_ADDR 232 #define IPV6_REACHABILITY 236 #define WAY3_HELLO 240 #define ROUTER_INFORMATION 242 #define AUTH_INFO_HDRLEN 3 #define MAX_TLV_LEN 255 #define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5) #define LAN_NEIGHBOURS_LEN 6 #define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */ #define IPV4_REACH_LEN 12 #define IPV6_REACH_LEN 22 #define TE_IPV4_REACH_LEN 9 #define MAX_SUBTLV_SIZE 256 /* struct for neighbor */ struct is_neigh { struct metric metrics; u_char neigh_id[ISIS_SYS_ID_LEN + 1]; }; /* struct for te metric */ struct te_is_neigh { u_char neigh_id[ISIS_SYS_ID_LEN + 1]; u_char te_metric[3]; u_char sub_tlvs_length; /* Theorical Maximum SubTLVs is 256 because the sub_tlvs_length is 8 bits */ /* Practically, 118 bytes are necessary to store all supported TE parameters */ /* FIXME: A pointer will use less memory, but need to be free */ /* which is hard to fix, especially within free_tlvs() function */ /* and malloc() / free() as a CPU cost compared to the memory usage */ u_char sub_tlvs[MAX_SUBTLV_SIZE]; /* SUB TLVs storage */ }; /* Decode and encode three-octet metric into host byte order integer */ #define GET_TE_METRIC(t) \ (((unsigned)(t)->te_metric[0]<<16) | ((t)->te_metric[1]<<8) | \ (t)->te_metric[2]) #define SET_TE_METRIC(t, m) \ (((t)->te_metric[0] = (m) >> 16), \ ((t)->te_metric[1] = (m) >> 8), \ ((t)->te_metric[2] = (m))) /* struct for es neighbors */ struct es_neigh { struct metric metrics; /* approximate position of first, we use the * length ((uchar*)metric-1) to know all */ u_char first_es_neigh[ISIS_SYS_ID_LEN]; }; struct partition_desig_level2_is { struct list *isis_system_ids; }; /* struct for lan neighbors */ struct lan_neigh { u_char LAN_addr[6]; }; #ifdef __SUNPRO_C #pragma pack(1) #endif /* struct for LSP entry */ struct lsp_entry { u_int16_t rem_lifetime; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; u_int32_t seq_num; u_int16_t checksum; } __attribute__ ((packed)); #ifdef __SUNPRO_C #pragma pack() #endif /* struct for checksum */ struct checksum { u_int16_t checksum; }; /* ipv4 reachability */ struct ipv4_reachability { struct metric metrics; struct in_addr prefix; struct in_addr mask; }; /* te router id */ struct te_router_id { struct in_addr id; }; /* te ipv4 reachability */ struct te_ipv4_reachability { u_int32_t te_metric; u_char control; u_char prefix_start; /* since this is variable length by nature it only */ }; /* points to an approximate location */ struct idrp_info { u_char len; u_char *value; }; #ifdef HAVE_IPV6 struct ipv6_reachability { u_int32_t metric; u_char control_info; u_char prefix_len; u_char prefix[16]; }; /* bits in control_info */ #define CTRL_INFO_DIRECTION 0x80 #define DIRECTION_UP 0x00 #define DIRECTION_DOWN 0x80 #define CTRL_INFO_DISTRIBUTION 0x40 #define DISTRIBUTION_INTERNAL 0x00 #define DISTRIBUTION_EXTERNAL 0x40 #define CTRL_INFO_SUBTLVS 0x20 #endif /* HAVE_IPV6 */ /* * Pointer to each tlv type, filled by parse_tlvs() */ struct tlvs { struct checksum *checksum; struct hostname *hostname; struct nlpids *nlpids; struct te_router_id *router_id; struct list *area_addrs; struct list *is_neighs; struct list *te_is_neighs; struct list *es_neighs; struct list *lsp_entries; struct list *prefix_neighs; struct list *lan_neighs; struct list *ipv4_addrs; struct list *ipv4_int_reachs; struct list *ipv4_ext_reachs; struct list *te_ipv4_reachs; #ifdef HAVE_IPV6 struct list *ipv6_addrs; struct list *ipv6_reachs; #endif struct isis_passwd auth_info; }; /* * Own definitions - used to bitmask found and expected */ #define TLVFLAG_AREA_ADDRS (1<<0) #define TLVFLAG_IS_NEIGHS (1<<1) #define TLVFLAG_ES_NEIGHS (1<<2) #define TLVFLAG_PARTITION_DESIG_LEVEL2_IS (1<<3) #define TLVFLAG_PREFIX_NEIGHS (1<<4) #define TLVFLAG_LAN_NEIGHS (1<<5) #define TLVFLAG_LSP_ENTRIES (1<<6) #define TLVFLAG_PADDING (1<<7) #define TLVFLAG_AUTH_INFO (1<<8) #define TLVFLAG_IPV4_INT_REACHABILITY (1<<9) #define TLVFLAG_NLPID (1<<10) #define TLVFLAG_IPV4_EXT_REACHABILITY (1<<11) #define TLVFLAG_IPV4_ADDR (1<<12) #define TLVFLAG_DYN_HOSTNAME (1<<13) #define TLVFLAG_IPV6_ADDR (1<<14) #define TLVFLAG_IPV6_REACHABILITY (1<<15) #define TLVFLAG_TE_IS_NEIGHS (1<<16) #define TLVFLAG_TE_IPV4_REACHABILITY (1<<17) #define TLVFLAG_3WAY_HELLO (1<<18) #define TLVFLAG_TE_ROUTER_ID (1<<19) #define TLVFLAG_CHECKSUM (1<<20) #define TLVFLAG_GRACEFUL_RESTART (1<<21) void init_tlvs (struct tlvs *tlvs, uint32_t expected); void free_tlvs (struct tlvs *tlvs); int parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs, u_int32_t * auth_tlv_offset); int add_tlv (u_char, u_char, u_char *, struct stream *); void free_tlv (void *val); int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream); int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream); int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream); int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream); int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream); int tlv_add_checksum (struct checksum *checksum, struct stream *stream); int tlv_add_authinfo (u_char auth_type, u_char authlen, u_char *auth_value, struct stream *stream); int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream); int tlv_add_in_addr (struct in_addr *, struct stream *stream, u_char tag); int tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream); int tlv_add_lsp_entries (struct list *lsps, struct stream *stream); int tlv_add_ipv4_int_reachs (struct list *ipv4_reachs, struct stream *stream); int tlv_add_ipv4_ext_reachs (struct list *ipv4_reachs, struct stream *stream); int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream); #ifdef HAVE_IPV6 int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream); int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream); #endif /* HAVE_IPV6 */ int tlv_add_padding (struct stream *stream); #endif /* _ZEBRA_ISIS_TLV_H */ quagga-1.2.4/isisd/isis_vty.c000066400000000000000000002055051325323223500161220ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_circuit.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * Copyright (C) 2016 David Lamparter, for NetDEF, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include #include "isis_circuit.h" #include "isis_csm.h" #include "isis_misc.h" #include "isisd.h" static struct isis_circuit * isis_circuit_lookup (struct vty *vty) { struct interface *ifp; struct isis_circuit *circuit; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return NULL; } circuit = circuit_scan_by_ifp (ifp); if (!circuit) { vty_out (vty, "ISIS is not enabled on circuit %s%s", ifp->name, VTY_NEWLINE); return NULL; } return circuit; } DEFUN (ip_router_isis, ip_router_isis_cmd, "(ip|ipv6) router isis WORD", "Interface Internet Protocol config commands\n" "IP router interface commands\n" "IS-IS Routing for IP\n" "Routing process tag\n") { struct interface *ifp; struct isis_circuit *circuit; struct isis_area *area; const char *af = argv[0]; const char *area_tag = argv[1]; ifp = (struct interface *) vty->index; assert (ifp); /* Prevent more than one area per circuit */ circuit = circuit_scan_by_ifp (ifp); if (circuit && circuit->area) { if (strcmp (circuit->area->area_tag, area_tag)) { vty_out (vty, "ISIS circuit is already defined on %s%s", circuit->area->area_tag, VTY_NEWLINE); return CMD_ERR_NOTHING_TODO; } } area = isis_area_lookup (area_tag); if (!area) area = isis_area_create (area_tag); if (!circuit || !circuit->area) { circuit = isis_circuit_create (area, ifp); if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP) { vty_out(vty, "Couldn't bring up interface, please check log.%s", VTY_NEWLINE); return CMD_WARNING; } } bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; if (af[2] != '\0') ipv6 = true; else ip = true; isis_circuit_af_set (circuit, ip, ipv6); return CMD_SUCCESS; } DEFUN (no_ip_router_isis, no_ip_router_isis_cmd, "no (ip|ipv6) router isis WORD", NO_STR "Interface Internet Protocol config commands\n" "IP router interface commands\n" "IS-IS Routing for IP\n" "Routing process tag\n") { struct interface *ifp; struct isis_area *area; struct isis_circuit *circuit; const char *af = argv[0]; const char *area_tag = argv[1]; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = isis_area_lookup (area_tag); if (!area) { vty_out (vty, "Can't find ISIS instance %s%s", argv[0], VTY_NEWLINE); return CMD_ERR_NO_MATCH; } circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); if (!circuit) { vty_out (vty, "ISIS is not enabled on circuit %s%s", ifp->name, VTY_NEWLINE); return CMD_ERR_NO_MATCH; } bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; if (af[2] != '\0') ipv6 = false; else ip = false; isis_circuit_af_set (circuit, ip, ipv6); return CMD_SUCCESS; } DEFUN (isis_passive, isis_passive_cmd, "isis passive", "IS-IS commands\n" "Configure the passive mode for interface\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; isis_circuit_passive_set (circuit, 1); return CMD_SUCCESS; } DEFUN (no_isis_passive, no_isis_passive_cmd, "no isis passive", NO_STR "IS-IS commands\n" "Configure the passive mode for interface\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; if (if_is_loopback (circuit->interface)) { vty_out (vty, "Can't set no passive for loopback interface%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_circuit_passive_set (circuit, 0); return CMD_SUCCESS; } DEFUN (isis_circuit_type, isis_circuit_type_cmd, "isis circuit-type (level-1|level-1-2|level-2-only)", "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { int is_type; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; is_type = string2circuit_t (argv[0]); if (!is_type) { vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } if (circuit->state == C_STATE_UP && circuit->area->is_type != IS_LEVEL_1_AND_2 && circuit->area->is_type != is_type) { vty_out (vty, "Invalid circuit level for area %s.%s", circuit->area->area_tag, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_circuit_is_type_set (circuit, is_type); return CMD_SUCCESS; } DEFUN (no_isis_circuit_type, no_isis_circuit_type_cmd, "no isis circuit-type (level-1|level-1-2|level-2-only)", NO_STR "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { int is_type; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; /* * Set the circuits level to its default value */ if (circuit->state == C_STATE_UP) is_type = circuit->area->is_type; else is_type = IS_LEVEL_1_AND_2; isis_circuit_is_type_set (circuit, is_type); return CMD_SUCCESS; } DEFUN (isis_network, isis_network_cmd, "isis network point-to-point", "IS-IS commands\n" "Set network type\n" "point-to-point network type\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) { vty_out (vty, "isis network point-to-point " "is valid only on broadcast interfaces%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } return CMD_SUCCESS; } DEFUN (no_isis_network, no_isis_network_cmd, "no isis network point-to-point", NO_STR "IS-IS commands\n" "Set network type for circuit\n" "point-to-point network type\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) { vty_out (vty, "isis network point-to-point " "is valid only on broadcast interfaces%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } return CMD_SUCCESS; } DEFUN (isis_passwd, isis_passwd_cmd, "isis password (md5|clear) WORD", "IS-IS commands\n" "Configure the authentication password for a circuit\n" "HMAC-MD5 authentication\n" "Cleartext password\n" "Circuit password\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); int rv; if (!circuit) return CMD_ERR_NO_MATCH; if (argv[0][0] == 'm') rv = isis_circuit_passwd_hmac_md5_set(circuit, argv[1]); else rv = isis_circuit_passwd_cleartext_set(circuit, argv[1]); if (rv) { vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } return CMD_SUCCESS; } DEFUN (no_isis_passwd, no_isis_passwd_cmd, "no isis password", NO_STR "IS-IS commands\n" "Configure the authentication password for a circuit\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; isis_circuit_passwd_unset(circuit); return CMD_SUCCESS; } ALIAS (no_isis_passwd, no_isis_passwd_arg_cmd, "no isis password (md5|clear) WORD", NO_STR "IS-IS commands\n" "Configure the authentication password for a circuit\n" "HMAC-MD5 authentication\n" "Cleartext password\n" "Circuit password\n") DEFUN (isis_priority, isis_priority_cmd, "isis priority <0-127>", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n") { int prio; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; prio = atoi (argv[0]); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out (vty, "Invalid priority %d - should be <0-127>%s", prio, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->priority[0] = prio; circuit->priority[1] = prio; return CMD_SUCCESS; } DEFUN (no_isis_priority, no_isis_priority_cmd, "no isis priority", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->priority[0] = DEFAULT_PRIORITY; circuit->priority[1] = DEFAULT_PRIORITY; return CMD_SUCCESS; } ALIAS (no_isis_priority, no_isis_priority_arg_cmd, "no isis priority <0-127>", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n") DEFUN (isis_priority_l1, isis_priority_l1_cmd, "isis priority <0-127> level-1", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-1 routing\n") { int prio; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; prio = atoi (argv[0]); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out (vty, "Invalid priority %d - should be <0-127>%s", prio, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->priority[0] = prio; return CMD_SUCCESS; } DEFUN (no_isis_priority_l1, no_isis_priority_l1_cmd, "no isis priority level-1", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Specify priority for level-1 routing\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->priority[0] = DEFAULT_PRIORITY; return CMD_SUCCESS; } ALIAS (no_isis_priority_l1, no_isis_priority_l1_arg_cmd, "no isis priority <0-127> level-1", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-1 routing\n") DEFUN (isis_priority_l2, isis_priority_l2_cmd, "isis priority <0-127> level-2", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-2 routing\n") { int prio; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; prio = atoi (argv[0]); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out (vty, "Invalid priority %d - should be <0-127>%s", prio, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->priority[1] = prio; return CMD_SUCCESS; } DEFUN (no_isis_priority_l2, no_isis_priority_l2_cmd, "no isis priority level-2", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Specify priority for level-2 routing\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->priority[1] = DEFAULT_PRIORITY; return CMD_SUCCESS; } ALIAS (no_isis_priority_l2, no_isis_priority_l2_arg_cmd, "no isis priority <0-127> level-2", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-2 routing\n") /* Metric command */ DEFUN (isis_metric, isis_metric_cmd, "isis metric <0-16777215>", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") { int met; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; met = atoi (argv[0]); /* RFC3787 section 5.1 */ if (circuit->area && circuit->area->oldmetric == 1 && met > MAX_NARROW_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } /* RFC4444 */ if (circuit->area && circuit->area->newmetric == 1 && met > MAX_WIDE_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_circuit_metric_set (circuit, IS_LEVEL_1, met); isis_circuit_metric_set (circuit, IS_LEVEL_2, met); return CMD_SUCCESS; } DEFUN (no_isis_metric, no_isis_metric_cmd, "no isis metric", NO_STR "IS-IS commands\n" "Set default metric for circuit\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; isis_circuit_metric_set (circuit, IS_LEVEL_1, DEFAULT_CIRCUIT_METRIC); isis_circuit_metric_set (circuit, IS_LEVEL_2, DEFAULT_CIRCUIT_METRIC); return CMD_SUCCESS; } ALIAS (no_isis_metric, no_isis_metric_arg_cmd, "no isis metric <0-16777215>", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") DEFUN (isis_metric_l1, isis_metric_l1_cmd, "isis metric <0-16777215> level-1", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-1 routing\n") { int met; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; met = atoi (argv[0]); /* RFC3787 section 5.1 */ if (circuit->area && circuit->area->oldmetric == 1 && met > MAX_NARROW_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } /* RFC4444 */ if (circuit->area && circuit->area->newmetric == 1 && met > MAX_WIDE_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_circuit_metric_set (circuit, IS_LEVEL_1, met); return CMD_SUCCESS; } DEFUN (no_isis_metric_l1, no_isis_metric_l1_cmd, "no isis metric level-1", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Specify metric for level-1 routing\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; isis_circuit_metric_set (circuit, IS_LEVEL_1, DEFAULT_CIRCUIT_METRIC); return CMD_SUCCESS; } ALIAS (no_isis_metric_l1, no_isis_metric_l1_arg_cmd, "no isis metric <0-16777215> level-1", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-1 routing\n") DEFUN (isis_metric_l2, isis_metric_l2_cmd, "isis metric <0-16777215> level-2", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-2 routing\n") { int met; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; met = atoi (argv[0]); /* RFC3787 section 5.1 */ if (circuit->area && circuit->area->oldmetric == 1 && met > MAX_NARROW_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } /* RFC4444 */ if (circuit->area && circuit->area->newmetric == 1 && met > MAX_WIDE_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_circuit_metric_set (circuit, IS_LEVEL_2, met); return CMD_SUCCESS; } DEFUN (no_isis_metric_l2, no_isis_metric_l2_cmd, "no isis metric level-2", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Specify metric for level-2 routing\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; isis_circuit_metric_set (circuit, IS_LEVEL_2, DEFAULT_CIRCUIT_METRIC); return CMD_SUCCESS; } ALIAS (no_isis_metric_l2, no_isis_metric_l2_arg_cmd, "no isis metric <0-16777215> level-2", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-2 routing\n") /* end of metrics */ DEFUN (isis_hello_interval, isis_hello_interval_cmd, "isis hello-interval <1-600>", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 seconds, interval depends on multiplier\n") { int interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atoi (argv[0]); if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_interval[0] = (u_int16_t) interval; circuit->hello_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_isis_hello_interval, no_isis_hello_interval_cmd, "no isis hello-interval", NO_STR "IS-IS commands\n" "Set Hello interval\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval, no_isis_hello_interval_arg_cmd, "no isis hello-interval <1-600>", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n") DEFUN (isis_hello_interval_l1, isis_hello_interval_l1_cmd, "isis hello-interval <1-600> level-1", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") { long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atoi (argv[0]); if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_interval[0] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_isis_hello_interval_l1, no_isis_hello_interval_l1_cmd, "no isis hello-interval level-1", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Specify hello-interval for level-1 IIHs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval_l1, no_isis_hello_interval_l1_arg_cmd, "no isis hello-interval <1-600> level-1", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") DEFUN (isis_hello_interval_l2, isis_hello_interval_l2_cmd, "isis hello-interval <1-600> level-2", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") { long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atoi (argv[0]); if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_isis_hello_interval_l2, no_isis_hello_interval_l2_cmd, "no isis hello-interval level-2", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Specify hello-interval for level-2 IIHs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval_l2, no_isis_hello_interval_l2_arg_cmd, "no isis hello-interval <1-600> level-2", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") DEFUN (isis_hello_multiplier, isis_hello_multiplier_cmd, "isis hello-multiplier <2-100>", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") { int mult; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; mult = atoi (argv[0]); if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", mult, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_multiplier[0] = (u_int16_t) mult; circuit->hello_multiplier[1] = (u_int16_t) mult; return CMD_SUCCESS; } DEFUN (no_isis_hello_multiplier, no_isis_hello_multiplier_cmd, "no isis hello-multiplier", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier, no_isis_hello_multiplier_arg_cmd, "no isis hello-multiplier <2-100>", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") DEFUN (isis_hello_multiplier_l1, isis_hello_multiplier_l1_cmd, "isis hello-multiplier <2-100> level-1", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") { int mult; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; mult = atoi (argv[0]); if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", mult, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_multiplier[0] = (u_int16_t) mult; return CMD_SUCCESS; } DEFUN (no_isis_hello_multiplier_l1, no_isis_hello_multiplier_l1_cmd, "no isis hello-multiplier level-1", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-1 IIHs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier_l1, no_isis_hello_multiplier_l1_arg_cmd, "no isis hello-multiplier <2-100> level-1", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") DEFUN (isis_hello_multiplier_l2, isis_hello_multiplier_l2_cmd, "isis hello-multiplier <2-100> level-2", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") { int mult; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; mult = atoi (argv[0]); if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", mult, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_multiplier[1] = (u_int16_t) mult; return CMD_SUCCESS; } DEFUN (no_isis_hello_multiplier_l2, no_isis_hello_multiplier_l2_cmd, "no isis hello-multiplier level-2", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-2 IIHs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier_l2, no_isis_hello_multiplier_l2_arg_cmd, "no isis hello-multiplier <2-100> level-2", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") DEFUN (isis_hello_padding, isis_hello_padding_cmd, "isis hello padding", "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->pad_hellos = 1; return CMD_SUCCESS; } DEFUN (no_isis_hello_padding, no_isis_hello_padding_cmd, "no isis hello padding", NO_STR "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->pad_hellos = 0; return CMD_SUCCESS; } DEFUN (csnp_interval, csnp_interval_cmd, "isis csnp-interval <1-600>", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->csnp_interval[0] = (u_int16_t) interval; circuit->csnp_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_csnp_interval, no_csnp_interval_cmd, "no isis csnp-interval", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval, no_csnp_interval_arg_cmd, "no isis csnp-interval <1-600>", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") DEFUN (csnp_interval_l1, csnp_interval_l1_cmd, "isis csnp-interval <1-600> level-1", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->csnp_interval[0] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_csnp_interval_l1, no_csnp_interval_l1_cmd, "no isis csnp-interval level-1", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "Specify interval for level-1 CSNPs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval_l1, no_csnp_interval_l1_arg_cmd, "no isis csnp-interval <1-600> level-1", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") DEFUN (csnp_interval_l2, csnp_interval_l2_cmd, "isis csnp-interval <1-600> level-2", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->csnp_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_csnp_interval_l2, no_csnp_interval_l2_cmd, "no isis csnp-interval level-2", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "Specify interval for level-2 CSNPs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval_l2, no_csnp_interval_l2_arg_cmd, "no isis csnp-interval <1-600> level-2", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") DEFUN (psnp_interval, psnp_interval_cmd, "isis psnp-interval <1-120>", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->psnp_interval[0] = (u_int16_t) interval; circuit->psnp_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_psnp_interval, no_psnp_interval_cmd, "no isis psnp-interval", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_psnp_interval, no_psnp_interval_arg_cmd, "no isis psnp-interval <1-120>", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n") DEFUN (psnp_interval_l1, psnp_interval_l1_cmd, "isis psnp-interval <1-120> level-1", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-1 PSNPs\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->psnp_interval[0] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_psnp_interval_l1, no_psnp_interval_l1_cmd, "no isis psnp-interval level-1", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "Specify interval for level-1 PSNPs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_psnp_interval_l1, no_psnp_interval_l1_arg_cmd, "no isis psnp-interval <1-120> level-1", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-1 PSNPs\n") DEFUN (psnp_interval_l2, psnp_interval_l2_cmd, "isis psnp-interval <1-120> level-2", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-2 PSNPs\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->psnp_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_psnp_interval_l2, no_psnp_interval_l2_cmd, "no isis psnp-interval level-2", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "Specify interval for level-2 PSNPs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_psnp_interval_l2, no_psnp_interval_l2_arg_cmd, "no isis psnp-interval <1-120> level-2", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-2 PSNPs\n") static int validate_metric_style_narrow (struct vty *vty, struct isis_area *area) { struct isis_circuit *circuit; struct listnode *node; if (! vty) return CMD_ERR_AMBIGUOUS; if (! area) { vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) { if ((area->is_type & IS_LEVEL_1) && (circuit->is_type & IS_LEVEL_1) && (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) { vty_out (vty, "ISIS circuit %s metric is invalid%s", circuit->interface->name, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } if ((area->is_type & IS_LEVEL_2) && (circuit->is_type & IS_LEVEL_2) && (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) { vty_out (vty, "ISIS circuit %s metric is invalid%s", circuit->interface->name, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } return CMD_SUCCESS; } DEFUN (metric_style, metric_style_cmd, "metric-style (narrow|transition|wide)", "Use old-style (ISO 10589) or new-style packet formats\n" "Use old style of TLVs with narrow metric\n" "Send and accept both styles of TLVs during transition\n" "Use new style of TLVs to carry wider metric\n") { struct isis_area *area = vty->index; int ret; assert(area); if (strncmp (argv[0], "w", 1) == 0) { isis_area_metricstyle_set(area, false, true); return CMD_SUCCESS; } ret = validate_metric_style_narrow (vty, area); if (ret != CMD_SUCCESS) return ret; if (strncmp (argv[0], "t", 1) == 0) isis_area_metricstyle_set(area, true, true); else if (strncmp (argv[0], "n", 1) == 0) isis_area_metricstyle_set(area, true, false); return CMD_SUCCESS; return CMD_SUCCESS; } DEFUN (no_metric_style, no_metric_style_cmd, "no metric-style", NO_STR "Use old-style (ISO 10589) or new-style packet formats\n") { struct isis_area *area = vty->index; int ret; assert (area); ret = validate_metric_style_narrow (vty, area); if (ret != CMD_SUCCESS) return ret; isis_area_metricstyle_set(area, true, false); return CMD_SUCCESS; } DEFUN (set_overload_bit, set_overload_bit_cmd, "set-overload-bit", "Set overload bit to avoid any transit traffic\n" "Set overload bit\n") { struct isis_area *area = vty->index; assert (area); isis_area_overload_bit_set(area, true); return CMD_SUCCESS; } DEFUN (no_set_overload_bit, no_set_overload_bit_cmd, "no set-overload-bit", "Reset overload bit to accept transit traffic\n" "Reset overload bit\n") { struct isis_area *area = vty->index; assert (area); isis_area_overload_bit_set(area, false); return CMD_SUCCESS; } DEFUN (set_attached_bit, set_attached_bit_cmd, "set-attached-bit", "Set attached bit to identify as L1/L2 router for inter-area traffic\n" "Set attached bit\n") { struct isis_area *area = vty->index; assert (area); isis_area_attached_bit_set(area, true); return CMD_SUCCESS; } DEFUN (no_set_attached_bit, no_set_attached_bit_cmd, "no set-attached-bit", "Reset attached bit\n") { struct isis_area *area = vty->index; assert (area); isis_area_attached_bit_set(area, false); return CMD_SUCCESS; } DEFUN (dynamic_hostname, dynamic_hostname_cmd, "hostname dynamic", "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") { struct isis_area *area = vty->index; assert(area); isis_area_dynhostname_set(area, true); return CMD_SUCCESS; } DEFUN (no_dynamic_hostname, no_dynamic_hostname_cmd, "no hostname dynamic", NO_STR "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") { struct isis_area *area = vty->index; assert(area); isis_area_dynhostname_set(area, false); return CMD_SUCCESS; } static int area_lsp_mtu_set(struct vty *vty, unsigned int lsp_mtu) { struct isis_area *area = vty->index; struct listnode *node; struct isis_circuit *circuit; if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { if(circuit->state != C_STATE_INIT && circuit->state != C_STATE_UP) continue; if(lsp_mtu > isis_circuit_pdu_size(circuit)) { vty_out(vty, "ISIS area contains circuit %s, which has a maximum PDU size of %zu.%s", circuit->interface->name, isis_circuit_pdu_size(circuit), VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } isis_area_lsp_mtu_set(area, lsp_mtu); return CMD_SUCCESS; } DEFUN (area_lsp_mtu, area_lsp_mtu_cmd, "lsp-mtu <128-4352>", "Configure the maximum size of generated LSPs\n" "Maximum size of generated LSPs\n") { unsigned int lsp_mtu; VTY_GET_INTEGER_RANGE("lsp-mtu", lsp_mtu, argv[0], 128, 4352); return area_lsp_mtu_set(vty, lsp_mtu); } DEFUN(no_area_lsp_mtu, no_area_lsp_mtu_cmd, "no lsp-mtu", NO_STR "Configure the maximum size of generated LSPs\n") { return area_lsp_mtu_set(vty, DEFAULT_LSP_MTU); } ALIAS(no_area_lsp_mtu, no_area_lsp_mtu_arg_cmd, "no lsp-mtu <128-4352>", NO_STR "Configure the maximum size of generated LSPs\n" "Maximum size of generated LSPs\n"); DEFUN (is_type, is_type_cmd, "is-type (level-1|level-1-2|level-2-only)", "IS Level for this routing process (OSI only)\n" "Act as a station router only\n" "Act as both a station router and an area router\n" "Act as an area router only\n") { struct isis_area *area; int type; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } type = string2circuit_t (argv[0]); if (!type) { vty_out (vty, "Unknown IS level %s", VTY_NEWLINE); return CMD_SUCCESS; } isis_area_is_type_set(area, type); return CMD_SUCCESS; } DEFUN (no_is_type, no_is_type_cmd, "no is-type (level-1|level-1-2|level-2-only)", NO_STR "IS Level for this routing process (OSI only)\n" "Act as a station router only\n" "Act as both a station router and an area router\n" "Act as an area router only\n") { struct isis_area *area; int type; area = vty->index; assert (area); /* * Put the is-type back to defaults: * - level-1-2 on first area * - level-1 for the rest */ if (listgetdata (listhead (isis->area_list)) == area) type = IS_LEVEL_1_AND_2; else type = IS_LEVEL_1; isis_area_is_type_set(area, type); return CMD_SUCCESS; } static int set_lsp_gen_interval (struct vty *vty, struct isis_area *area, uint16_t interval, int level) { int lvl; for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (!(lvl & level)) continue; if (interval >= area->lsp_refresh[lvl-1]) { vty_out (vty, "LSP gen interval %us must be less than " "the LSP refresh interval %us%s", interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (!(lvl & level)) continue; area->lsp_gen_interval[lvl-1] = interval; } return CMD_SUCCESS; } DEFUN (lsp_gen_interval, lsp_gen_interval_cmd, "lsp-gen-interval <1-120>", "Minimum interval between regenerating same LSP\n" "Minimum interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval, no_lsp_gen_interval_cmd, "no lsp-gen-interval", NO_STR "Minimum interval between regenerating same LSP\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MIN_LSP_GEN_INTERVAL; level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval, no_lsp_gen_interval_arg_cmd, "no lsp-gen-interval <1-120>", NO_STR "Minimum interval between regenerating same LSP\n" "Minimum interval in seconds\n") DEFUN (lsp_gen_interval_l1, lsp_gen_interval_l1_cmd, "lsp-gen-interval level-1 <1-120>", "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n" "Minimum interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1; return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval_l1, no_lsp_gen_interval_l1_cmd, "no lsp-gen-interval level-1", NO_STR "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MIN_LSP_GEN_INTERVAL; level = IS_LEVEL_1; return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval_l1, no_lsp_gen_interval_l1_arg_cmd, "no lsp-gen-interval level-1 <1-120>", NO_STR "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n" "Minimum interval in seconds\n") DEFUN (lsp_gen_interval_l2, lsp_gen_interval_l2_cmd, "lsp-gen-interval level-2 <1-120>", "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n" "Minimum interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_2; return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval_l2, no_lsp_gen_interval_l2_cmd, "no lsp-gen-interval level-2", NO_STR "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MIN_LSP_GEN_INTERVAL; level = IS_LEVEL_2; return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval_l2, no_lsp_gen_interval_l2_arg_cmd, "no lsp-gen-interval level-2 <1-120>", NO_STR "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n" "Minimum interval in seconds\n") DEFUN (spf_interval, spf_interval_cmd, "spf-interval <1-120>", "Minimum interval between SPF calculations\n" "Minimum interval between consecutive SPFs in seconds\n") { struct isis_area *area; u_int16_t interval; area = vty->index; interval = atoi (argv[0]); area->min_spf_interval[0] = interval; area->min_spf_interval[1] = interval; return CMD_SUCCESS; } DEFUN (no_spf_interval, no_spf_interval_cmd, "no spf-interval", NO_STR "Minimum interval between SPF calculations\n") { struct isis_area *area; area = vty->index; area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; return CMD_SUCCESS; } ALIAS (no_spf_interval, no_spf_interval_arg_cmd, "no spf-interval <1-120>", NO_STR "Minimum interval between SPF calculations\n" "Minimum interval between consecutive SPFs in seconds\n") DEFUN (spf_interval_l1, spf_interval_l1_cmd, "spf-interval level-1 <1-120>", "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n" "Minimum interval between consecutive SPFs in seconds\n") { struct isis_area *area; u_int16_t interval; area = vty->index; interval = atoi (argv[0]); area->min_spf_interval[0] = interval; return CMD_SUCCESS; } DEFUN (no_spf_interval_l1, no_spf_interval_l1_cmd, "no spf-interval level-1", NO_STR "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n") { struct isis_area *area; area = vty->index; area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; return CMD_SUCCESS; } ALIAS (no_spf_interval, no_spf_interval_l1_arg_cmd, "no spf-interval level-1 <1-120>", NO_STR "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFUN (spf_interval_l2, spf_interval_l2_cmd, "spf-interval level-2 <1-120>", "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") { struct isis_area *area; u_int16_t interval; area = vty->index; interval = atoi (argv[0]); area->min_spf_interval[1] = interval; return CMD_SUCCESS; } DEFUN (no_spf_interval_l2, no_spf_interval_l2_cmd, "no spf-interval level-2", NO_STR "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n") { struct isis_area *area; area = vty->index; area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; return CMD_SUCCESS; } ALIAS (no_spf_interval, no_spf_interval_l2_arg_cmd, "no spf-interval level-2 <1-120>", NO_STR "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") static int area_max_lsp_lifetime_set(struct vty *vty, int level, uint16_t interval) { struct isis_area *area = vty->index; int lvl; uint16_t refresh_interval = interval - 300; int set_refresh_interval[ISIS_LEVELS] = {0, 0}; if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { if (!(lvl & level)) continue; if (refresh_interval < area->lsp_refresh[lvl-1]) { vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than " "the configured LSP refresh interval %us%s", lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); vty_out (vty, "Automatically reducing level %d LSP refresh interval " "to %us%s", lvl, refresh_interval, VTY_NEWLINE); set_refresh_interval[lvl-1] = 1; if (refresh_interval <= area->lsp_gen_interval[lvl-1]) { vty_out (vty, "LSP refresh interval %us must be greater than " "the configured LSP gen interval %us%s", refresh_interval, area->lsp_gen_interval[lvl-1], VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } } for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { if (!(lvl & level)) continue; isis_area_max_lsp_lifetime_set(area, lvl, interval); if (set_refresh_interval[lvl-1]) isis_area_lsp_refresh_set(area, lvl, refresh_interval); } return CMD_SUCCESS; } DEFUN (max_lsp_lifetime, max_lsp_lifetime_cmd, "max-lsp-lifetime <350-65535>", "Maximum LSP lifetime\n" "LSP lifetime in seconds\n") { return area_max_lsp_lifetime_set(vty, IS_LEVEL_1_AND_2, atoi(argv[0])); } DEFUN (no_max_lsp_lifetime, no_max_lsp_lifetime_cmd, "no max-lsp-lifetime", NO_STR "LSP lifetime in seconds\n") { return area_max_lsp_lifetime_set(vty, IS_LEVEL_1_AND_2, DEFAULT_LSP_LIFETIME); } ALIAS (no_max_lsp_lifetime, no_max_lsp_lifetime_arg_cmd, "no max-lsp-lifetime <350-65535>", NO_STR "Maximum LSP lifetime\n" "LSP lifetime in seconds\n") DEFUN (max_lsp_lifetime_l1, max_lsp_lifetime_l1_cmd, "max-lsp-lifetime level-1 <350-65535>", "Maximum LSP lifetime for Level 1 only\n" "LSP lifetime for Level 1 only in seconds\n") { return area_max_lsp_lifetime_set(vty, IS_LEVEL_1, atoi(argv[0])); } DEFUN (no_max_lsp_lifetime_l1, no_max_lsp_lifetime_l1_cmd, "no max-lsp-lifetime level-1", NO_STR "LSP lifetime for Level 1 only in seconds\n") { return area_max_lsp_lifetime_set(vty, IS_LEVEL_1, DEFAULT_LSP_LIFETIME); } ALIAS (no_max_lsp_lifetime_l1, no_max_lsp_lifetime_l1_arg_cmd, "no max-lsp-lifetime level-1 <350-65535>", NO_STR "Maximum LSP lifetime for Level 1 only\n" "LSP lifetime for Level 1 only in seconds\n") DEFUN (max_lsp_lifetime_l2, max_lsp_lifetime_l2_cmd, "max-lsp-lifetime level-2 <350-65535>", "Maximum LSP lifetime for Level 2 only\n" "LSP lifetime for Level 2 only in seconds\n") { return area_max_lsp_lifetime_set(vty, IS_LEVEL_2, atoi(argv[0])); } DEFUN (no_max_lsp_lifetime_l2, no_max_lsp_lifetime_l2_cmd, "no max-lsp-lifetime level-2", NO_STR "LSP lifetime for Level 2 only in seconds\n") { return area_max_lsp_lifetime_set(vty, IS_LEVEL_2, DEFAULT_LSP_LIFETIME); } ALIAS (no_max_lsp_lifetime_l2, no_max_lsp_lifetime_l2_arg_cmd, "no max-lsp-lifetime level-2 <350-65535>", NO_STR "Maximum LSP lifetime for Level 2 only\n" "LSP lifetime for Level 2 only in seconds\n") static int area_lsp_refresh_interval_set(struct vty *vty, int level, uint16_t interval) { struct isis_area *area = vty->index; int lvl; if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (!(lvl & level)) continue; if (interval <= area->lsp_gen_interval[lvl-1]) { vty_out (vty, "LSP refresh interval %us must be greater than " "the configured LSP gen interval %us%s", interval, area->lsp_gen_interval[lvl-1], VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } if (interval > (area->max_lsp_lifetime[lvl-1] - 300)) { vty_out (vty, "LSP refresh interval %us must be less than " "the configured LSP lifetime %us less 300%s", interval, area->max_lsp_lifetime[lvl-1], VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (!(lvl & level)) continue; isis_area_lsp_refresh_set(area, lvl, interval); } return CMD_SUCCESS; } DEFUN (lsp_refresh_interval, lsp_refresh_interval_cmd, "lsp-refresh-interval <1-65235>", "LSP refresh interval\n" "LSP refresh interval in seconds\n") { return area_lsp_refresh_interval_set(vty, IS_LEVEL_1_AND_2, atoi(argv[0])); } DEFUN (no_lsp_refresh_interval, no_lsp_refresh_interval_cmd, "no lsp-refresh-interval", NO_STR "LSP refresh interval in seconds\n") { return area_lsp_refresh_interval_set(vty, IS_LEVEL_1_AND_2, DEFAULT_MAX_LSP_GEN_INTERVAL); } ALIAS (no_lsp_refresh_interval, no_lsp_refresh_interval_arg_cmd, "no lsp-refresh-interval <1-65235>", NO_STR "LSP refresh interval\n" "LSP refresh interval in seconds\n") DEFUN (lsp_refresh_interval_l1, lsp_refresh_interval_l1_cmd, "lsp-refresh-interval level-1 <1-65235>", "LSP refresh interval for Level 1 only\n" "LSP refresh interval for Level 1 only in seconds\n") { return area_lsp_refresh_interval_set(vty, IS_LEVEL_1, atoi(argv[0])); } DEFUN (no_lsp_refresh_interval_l1, no_lsp_refresh_interval_l1_cmd, "no lsp-refresh-interval level-1", NO_STR "LSP refresh interval for Level 1 only in seconds\n") { return area_lsp_refresh_interval_set(vty, IS_LEVEL_1, DEFAULT_MAX_LSP_GEN_INTERVAL); } ALIAS (no_lsp_refresh_interval_l1, no_lsp_refresh_interval_l1_arg_cmd, "no lsp-refresh-interval level-1 <1-65235>", NO_STR "LSP refresh interval for Level 1 only\n" "LSP refresh interval for Level 1 only in seconds\n") DEFUN (lsp_refresh_interval_l2, lsp_refresh_interval_l2_cmd, "lsp-refresh-interval level-2 <1-65235>", "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") { return area_lsp_refresh_interval_set(vty, IS_LEVEL_2, atoi(argv[0])); } DEFUN (no_lsp_refresh_interval_l2, no_lsp_refresh_interval_l2_cmd, "no lsp-refresh-interval level-2", NO_STR "LSP refresh interval for Level 2 only in seconds\n") { return area_lsp_refresh_interval_set(vty, IS_LEVEL_2, DEFAULT_MAX_LSP_GEN_INTERVAL); } ALIAS (no_lsp_refresh_interval_l2, no_lsp_refresh_interval_l2_arg_cmd, "no lsp-refresh-interval level-2 <1-65235>", NO_STR "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") static int area_passwd_set(struct vty *vty, int level, int (*type_set)(struct isis_area *area, int level, const char *passwd, u_char snp_auth), const char *passwd, u_char snp_auth) { struct isis_area *area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } if (passwd && strlen(passwd) > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } type_set(area, level, passwd, snp_auth); return CMD_SUCCESS; } DEFUN (area_passwd_md5, area_passwd_md5_cmd, "(area-password|domain-password) md5 WORD", "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n" "Authentication type\n" "Level-wide password\n") { u_char snp_auth = 0; int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; if (argc > 2) { snp_auth = SNP_AUTH_SEND; if (strncmp(argv[2], "v", 1) == 0) snp_auth |= SNP_AUTH_RECV; } return area_passwd_set(vty, level, isis_area_passwd_hmac_md5_set, argv[1], snp_auth); } ALIAS (area_passwd_md5, area_passwd_md5_snpauth_cmd, "(area-password|domain-password) md5 WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n" "Authentication type\n" "Level-wide password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n") DEFUN (area_passwd_clear, area_passwd_clear_cmd, "(area-password|domain-password) clear WORD", "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n" "Authentication type\n" "Area password\n") { u_char snp_auth = 0; int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; if (argc > 2) { snp_auth = SNP_AUTH_SEND; if (strncmp(argv[2], "v", 1) == 0) snp_auth |= SNP_AUTH_RECV; } return area_passwd_set(vty, level, isis_area_passwd_cleartext_set, argv[1], snp_auth); } ALIAS (area_passwd_clear, area_passwd_clear_snpauth_cmd, "(area-password|domain-password) clear WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n" "Authentication type\n" "Area password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n") DEFUN (no_area_passwd, no_area_passwd_cmd, "no (area-password|domain-password)", NO_STR "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n") { int level = (argv[0][0] == 'd') ? IS_LEVEL_2 : IS_LEVEL_1; struct isis_area *area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } return isis_area_passwd_unset (area, level); } void isis_vty_init (void) { install_element (INTERFACE_NODE, &ip_router_isis_cmd); install_element (INTERFACE_NODE, &no_ip_router_isis_cmd); install_element (INTERFACE_NODE, &isis_passive_cmd); install_element (INTERFACE_NODE, &no_isis_passive_cmd); install_element (INTERFACE_NODE, &isis_circuit_type_cmd); install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); install_element (INTERFACE_NODE, &isis_network_cmd); install_element (INTERFACE_NODE, &no_isis_network_cmd); install_element (INTERFACE_NODE, &isis_passwd_cmd); install_element (INTERFACE_NODE, &no_isis_passwd_cmd); install_element (INTERFACE_NODE, &no_isis_passwd_arg_cmd); install_element (INTERFACE_NODE, &isis_priority_cmd); install_element (INTERFACE_NODE, &no_isis_priority_cmd); install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd); install_element (INTERFACE_NODE, &isis_priority_l1_cmd); install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd); install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd); install_element (INTERFACE_NODE, &isis_priority_l2_cmd); install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd); install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_metric_cmd); install_element (INTERFACE_NODE, &no_isis_metric_cmd); install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd); install_element (INTERFACE_NODE, &isis_metric_l1_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd); install_element (INTERFACE_NODE, &isis_metric_l2_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_padding_cmd); install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd); install_element (INTERFACE_NODE, &csnp_interval_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd); install_element (INTERFACE_NODE, &csnp_interval_l1_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd); install_element (INTERFACE_NODE, &csnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd); install_element (INTERFACE_NODE, &psnp_interval_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd); install_element (INTERFACE_NODE, &psnp_interval_l1_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd); install_element (INTERFACE_NODE, &psnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd); install_element (ISIS_NODE, &metric_style_cmd); install_element (ISIS_NODE, &no_metric_style_cmd); install_element (ISIS_NODE, &set_overload_bit_cmd); install_element (ISIS_NODE, &no_set_overload_bit_cmd); install_element (ISIS_NODE, &set_attached_bit_cmd); install_element (ISIS_NODE, &no_set_attached_bit_cmd); install_element (ISIS_NODE, &dynamic_hostname_cmd); install_element (ISIS_NODE, &no_dynamic_hostname_cmd); install_element (ISIS_NODE, &area_lsp_mtu_cmd); install_element (ISIS_NODE, &no_area_lsp_mtu_cmd); install_element (ISIS_NODE, &no_area_lsp_mtu_arg_cmd); install_element (ISIS_NODE, &is_type_cmd); install_element (ISIS_NODE, &no_is_type_cmd); install_element (ISIS_NODE, &lsp_gen_interval_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd); install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd); install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd); install_element (ISIS_NODE, &spf_interval_cmd); install_element (ISIS_NODE, &no_spf_interval_cmd); install_element (ISIS_NODE, &no_spf_interval_arg_cmd); install_element (ISIS_NODE, &spf_interval_l1_cmd); install_element (ISIS_NODE, &no_spf_interval_l1_cmd); install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd); install_element (ISIS_NODE, &spf_interval_l2_cmd); install_element (ISIS_NODE, &no_spf_interval_l2_cmd); install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd); install_element (ISIS_NODE, &max_lsp_lifetime_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd); install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd); install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd); install_element (ISIS_NODE, &lsp_refresh_interval_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd); install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd); install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); install_element (ISIS_NODE, &area_passwd_md5_cmd); install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); install_element (ISIS_NODE, &area_passwd_clear_cmd); install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd); install_element (ISIS_NODE, &no_area_passwd_cmd); } quagga-1.2.4/isisd/isis_zebra.c000066400000000000000000000465111325323223500164030ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_zebra.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * Copyright (C) 2013-2015 Christian Franke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "thread.h" #include "command.h" #include "memory.h" #include "log.h" #include "if.h" #include "network.h" #include "prefix.h" #include "zclient.h" #include "stream.h" #include "linklist.h" #include "vrf.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_misc.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" #include "isisd/isis_lsp.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" #include "isisd/isis_te.h" struct zclient *zclient = NULL; /* Router-id update message from zebra. */ static int isis_router_id_update_zebra (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct isis_area *area; struct listnode *node; struct prefix router_id; /* * If ISIS TE is enable, TE Router ID is set through specific command. * See mpls_te_router_addr() command in isis_te.c */ if (IS_MPLS_TE(isisMplsTE)) return 0; zebra_router_id_update_read (zclient->ibuf, &router_id); if (isis->router_id == router_id.u.prefix4.s_addr) return 0; isis->router_id = router_id.u.prefix4.s_addr; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) if (listcount (area->area_addrs) > 0) lsp_regenerate_schedule (area, area->is_type, 0); return 0; } static int isis_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (isis->debugs & DEBUG_ZEBRA) zlog_debug ("Zebra I/F add: %s index %d flags %ld metric %d mtu %d", ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu); if (if_is_operative (ifp)) isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp); return 0; } static int isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = zclient->ibuf; ifp = zebra_interface_state_read (s, vrf_id); if (!ifp) return 0; if (if_is_operative (ifp)) zlog_warn ("Zebra: got delete of %s, but interface is still up", ifp->name); if (isis->debugs & DEBUG_ZEBRA) zlog_debug ("Zebra I/F delete: %s index %d flags %ld metric %d mtu %d", ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu); isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); /* Cannot call if_delete because we should retain the pseudo interface in case there is configuration info attached to it. */ if_delete_retain(ifp); ifp->ifindex = IFINDEX_INTERNAL; return 0; } static int isis_zebra_if_state_up (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp); return 0; } static int isis_zebra_if_state_down (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct isis_circuit *circuit; ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; circuit = isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); if (circuit) SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); return 0; } static int isis_zebra_if_address_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; char buf[BUFSIZ]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf, vrf_id); if (c == NULL) return 0; p = c->address; prefix2str (p, buf, BUFSIZ); #ifdef EXTREME_DEBUG if (p->family == AF_INET) zlog_debug ("connected IP address %s", buf); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zlog_debug ("connected IPv6 address %s", buf); #endif /* HAVE_IPV6 */ #endif /* EXTREME_DEBUG */ if (if_is_operative (c->ifp)) isis_circuit_add_addr (circuit_scan_by_ifp (c->ifp), c); return 0; } static int isis_zebra_if_address_del (int command, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct interface *ifp; #ifdef EXTREME_DEBUG struct prefix *p; u_char buf[BUFSIZ]; #endif /* EXTREME_DEBUG */ c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf, vrf_id); if (c == NULL) return 0; ifp = c->ifp; #ifdef EXTREME_DEBUG p = c->address; prefix2str (p, buf, BUFSIZ); if (p->family == AF_INET) zlog_debug ("disconnected IP address %s", buf); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zlog_debug ("disconnected IPv6 address %s", buf); #endif /* HAVE_IPV6 */ #endif /* EXTREME_DEBUG */ if (if_is_operative (ifp)) isis_circuit_del_addr (circuit_scan_by_ifp (ifp), c); connected_free (c); return 0; } static int isis_zebra_link_params (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_link_params_read (zclient->ibuf); if (ifp == NULL) return 0; /* Update TE TLV */ isis_mpls_te_update(ifp); return 0; } static void isis_zebra_route_add_ipv4 (struct prefix *prefix, struct isis_route_info *route_info) { u_char message, flags; int psize; struct stream *stream; struct isis_nexthop *nexthop; struct listnode *node; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_ISIS], VRF_DEFAULT)) { message = 0; flags = 0; SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (message, ZAPI_MESSAGE_METRIC); #if 0 SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); #endif stream = zclient->obuf; stream_reset (stream); zclient_create_header (stream, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT); /* type */ stream_putc (stream, ZEBRA_ROUTE_ISIS); /* flags */ stream_putc (stream, flags); /* message */ stream_putc (stream, message); /* SAFI */ stream_putw (stream, SAFI_UNICAST); /* prefix information */ psize = PSIZE (prefix->prefixlen); stream_putc (stream, prefix->prefixlen); stream_write (stream, (u_char *) & prefix->u.prefix4, psize); stream_putc (stream, listcount (route_info->nexthops)); /* Nexthop, ifindex, distance and metric information */ for (ALL_LIST_ELEMENTS_RO (route_info->nexthops, node, nexthop)) { /* FIXME: can it be ? */ if (nexthop->ip.s_addr != INADDR_ANY) { stream_putc (stream, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (stream, &nexthop->ip); } else { stream_putc (stream, ZEBRA_NEXTHOP_IFINDEX); stream_putl (stream, nexthop->ifindex); } } #if 0 if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) stream_putc (stream, route_info->depth); #endif if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) stream_putl (stream, route_info->cost); stream_putw_at (stream, 0, stream_get_endp (stream)); zclient_send_message(zclient); SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } } static void isis_zebra_route_del_ipv4 (struct prefix *prefix, struct isis_route_info *route_info) { struct zapi_ipv4 api; struct prefix_ipv4 prefix4; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_ISIS], VRF_DEFAULT)) { api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; prefix4.family = AF_INET; prefix4.prefixlen = prefix->prefixlen; prefix4.prefix = prefix->u.prefix4; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, &prefix4, &api); } UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); return; } #ifdef HAVE_IPV6 static void isis_zebra_route_add_ipv6 (struct prefix *prefix, struct isis_route_info *route_info) { struct zapi_ipv6 api; struct in6_addr **nexthop_list; ifindex_t *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; struct prefix_ipv6 prefix6; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = route_info->cost; #if 0 SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = route_info->depth; #endif api.nexthop_num = listcount (route_info->nexthops6); api.ifindex_num = listcount (route_info->nexthops6); /* allocate memory for nexthop_list */ size = sizeof (struct isis_nexthop6 *) * listcount (route_info->nexthops6); nexthop_list = (struct in6_addr **) XMALLOC (MTYPE_ISIS_TMP, size); if (!nexthop_list) { zlog_err ("isis_zebra_add_route_ipv6: out of memory!"); return; } /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); ifindex_list = (ifindex_t *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_add_route_ipv6: out of memory!"); XFREE (MTYPE_ISIS_TMP, nexthop_list); return; } /* for each nexthop */ i = 0; for (ALL_LIST_ELEMENTS_RO (route_info->nexthops6, node, nexthop6)) { if (!IN6_IS_ADDR_LINKLOCAL (&nexthop6->ip6) && !IN6_IS_ADDR_UNSPECIFIED (&nexthop6->ip6)) { api.nexthop_num--; api.ifindex_num--; continue; } nexthop_list[i] = &nexthop6->ip6; ifindex_list[i] = nexthop6->ifindex; i++; } api.nexthop = nexthop_list; api.ifindex = ifindex_list; if (api.nexthop_num && api.ifindex_num) { prefix6.family = AF_INET6; prefix6.prefixlen = prefix->prefixlen; memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr)); zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, &prefix6, &api); SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } XFREE (MTYPE_ISIS_TMP, nexthop_list); XFREE (MTYPE_ISIS_TMP, ifindex_list); return; } static void isis_zebra_route_del_ipv6 (struct prefix *prefix, struct isis_route_info *route_info) { struct zapi_ipv6 api; struct in6_addr **nexthop_list; ifindex_t *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; struct prefix_ipv6 prefix6; if (!CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.nexthop_num = listcount (route_info->nexthops6); api.ifindex_num = listcount (route_info->nexthops6); /* allocate memory for nexthop_list */ size = sizeof (struct isis_nexthop6 *) * listcount (route_info->nexthops6); nexthop_list = (struct in6_addr **) XMALLOC (MTYPE_ISIS_TMP, size); if (!nexthop_list) { zlog_err ("isis_zebra_route_del_ipv6: out of memory!"); return; } /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); ifindex_list = (ifindex_t *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_route_del_ipv6: out of memory!"); XFREE (MTYPE_ISIS_TMP, nexthop_list); return; } /* for each nexthop */ i = 0; for (ALL_LIST_ELEMENTS_RO (route_info->nexthops6, node, nexthop6)) { if (!IN6_IS_ADDR_LINKLOCAL (&nexthop6->ip6) && !IN6_IS_ADDR_UNSPECIFIED (&nexthop6->ip6)) { api.nexthop_num--; api.ifindex_num--; continue; } nexthop_list[i] = &nexthop6->ip6; ifindex_list[i] = nexthop6->ifindex; i++; } api.nexthop = nexthop_list; api.ifindex = ifindex_list; if (api.nexthop_num && api.ifindex_num) { prefix6.family = AF_INET6; prefix6.prefixlen = prefix->prefixlen; memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr)); zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, &prefix6, &api); UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } XFREE (MTYPE_ISIS_TMP, nexthop_list); XFREE (MTYPE_ISIS_TMP, ifindex_list); } #endif /* HAVE_IPV6 */ void isis_zebra_route_update (struct prefix *prefix, struct isis_route_info *route_info) { if (zclient->sock < 0) return; if (!vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_ISIS], VRF_DEFAULT)) return; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) { if (prefix->family == AF_INET) isis_zebra_route_add_ipv4 (prefix, route_info); #ifdef HAVE_IPV6 else if (prefix->family == AF_INET6) isis_zebra_route_add_ipv6 (prefix, route_info); #endif /* HAVE_IPV6 */ } else { if (prefix->family == AF_INET) isis_zebra_route_del_ipv4 (prefix, route_info); #ifdef HAVE_IPV6 else if (prefix->family == AF_INET6) isis_zebra_route_del_ipv6 (prefix, route_info); #endif /* HAVE_IPV6 */ } return; } static int isis_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *stream; struct zapi_ipv4 api; struct prefix_ipv4 p; struct prefix *p_generic = (struct prefix*)&p; unsigned long ifindex __attribute__ ((unused)); struct in_addr nexthop __attribute__ ((unused)); unsigned char plength = 0; stream = zclient->ibuf; memset(&api, 0, sizeof(api)); memset (&p, 0, sizeof (struct prefix_ipv4)); memset(&nexthop, 0, sizeof(nexthop)); ifindex = 0; api.type = stream_getc (stream); api.flags = stream_getc (stream); api.message = stream_getc (stream); p.family = AF_INET; plength = stream_getc (stream); p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength); stream_get (&p.prefix, stream, PSIZE (p.prefixlen)); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (stream); nexthop.s_addr = stream_get_ipv4 (stream); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (stream); ifindex = stream_getl (stream); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (stream); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (stream); /* * Avoid advertising a false default reachability. (A default * route installed by IS-IS gets redistributed from zebra back * into IS-IS causing us to start advertising default reachabity * without this check) */ if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) command = ZEBRA_IPV4_ROUTE_DELETE; if (command == ZEBRA_IPV4_ROUTE_ADD) isis_redist_add(api.type, p_generic, api.distance, api.metric); else isis_redist_delete(api.type, p_generic); return 0; } static int isis_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *stream; struct zapi_ipv6 api; struct prefix_ipv6 p; struct prefix *p_generic = (struct prefix*)&p; struct in6_addr nexthop; unsigned long ifindex __attribute__((unused)); stream = zclient->ibuf; memset(&api, 0, sizeof(api)); memset(&p, 0, sizeof(struct prefix_ipv6)); memset(&nexthop, 0, sizeof(nexthop)); ifindex = 0; api.type = stream_getc(stream); api.flags = stream_getc(stream); api.message = stream_getc(stream); p.family = AF_INET6; p.prefixlen = stream_getc(stream); stream_get(&p.prefix, stream, PSIZE(p.prefixlen)); if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc(stream); /* this is always 1 */ stream_get(&nexthop, stream, sizeof(nexthop)); } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc(stream); ifindex = stream_getl(stream); } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc(stream); if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl(stream); /* * Avoid advertising a false default reachability. (A default * route installed by IS-IS gets redistributed from zebra back * into IS-IS causing us to start advertising default reachabity * without this check) */ if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) command = ZEBRA_IPV6_ROUTE_DELETE; if (command == ZEBRA_IPV6_ROUTE_ADD) isis_redist_add(api.type, p_generic, api.distance, api.metric); else isis_redist_delete(api.type, p_generic); return 0; } int isis_distribute_list_update (int routetype) { return 0; } void isis_zebra_redistribute_set(int type) { if (type == DEFAULT_ROUTE) zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, VRF_DEFAULT); else zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); } void isis_zebra_redistribute_unset(int type) { if (type == DEFAULT_ROUTE) zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, VRF_DEFAULT); else zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT); } static void isis_zebra_connected (struct zclient *zclient) { zclient_send_requests (zclient, VRF_DEFAULT); } void isis_zebra_init (struct thread_master *master) { zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_ISIS); zclient->zebra_connected = isis_zebra_connected; zclient->router_id_update = isis_router_id_update_zebra; zclient->interface_add = isis_zebra_if_add; zclient->interface_delete = isis_zebra_if_del; zclient->interface_up = isis_zebra_if_state_up; zclient->interface_down = isis_zebra_if_state_down; zclient->interface_address_add = isis_zebra_if_address_add; zclient->interface_address_delete = isis_zebra_if_address_del; zclient->interface_link_params = isis_zebra_link_params; zclient->ipv4_route_add = isis_zebra_read_ipv4; zclient->ipv4_route_delete = isis_zebra_read_ipv4; #ifdef HAVE_IPV6 zclient->ipv6_route_add = isis_zebra_read_ipv6; zclient->ipv6_route_delete = isis_zebra_read_ipv6; #endif /* HAVE_IPV6 */ return; } quagga-1.2.4/isisd/isis_zebra.h000066400000000000000000000025311325323223500164020ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isis_zebra.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISIS_ZEBRA_H #define _ZEBRA_ISIS_ZEBRA_H extern struct zclient *zclient; void isis_zebra_init (struct thread_master *); void isis_zebra_route_update (struct prefix *prefix, struct isis_route_info *route_info); int isis_distribute_list_update (int routetype); void isis_zebra_redistribute_set(int type); void isis_zebra_redistribute_unset(int type); #endif /* _ZEBRA_ISIS_ZEBRA_H */ quagga-1.2.4/isisd/isisd.c000066400000000000000000001774141325323223500153730ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isisd.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "thread.h" #include "vty.h" #include "command.h" #include "log.h" #include "memory.h" #include "time.h" #include "linklist.h" #include "if.h" #include "hash.h" #include "stream.h" #include "prefix.h" #include "table.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_pdu.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_spf.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" #include "isisd/isis_events.h" #include "isisd/isis_te.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" u_char DEFAULT_TOPOLOGY_BASEIS[6] = { 0xFE, 0xED, 0xFE, 0xED, 0x00, 0x00 }; #endif /* TOPOLOGY_GENERATE */ struct isis *isis = NULL; /* * Prototypes. */ int isis_area_get(struct vty *, const char *); int isis_area_destroy(struct vty *, const char *); int area_net_title(struct vty *, const char *); int area_clear_net_title(struct vty *, const char *); int show_isis_interface_common(struct vty *, const char *ifname, char); int show_isis_neighbor_common(struct vty *, const char *id, char); int clear_isis_neighbor_common(struct vty *, const char *id); int isis_config_write(struct vty *); void isis_new (unsigned long process_id) { isis = XCALLOC (MTYPE_ISIS, sizeof (struct isis)); /* * Default values */ isis->max_area_addrs = 3; isis->process_id = process_id; isis->router_id = 0; isis->area_list = list_new (); isis->init_circ_list = list_new (); isis->uptime = time (NULL); isis->nexthops = list_new (); #ifdef HAVE_IPV6 isis->nexthops6 = list_new (); #endif /* HAVE_IPV6 */ dyn_cache_init (); /* * uncomment the next line for full debugs */ /* isis->debugs = 0xFFFF; */ isisMplsTE.status = disable; /* Only support TE metric */ } struct isis_area * isis_area_create (const char *area_tag) { struct isis_area *area; area = XCALLOC (MTYPE_ISIS_AREA, sizeof (struct isis_area)); /* * The first instance is level-1-2 rest are level-1, unless otherwise * configured */ if (listcount (isis->area_list) > 0) area->is_type = IS_LEVEL_1; else area->is_type = IS_LEVEL_1_AND_2; /* * intialize the databases */ if (area->is_type & IS_LEVEL_1) { area->lspdb[0] = lsp_db_init (); area->route_table[0] = route_table_init (); #ifdef HAVE_IPV6 area->route_table6[0] = route_table_init (); #endif /* HAVE_IPV6 */ } if (area->is_type & IS_LEVEL_2) { area->lspdb[1] = lsp_db_init (); area->route_table[1] = route_table_init (); #ifdef HAVE_IPV6 area->route_table6[1] = route_table_init (); #endif /* HAVE_IPV6 */ } spftree_area_init (area); area->circuit_list = list_new (); area->area_addrs = list_new (); THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1); flags_initialize (&area->flags); /* * Default values */ area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME; /* 1200 */ area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME; /* 1200 */ area->lsp_refresh[0] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */ area->lsp_refresh[1] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */ area->lsp_gen_interval[0] = DEFAULT_MIN_LSP_GEN_INTERVAL; area->lsp_gen_interval[1] = DEFAULT_MIN_LSP_GEN_INTERVAL; area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; area->dynhostname = 1; area->oldmetric = 0; area->newmetric = 1; area->lsp_frag_threshold = 90; area->lsp_mtu = DEFAULT_LSP_MTU; #ifdef TOPOLOGY_GENERATE memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); #endif /* TOPOLOGY_GENERATE */ area->area_tag = strdup (area_tag); listnode_add (isis->area_list, area); area->isis = isis; return area; } struct isis_area * isis_area_lookup (const char *area_tag) { struct isis_area *area; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) if ((area->area_tag == NULL && area_tag == NULL) || (area->area_tag && area_tag && strcmp (area->area_tag, area_tag) == 0)) return area; return NULL; } int isis_area_get (struct vty *vty, const char *area_tag) { struct isis_area *area; area = isis_area_lookup (area_tag); if (area) { vty->node = ISIS_NODE; vty->index = area; return CMD_SUCCESS; } area = isis_area_create (area_tag); if (isis->debugs & DEBUG_EVENTS) zlog_debug ("New IS-IS area instance %s", area->area_tag); vty->node = ISIS_NODE; vty->index = area; return CMD_SUCCESS; } int isis_area_destroy (struct vty *vty, const char *area_tag) { struct isis_area *area; struct listnode *node, *nnode; struct isis_circuit *circuit; struct area_addr *addr; area = isis_area_lookup (area_tag); if (area == NULL) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } if (area->circuit_list) { for (ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit)) { circuit->ip_router = 0; #ifdef HAVE_IPV6 circuit->ipv6_router = 0; #endif isis_csm_state_change (ISIS_DISABLE, circuit, area); } list_delete (area->circuit_list); area->circuit_list = NULL; } if (area->lspdb[0] != NULL) { lsp_db_destroy (area->lspdb[0]); area->lspdb[0] = NULL; } if (area->lspdb[1] != NULL) { lsp_db_destroy (area->lspdb[1]); area->lspdb[1] = NULL; } spftree_area_del (area); /* invalidate and validate would delete all routes from zebra */ isis_route_invalidate (area); isis_route_validate (area); if (area->route_table[0]) { route_table_finish (area->route_table[0]); area->route_table[0] = NULL; } if (area->route_table[1]) { route_table_finish (area->route_table[1]); area->route_table[1] = NULL; } #ifdef HAVE_IPV6 if (area->route_table6[0]) { route_table_finish (area->route_table6[0]); area->route_table6[0] = NULL; } if (area->route_table6[1]) { route_table_finish (area->route_table6[1]); area->route_table6[1] = NULL; } #endif /* HAVE_IPV6 */ isis_redist_area_finish(area); for (ALL_LIST_ELEMENTS (area->area_addrs, node, nnode, addr)) { list_delete_node (area->area_addrs, node); XFREE (MTYPE_ISIS_AREA_ADDR, addr); } area->area_addrs = NULL; THREAD_TIMER_OFF (area->t_tick); THREAD_TIMER_OFF (area->t_lsp_refresh[0]); THREAD_TIMER_OFF (area->t_lsp_refresh[1]); thread_cancel_event (master, area); listnode_delete (isis->area_list, area); free (area->area_tag); XFREE (MTYPE_ISIS_AREA, area); if (listcount (isis->area_list) == 0) { memset (isis->sysid, 0, ISIS_SYS_ID_LEN); isis->sysid_set = 0; } return CMD_SUCCESS; } int area_net_title (struct vty *vty, const char *net_title) { struct isis_area *area; struct area_addr *addr; struct area_addr *addrp; struct listnode *node; u_char buff[255]; area = vty->index; if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } /* We check that we are not over the maximal number of addresses */ if (listcount (area->area_addrs) >= isis->max_area_addrs) { vty_out (vty, "Maximum of area addresses (%d) already reached %s", isis->max_area_addrs, VTY_NEWLINE); return CMD_ERR_NOTHING_TODO; } addr = XMALLOC (MTYPE_ISIS_AREA_ADDR, sizeof (struct area_addr)); addr->addr_len = dotformat2buff (buff, net_title); memcpy (addr->area_addr, buff, addr->addr_len); #ifdef EXTREME_DEBUG zlog_debug ("added area address %s for area %s (address length %d)", net_title, area->area_tag, addr->addr_len); #endif /* EXTREME_DEBUG */ if (addr->addr_len < 8 || addr->addr_len > 20) { vty_out (vty, "area address must be at least 8..20 octets long (%d)%s", addr->addr_len, VTY_NEWLINE); XFREE (MTYPE_ISIS_AREA_ADDR, addr); return CMD_ERR_AMBIGUOUS; } if (addr->area_addr[addr->addr_len-1] != 0) { vty_out (vty, "nsel byte (last byte) in area address must be 0%s", VTY_NEWLINE); XFREE (MTYPE_ISIS_AREA_ADDR, addr); return CMD_ERR_AMBIGUOUS; } if (isis->sysid_set == 0) { /* * First area address - get the SystemID for this router */ memcpy (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN); isis->sysid_set = 1; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("Router has SystemID %s", sysid_print (isis->sysid)); } else { /* * Check that the SystemID portions match */ if (memcmp (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN)) { vty_out (vty, "System ID must not change when defining additional area" " addresses%s", VTY_NEWLINE); XFREE (MTYPE_ISIS_AREA_ADDR, addr); return CMD_ERR_AMBIGUOUS; } /* now we see that we don't already have this address */ for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp)) { if ((addrp->addr_len + ISIS_SYS_ID_LEN + ISIS_NSEL_LEN) != (addr->addr_len)) continue; if (!memcmp (addrp->area_addr, addr->area_addr, addr->addr_len)) { XFREE (MTYPE_ISIS_AREA_ADDR, addr); return CMD_SUCCESS; /* silent fail */ } } } /* * Forget the systemID part of the address */ addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN); listnode_add (area->area_addrs, addr); /* only now we can safely generate our LSPs for this area */ if (listcount (area->area_addrs) > 0) { if (area->is_type & IS_LEVEL_1) lsp_generate (area, IS_LEVEL_1); if (area->is_type & IS_LEVEL_2) lsp_generate (area, IS_LEVEL_2); } return CMD_SUCCESS; } int area_clear_net_title (struct vty *vty, const char *net_title) { struct isis_area *area; struct area_addr addr, *addrp = NULL; struct listnode *node; u_char buff[255]; area = vty->index; if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } addr.addr_len = dotformat2buff (buff, net_title); if (addr.addr_len < 8 || addr.addr_len > 20) { vty_out (vty, "Unsupported area address length %d, should be 8...20 %s", addr.addr_len, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } memcpy (addr.area_addr, buff, (int) addr.addr_len); for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp)) if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len && !memcmp (addrp->area_addr, addr.area_addr, addr.addr_len)) break; if (!addrp) { vty_out (vty, "No area address %s for area %s %s", net_title, area->area_tag, VTY_NEWLINE); return CMD_ERR_NO_MATCH; } listnode_delete (area->area_addrs, addrp); XFREE (MTYPE_ISIS_AREA_ADDR, addrp); /* * Last area address - reset the SystemID for this router */ if (listcount (area->area_addrs) == 0) { memset (isis->sysid, 0, ISIS_SYS_ID_LEN); isis->sysid_set = 0; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("Router has no SystemID"); } return CMD_SUCCESS; } /* * 'show isis interface' command */ int show_isis_interface_common (struct vty *vty, const char *ifname, char detail) { struct listnode *anode, *cnode; struct isis_area *area; struct isis_circuit *circuit; if (!isis) { vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) { vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE); if (detail == ISIS_UI_LEVEL_BRIEF) vty_out (vty, " Interface CircId State Type Level%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) if (!ifname) isis_circuit_print_vty (circuit, vty, detail); else if (strcmp(circuit->interface->name, ifname) == 0) isis_circuit_print_vty (circuit, vty, detail); } return CMD_SUCCESS; } DEFUN (show_isis_interface, show_isis_interface_cmd, "show isis interface", SHOW_STR "ISIS network information\n" "ISIS interface\n") { return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_BRIEF); } DEFUN (show_isis_interface_detail, show_isis_interface_detail_cmd, "show isis interface detail", SHOW_STR "ISIS network information\n" "ISIS interface\n" "show detailed information\n") { return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_DETAIL); } DEFUN (show_isis_interface_arg, show_isis_interface_arg_cmd, "show isis interface WORD", SHOW_STR "ISIS network information\n" "ISIS interface\n" "ISIS interface name\n") { return show_isis_interface_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } /* * 'show isis neighbor' command */ int show_isis_neighbor_common (struct vty *vty, const char *id, char detail) { struct listnode *anode, *cnode, *node; struct isis_area *area; struct isis_circuit *circuit; struct list *adjdb; struct isis_adjacency *adj; struct isis_dynhn *dynhn; u_char sysid[ISIS_SYS_ID_LEN]; int i; if (!isis) { vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } memset (sysid, 0, ISIS_SYS_ID_LEN); if (id) { if (sysid2buff (sysid, id) == 0) { dynhn = dynhn_find_by_name (id); if (dynhn == NULL) { vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE); return CMD_SUCCESS; } memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN); } } for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) { vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE); if (detail == ISIS_UI_LEVEL_BRIEF) vty_out (vty, " System Id Interface L State" " Holdtime SNPA%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { for (i = 0; i < 2; i++) { adjdb = circuit->u.bc.adjdb[i]; if (adjdb && adjdb->count) { for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_print_vty (adj, vty, detail); } } } else if (circuit->circ_type == CIRCUIT_T_P2P && circuit->u.p2p.neighbor) { adj = circuit->u.p2p.neighbor; if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_print_vty (adj, vty, detail); } } } return CMD_SUCCESS; } /* * 'clear isis neighbor' command */ int clear_isis_neighbor_common (struct vty *vty, const char *id) { struct listnode *anode, *cnode, *cnextnode, *node, *nnode; struct isis_area *area; struct isis_circuit *circuit; struct list *adjdb; struct isis_adjacency *adj; struct isis_dynhn *dynhn; u_char sysid[ISIS_SYS_ID_LEN]; int i; if (!isis) { vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } memset (sysid, 0, ISIS_SYS_ID_LEN); if (id) { if (sysid2buff (sysid, id) == 0) { dynhn = dynhn_find_by_name (id); if (dynhn == NULL) { vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE); return CMD_SUCCESS; } memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN); } } for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) { for (ALL_LIST_ELEMENTS (area->circuit_list, cnode, cnextnode, circuit)) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { for (i = 0; i < 2; i++) { adjdb = circuit->u.bc.adjdb[i]; if (adjdb && adjdb->count) { for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj)) if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_state_change (adj, ISIS_ADJ_DOWN, "clear user request"); } } } else if (circuit->circ_type == CIRCUIT_T_P2P && circuit->u.p2p.neighbor) { adj = circuit->u.p2p.neighbor; if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_state_change (adj, ISIS_ADJ_DOWN, "clear user request"); } } } return CMD_SUCCESS; } DEFUN (show_isis_neighbor, show_isis_neighbor_cmd, "show isis neighbor", SHOW_STR "ISIS network information\n" "ISIS neighbor adjacencies\n") { return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_BRIEF); } DEFUN (show_isis_neighbor_detail, show_isis_neighbor_detail_cmd, "show isis neighbor detail", SHOW_STR "ISIS network information\n" "ISIS neighbor adjacencies\n" "show detailed information\n") { return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_DETAIL); } DEFUN (show_isis_neighbor_arg, show_isis_neighbor_arg_cmd, "show isis neighbor WORD", SHOW_STR "ISIS network information\n" "ISIS neighbor adjacencies\n" "System id\n") { return show_isis_neighbor_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } DEFUN (clear_isis_neighbor, clear_isis_neighbor_cmd, "clear isis neighbor", CLEAR_STR "Reset ISIS network information\n" "Reset ISIS neighbor adjacencies\n") { return clear_isis_neighbor_common (vty, NULL); } DEFUN (clear_isis_neighbor_arg, clear_isis_neighbor_arg_cmd, "clear isis neighbor WORD", CLEAR_STR "ISIS network information\n" "ISIS neighbor adjacencies\n" "System id\n") { return clear_isis_neighbor_common (vty, argv[0]); } /* * 'isis debug', 'show debugging' */ void print_debug (struct vty *vty, int flags, int onoff) { char onoffs[4]; if (onoff) strcpy (onoffs, "on"); else strcpy (onoffs, "off"); if (flags & DEBUG_ADJ_PACKETS) vty_out (vty, "IS-IS Adjacency related packets debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_CHECKSUM_ERRORS) vty_out (vty, "IS-IS checksum errors debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_LOCAL_UPDATES) vty_out (vty, "IS-IS local updates debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_PROTOCOL_ERRORS) vty_out (vty, "IS-IS protocol errors debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_SNP_PACKETS) vty_out (vty, "IS-IS CSNP/PSNP packets debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_SPF_EVENTS) vty_out (vty, "IS-IS SPF events debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_SPF_STATS) vty_out (vty, "IS-IS SPF Timing and Statistics Data debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_SPF_TRIGGERS) vty_out (vty, "IS-IS SPF triggering events debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_UPDATE_PACKETS) vty_out (vty, "IS-IS Update related packet debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_RTE_EVENTS) vty_out (vty, "IS-IS Route related debuggin is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_EVENTS) vty_out (vty, "IS-IS Event debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_PACKET_DUMP) vty_out (vty, "IS-IS Packet dump debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_LSP_GEN) vty_out (vty, "IS-IS LSP generation debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_LSP_SCHED) vty_out (vty, "IS-IS LSP scheduling debugging is %s%s", onoffs, VTY_NEWLINE); } DEFUN (show_debugging, show_debugging_isis_cmd, "show debugging isis", SHOW_STR "State of each debugging option\n") { if (isis->debugs) { vty_out (vty, "IS-IS:%s", VTY_NEWLINE); print_debug (vty, isis->debugs, 1); } return CMD_SUCCESS; } /* Debug node. */ static struct cmd_node debug_node = { DEBUG_NODE, "", 1 }; static int config_write_debug (struct vty *vty) { int write = 0; int flags = isis->debugs; if (flags & DEBUG_ADJ_PACKETS) { vty_out (vty, "debug isis adj-packets%s", VTY_NEWLINE); write++; } if (flags & DEBUG_CHECKSUM_ERRORS) { vty_out (vty, "debug isis checksum-errors%s", VTY_NEWLINE); write++; } if (flags & DEBUG_LOCAL_UPDATES) { vty_out (vty, "debug isis local-updates%s", VTY_NEWLINE); write++; } if (flags & DEBUG_PROTOCOL_ERRORS) { vty_out (vty, "debug isis protocol-errors%s", VTY_NEWLINE); write++; } if (flags & DEBUG_SNP_PACKETS) { vty_out (vty, "debug isis snp-packets%s", VTY_NEWLINE); write++; } if (flags & DEBUG_SPF_EVENTS) { vty_out (vty, "debug isis spf-events%s", VTY_NEWLINE); write++; } if (flags & DEBUG_SPF_STATS) { vty_out (vty, "debug isis spf-statistics%s", VTY_NEWLINE); write++; } if (flags & DEBUG_SPF_TRIGGERS) { vty_out (vty, "debug isis spf-triggers%s", VTY_NEWLINE); write++; } if (flags & DEBUG_UPDATE_PACKETS) { vty_out (vty, "debug isis update-packets%s", VTY_NEWLINE); write++; } if (flags & DEBUG_RTE_EVENTS) { vty_out (vty, "debug isis route-events%s", VTY_NEWLINE); write++; } if (flags & DEBUG_EVENTS) { vty_out (vty, "debug isis events%s", VTY_NEWLINE); write++; } if (flags & DEBUG_PACKET_DUMP) { vty_out (vty, "debug isis packet-dump%s", VTY_NEWLINE); write++; } if (flags & DEBUG_LSP_GEN) { vty_out (vty, "debug isis lsp-gen%s", VTY_NEWLINE); write++; } if (flags & DEBUG_LSP_SCHED) { vty_out (vty, "debug isis lsp-sched%s", VTY_NEWLINE); write++; } return write; } DEFUN (debug_isis_adj, debug_isis_adj_cmd, "debug isis adj-packets", DEBUG_STR "IS-IS information\n" "IS-IS Adjacency related packets\n") { isis->debugs |= DEBUG_ADJ_PACKETS; print_debug (vty, DEBUG_ADJ_PACKETS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_adj, no_debug_isis_adj_cmd, "no debug isis adj-packets", UNDEBUG_STR "IS-IS information\n" "IS-IS Adjacency related packets\n") { isis->debugs &= ~DEBUG_ADJ_PACKETS; print_debug (vty, DEBUG_ADJ_PACKETS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_csum, debug_isis_csum_cmd, "debug isis checksum-errors", DEBUG_STR "IS-IS information\n" "IS-IS LSP checksum errors\n") { isis->debugs |= DEBUG_CHECKSUM_ERRORS; print_debug (vty, DEBUG_CHECKSUM_ERRORS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_csum, no_debug_isis_csum_cmd, "no debug isis checksum-errors", UNDEBUG_STR "IS-IS information\n" "IS-IS LSP checksum errors\n") { isis->debugs &= ~DEBUG_CHECKSUM_ERRORS; print_debug (vty, DEBUG_CHECKSUM_ERRORS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_lupd, debug_isis_lupd_cmd, "debug isis local-updates", DEBUG_STR "IS-IS information\n" "IS-IS local update packets\n") { isis->debugs |= DEBUG_LOCAL_UPDATES; print_debug (vty, DEBUG_LOCAL_UPDATES, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_lupd, no_debug_isis_lupd_cmd, "no debug isis local-updates", UNDEBUG_STR "IS-IS information\n" "IS-IS local update packets\n") { isis->debugs &= ~DEBUG_LOCAL_UPDATES; print_debug (vty, DEBUG_LOCAL_UPDATES, 0); return CMD_SUCCESS; } DEFUN (debug_isis_err, debug_isis_err_cmd, "debug isis protocol-errors", DEBUG_STR "IS-IS information\n" "IS-IS LSP protocol errors\n") { isis->debugs |= DEBUG_PROTOCOL_ERRORS; print_debug (vty, DEBUG_PROTOCOL_ERRORS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_err, no_debug_isis_err_cmd, "no debug isis protocol-errors", UNDEBUG_STR "IS-IS information\n" "IS-IS LSP protocol errors\n") { isis->debugs &= ~DEBUG_PROTOCOL_ERRORS; print_debug (vty, DEBUG_PROTOCOL_ERRORS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_snp, debug_isis_snp_cmd, "debug isis snp-packets", DEBUG_STR "IS-IS information\n" "IS-IS CSNP/PSNP packets\n") { isis->debugs |= DEBUG_SNP_PACKETS; print_debug (vty, DEBUG_SNP_PACKETS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_snp, no_debug_isis_snp_cmd, "no debug isis snp-packets", UNDEBUG_STR "IS-IS information\n" "IS-IS CSNP/PSNP packets\n") { isis->debugs &= ~DEBUG_SNP_PACKETS; print_debug (vty, DEBUG_SNP_PACKETS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_upd, debug_isis_upd_cmd, "debug isis update-packets", DEBUG_STR "IS-IS information\n" "IS-IS Update related packets\n") { isis->debugs |= DEBUG_UPDATE_PACKETS; print_debug (vty, DEBUG_UPDATE_PACKETS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_upd, no_debug_isis_upd_cmd, "no debug isis update-packets", UNDEBUG_STR "IS-IS information\n" "IS-IS Update related packets\n") { isis->debugs &= ~DEBUG_UPDATE_PACKETS; print_debug (vty, DEBUG_UPDATE_PACKETS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_spfevents, debug_isis_spfevents_cmd, "debug isis spf-events", DEBUG_STR "IS-IS information\n" "IS-IS Shortest Path First Events\n") { isis->debugs |= DEBUG_SPF_EVENTS; print_debug (vty, DEBUG_SPF_EVENTS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_spfevents, no_debug_isis_spfevents_cmd, "no debug isis spf-events", UNDEBUG_STR "IS-IS information\n" "IS-IS Shortest Path First Events\n") { isis->debugs &= ~DEBUG_SPF_EVENTS; print_debug (vty, DEBUG_SPF_EVENTS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_spfstats, debug_isis_spfstats_cmd, "debug isis spf-statistics ", DEBUG_STR "IS-IS information\n" "IS-IS SPF Timing and Statistic Data\n") { isis->debugs |= DEBUG_SPF_STATS; print_debug (vty, DEBUG_SPF_STATS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_spfstats, no_debug_isis_spfstats_cmd, "no debug isis spf-statistics", UNDEBUG_STR "IS-IS information\n" "IS-IS SPF Timing and Statistic Data\n") { isis->debugs &= ~DEBUG_SPF_STATS; print_debug (vty, DEBUG_SPF_STATS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_spftrigg, debug_isis_spftrigg_cmd, "debug isis spf-triggers", DEBUG_STR "IS-IS information\n" "IS-IS SPF triggering events\n") { isis->debugs |= DEBUG_SPF_TRIGGERS; print_debug (vty, DEBUG_SPF_TRIGGERS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_spftrigg, no_debug_isis_spftrigg_cmd, "no debug isis spf-triggers", UNDEBUG_STR "IS-IS information\n" "IS-IS SPF triggering events\n") { isis->debugs &= ~DEBUG_SPF_TRIGGERS; print_debug (vty, DEBUG_SPF_TRIGGERS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_rtevents, debug_isis_rtevents_cmd, "debug isis route-events", DEBUG_STR "IS-IS information\n" "IS-IS Route related events\n") { isis->debugs |= DEBUG_RTE_EVENTS; print_debug (vty, DEBUG_RTE_EVENTS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_rtevents, no_debug_isis_rtevents_cmd, "no debug isis route-events", UNDEBUG_STR "IS-IS information\n" "IS-IS Route related events\n") { isis->debugs &= ~DEBUG_RTE_EVENTS; print_debug (vty, DEBUG_RTE_EVENTS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_events, debug_isis_events_cmd, "debug isis events", DEBUG_STR "IS-IS information\n" "IS-IS Events\n") { isis->debugs |= DEBUG_EVENTS; print_debug (vty, DEBUG_EVENTS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_events, no_debug_isis_events_cmd, "no debug isis events", UNDEBUG_STR "IS-IS information\n" "IS-IS Events\n") { isis->debugs &= ~DEBUG_EVENTS; print_debug (vty, DEBUG_EVENTS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_packet_dump, debug_isis_packet_dump_cmd, "debug isis packet-dump", DEBUG_STR "IS-IS information\n" "IS-IS packet dump\n") { isis->debugs |= DEBUG_PACKET_DUMP; print_debug (vty, DEBUG_PACKET_DUMP, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_packet_dump, no_debug_isis_packet_dump_cmd, "no debug isis packet-dump", UNDEBUG_STR "IS-IS information\n" "IS-IS packet dump\n") { isis->debugs &= ~DEBUG_PACKET_DUMP; print_debug (vty, DEBUG_PACKET_DUMP, 0); return CMD_SUCCESS; } DEFUN (debug_isis_lsp_gen, debug_isis_lsp_gen_cmd, "debug isis lsp-gen", DEBUG_STR "IS-IS information\n" "IS-IS generation of own LSPs\n") { isis->debugs |= DEBUG_LSP_GEN; print_debug (vty, DEBUG_LSP_GEN, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_lsp_gen, no_debug_isis_lsp_gen_cmd, "no debug isis lsp-gen", UNDEBUG_STR "IS-IS information\n" "IS-IS generation of own LSPs\n") { isis->debugs &= ~DEBUG_LSP_GEN; print_debug (vty, DEBUG_LSP_GEN, 0); return CMD_SUCCESS; } DEFUN (debug_isis_lsp_sched, debug_isis_lsp_sched_cmd, "debug isis lsp-sched", DEBUG_STR "IS-IS information\n" "IS-IS scheduling of LSP generation\n") { isis->debugs |= DEBUG_LSP_SCHED; print_debug (vty, DEBUG_LSP_SCHED, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_lsp_sched, no_debug_isis_lsp_sched_cmd, "no debug isis lsp-gen", UNDEBUG_STR "IS-IS information\n" "IS-IS scheduling of LSP generation\n") { isis->debugs &= ~DEBUG_LSP_SCHED; print_debug (vty, DEBUG_LSP_SCHED, 0); return CMD_SUCCESS; } DEFUN (show_hostname, show_hostname_cmd, "show isis hostname", SHOW_STR "IS-IS information\n" "IS-IS Dynamic hostname mapping\n") { dynhn_print_all (vty); return CMD_SUCCESS; } static void vty_out_timestr(struct vty *vty, time_t uptime) { struct tm *tm; time_t difftime = time (NULL); difftime -= uptime; tm = gmtime (&difftime); #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 if (difftime < ONE_DAY_SECOND) vty_out (vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (difftime < 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"); } DEFUN (show_isis_summary, show_isis_summary_cmd, "show isis summary", SHOW_STR "IS-IS information\n" "IS-IS summary\n") { struct listnode *node, *node2; struct isis_area *area; struct isis_spftree *spftree; int level; if (isis == NULL) { vty_out (vty, "ISIS is not running%s", VTY_NEWLINE); return CMD_SUCCESS; } vty_out (vty, "Process Id : %ld%s", isis->process_id, VTY_NEWLINE); if (isis->sysid_set) vty_out (vty, "System Id : %s%s", sysid_print (isis->sysid), VTY_NEWLINE); vty_out (vty, "Up time : "); vty_out_timestr(vty, isis->uptime); vty_out (vty, "%s", VTY_NEWLINE); if (isis->area_list) vty_out (vty, "Number of areas : %d%s", isis->area_list->count, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); if (listcount (area->area_addrs) > 0) { struct area_addr *area_addr; for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node2, area_addr)) { vty_out (vty, " Net: %s%s", isonet_print (area_addr->area_addr, area_addr->addr_len + ISIS_SYS_ID_LEN + 1), VTY_NEWLINE); } } for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { if ((area->is_type & level) == 0) continue; vty_out (vty, " Level-%d:%s", level, VTY_NEWLINE); spftree = area->spftree[level - 1]; if (spftree->pending) vty_out (vty, " IPv4 SPF: (pending)%s", VTY_NEWLINE); else vty_out (vty, " IPv4 SPF:%s", VTY_NEWLINE); vty_out (vty, " minimum interval : %d%s", area->min_spf_interval[level - 1], VTY_NEWLINE); vty_out (vty, " last run elapsed : "); vty_out_timestr(vty, spftree->last_run_timestamp); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " last run duration : %u usec%s", (u_int32_t)spftree->last_run_duration, VTY_NEWLINE); vty_out (vty, " run count : %d%s", spftree->runcount, VTY_NEWLINE); #ifdef HAVE_IPV6 spftree = area->spftree6[level - 1]; if (spftree->pending) vty_out (vty, " IPv6 SPF: (pending)%s", VTY_NEWLINE); else vty_out (vty, " IPv6 SPF:%s", VTY_NEWLINE); vty_out (vty, " minimum interval : %d%s", area->min_spf_interval[level - 1], VTY_NEWLINE); vty_out (vty, " last run elapsed : "); vty_out_timestr(vty, spftree->last_run_timestamp); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " last run duration : %llu msec%s", (unsigned long long)spftree->last_run_duration, VTY_NEWLINE); vty_out (vty, " run count : %d%s", spftree->runcount, VTY_NEWLINE); #endif } } vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } /* * This function supports following display options: * [ show isis database [detail] ] * [ show isis database [detail] ] * [ show isis database [detail] ] * [ show isis database . [detail] ] * [ show isis database . [detail] ] * [ show isis database .- [detail] ] * [ show isis database .- [detail] ] * [ show isis database detail ] * [ show isis database detail ] * [ show isis database detail . ] * [ show isis database detail . ] * [ show isis database detail .- ] * [ show isis database detail .- ] */ static int show_isis_database (struct vty *vty, const char *argv, int ui_level) { struct listnode *node; struct isis_area *area; struct isis_lsp *lsp; struct isis_dynhn *dynhn; const char *pos = argv; u_char lspid[ISIS_SYS_ID_LEN+2]; char sysid[255]; u_char number[3]; int level, lsp_count; if (isis->area_list->count == 0) return CMD_SUCCESS; memset (&lspid, 0, ISIS_SYS_ID_LEN); memset (&sysid, 0, 255); /* * extract fragment and pseudo id from the string argv * in the forms: * (a) .- or * (b) . or * (c) or * Where systemid is in the form: * xxxx.xxxx.xxxx */ if (argv) strncpy (sysid, argv, 254); if (argv && strlen (argv) > 3) { pos = argv + strlen (argv) - 3; if (strncmp (pos, "-", 1) == 0) { memcpy (number, ++pos, 2); lspid[ISIS_SYS_ID_LEN+1] = (u_char) strtol ((char *)number, NULL, 16); pos -= 4; if (strncmp (pos, ".", 1) != 0) return CMD_ERR_AMBIGUOUS; } if (strncmp (pos, ".", 1) == 0) { memcpy (number, ++pos, 2); lspid[ISIS_SYS_ID_LEN] = (u_char) strtol ((char *)number, NULL, 16); sysid[pos - argv - 1] = '\0'; } } for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); for (level = 0; level < ISIS_LEVELS; level++) { if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) { lsp = NULL; if (argv != NULL) { /* * Try to find the lsp-id if the argv string is in * the form hostname.- */ if (sysid2buff (lspid, sysid)) { lsp = lsp_search (lspid, area->lspdb[level]); } else if ((dynhn = dynhn_find_by_name (sysid))) { memcpy (lspid, dynhn->id, ISIS_SYS_ID_LEN); lsp = lsp_search (lspid, area->lspdb[level]); } else if (strncmp(unix_hostname (), sysid, 15) == 0) { memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); lsp = lsp_search (lspid, area->lspdb[level]); } } if (lsp != NULL || argv == NULL) { vty_out (vty, "IS-IS Level-%d link-state database:%s", level + 1, VTY_NEWLINE); /* print the title in all cases */ vty_out (vty, "LSP ID PduLen " "SeqNumber Chksum Holdtime ATT/P/OL%s", VTY_NEWLINE); } if (lsp) { if (ui_level == ISIS_UI_LEVEL_DETAIL) lsp_print_detail (lsp, vty, area->dynhostname); else lsp_print (lsp, vty, area->dynhostname); } else if (argv == NULL) { lsp_count = lsp_print_all (vty, area->lspdb[level], ui_level, area->dynhostname); vty_out (vty, " %u LSPs%s%s", lsp_count, VTY_NEWLINE, VTY_NEWLINE); } } } } return CMD_SUCCESS; } DEFUN (show_database_brief, show_database_cmd, "show isis database", SHOW_STR "IS-IS information\n" "IS-IS link state database\n") { return show_isis_database (vty, NULL, ISIS_UI_LEVEL_BRIEF); } DEFUN (show_database_lsp_brief, show_database_arg_cmd, "show isis database WORD", SHOW_STR "IS-IS information\n" "IS-IS link state database\n" "LSP ID\n") { return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_BRIEF); } DEFUN (show_database_lsp_detail, show_database_arg_detail_cmd, "show isis database WORD detail", SHOW_STR "IS-IS information\n" "IS-IS link state database\n" "LSP ID\n" "Detailed information\n") { return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } DEFUN (show_database_detail, show_database_detail_cmd, "show isis database detail", SHOW_STR "IS-IS information\n" "IS-IS link state database\n") { return show_isis_database (vty, NULL, ISIS_UI_LEVEL_DETAIL); } DEFUN (show_database_detail_lsp, show_database_detail_arg_cmd, "show isis database detail WORD", SHOW_STR "IS-IS information\n" "IS-IS link state database\n" "Detailed information\n" "LSP ID\n") { return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } /* * 'router isis' command */ DEFUN (router_isis, router_isis_cmd, "router isis WORD", ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag") { return isis_area_get (vty, argv[0]); } /* *'no router isis' command */ DEFUN (no_router_isis, no_router_isis_cmd, "no router isis WORD", "no\n" ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag") { return isis_area_destroy (vty, argv[0]); } /* * 'net' command */ DEFUN (net, net_cmd, "net WORD", "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") { return area_net_title (vty, argv[0]); } /* * 'no net' command */ DEFUN (no_net, no_net_cmd, "no net WORD", NO_STR "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") { return area_clear_net_title (vty, argv[0]); } void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu) { area->lsp_mtu = lsp_mtu; lsp_regenerate_schedule(area, IS_LEVEL_1_AND_2, 1); } static int isis_area_passwd_set(struct isis_area *area, int level, u_char passwd_type, const char *passwd, u_char snp_auth) { struct isis_passwd *dest; struct isis_passwd modified; int len; assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); dest = (level == IS_LEVEL_1) ? &area->area_passwd : &area->domain_passwd; memset(&modified, 0, sizeof(modified)); if (passwd_type != ISIS_PASSWD_TYPE_UNUSED) { if (!passwd) return -1; len = strlen(passwd); if (len > 254) return -1; modified.len = len; strncpy((char*)modified.passwd, passwd, 255); modified.type = passwd_type; modified.snp_auth = snp_auth; } if (memcmp(&modified, dest, sizeof(modified))) { memcpy(dest, &modified, sizeof(modified)); lsp_regenerate_schedule(area, IS_LEVEL_1|IS_LEVEL_2, 1); } return 0; } int isis_area_passwd_unset (struct isis_area *area, int level) { return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_UNUSED, NULL, 0); } int isis_area_passwd_cleartext_set (struct isis_area *area, int level, const char *passwd, u_char snp_auth) { return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_CLEARTXT, passwd, snp_auth); } int isis_area_passwd_hmac_md5_set (struct isis_area *area, int level, const char *passwd, u_char snp_auth) { return isis_area_passwd_set (area, level, ISIS_PASSWD_TYPE_HMAC_MD5, passwd, snp_auth); } static void area_resign_level (struct isis_area *area, int level) { if (area->lspdb[level - 1]) { lsp_db_destroy (area->lspdb[level - 1]); area->lspdb[level - 1] = NULL; } if (area->spftree[level - 1]) { isis_spftree_del (area->spftree[level - 1]); area->spftree[level - 1] = NULL; } #ifdef HAVE_IPV6 if (area->spftree6[level - 1]) { isis_spftree_del (area->spftree6[level - 1]); area->spftree6[level - 1] = NULL; } #endif if (area->route_table[level - 1]) { route_table_finish (area->route_table[level - 1]); area->route_table[level - 1] = NULL; } #ifdef HAVE_IPV6 if (area->route_table6[level - 1]) { route_table_finish (area->route_table6[level - 1]); area->route_table6[level - 1] = NULL; } #endif /* HAVE_IPV6 */ sched_debug("ISIS (%s): Resigned from L%d - canceling LSP regeneration timer.", area->area_tag, level); THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); area->lsp_regenerate_pending[level - 1] = 0; } void isis_area_is_type_set(struct isis_area *area, int is_type) { struct listnode *node; struct isis_circuit *circuit; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) system type change %s -> %s", area->area_tag, circuit_t2string (area->is_type), circuit_t2string (is_type)); if (area->is_type == is_type) return; /* No change */ switch (area->is_type) { case IS_LEVEL_1: if (is_type == IS_LEVEL_2) area_resign_level (area, IS_LEVEL_1); if (area->lspdb[1] == NULL) area->lspdb[1] = lsp_db_init (); if (area->route_table[1] == NULL) area->route_table[1] = route_table_init (); #ifdef HAVE_IPV6 if (area->route_table6[1] == NULL) area->route_table6[1] = route_table_init (); #endif /* HAVE_IPV6 */ break; case IS_LEVEL_1_AND_2: if (is_type == IS_LEVEL_1) area_resign_level (area, IS_LEVEL_2); else area_resign_level (area, IS_LEVEL_1); break; case IS_LEVEL_2: if (is_type == IS_LEVEL_1) area_resign_level (area, IS_LEVEL_2); if (area->lspdb[0] == NULL) area->lspdb[0] = lsp_db_init (); if (area->route_table[0] == NULL) area->route_table[0] = route_table_init (); #ifdef HAVE_IPV6 if (area->route_table6[0] == NULL) area->route_table6[0] = route_table_init (); #endif /* HAVE_IPV6 */ break; default: break; } area->is_type = is_type; /* override circuit's is_type */ if (area->is_type != IS_LEVEL_1_AND_2) { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) isis_circuit_is_type_set (circuit, is_type); } spftree_area_init (area); if (is_type & IS_LEVEL_1) lsp_generate (area, IS_LEVEL_1); if (is_type & IS_LEVEL_2) lsp_generate (area, IS_LEVEL_2); lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return; } void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, bool new_metric) { if (area->oldmetric != old_metric || area->newmetric != new_metric) { area->oldmetric = old_metric; area->newmetric = new_metric; lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } } void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit) { char new_overload_bit = overload_bit ? LSPBIT_OL : 0; if (new_overload_bit != area->overload_bit) { area->overload_bit = new_overload_bit; lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } } void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit) { char new_attached_bit = attached_bit ? LSPBIT_ATT : 0; if (new_attached_bit != area->attached_bit) { area->attached_bit = new_attached_bit; lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } } void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname) { if (area->dynhostname != dynhostname) { area->dynhostname = dynhostname; lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0); } } void isis_area_max_lsp_lifetime_set(struct isis_area *area, int level, uint16_t max_lsp_lifetime) { assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); if (area->max_lsp_lifetime[level-1] == max_lsp_lifetime) return; area->max_lsp_lifetime[level-1] = max_lsp_lifetime; lsp_regenerate_schedule(area, level, 1); } void isis_area_lsp_refresh_set(struct isis_area *area, int level, uint16_t lsp_refresh) { assert((level == IS_LEVEL_1) || (level == IS_LEVEL_2)); if (area->lsp_refresh[level-1] == lsp_refresh) return; area->lsp_refresh[level-1] = lsp_refresh; lsp_regenerate_schedule(area, level, 1); } DEFUN (log_adj_changes, log_adj_changes_cmd, "log-adjacency-changes", "Log changes in adjacency state\n") { struct isis_area *area; area = vty->index; assert (area); area->log_adj_changes = 1; return CMD_SUCCESS; } DEFUN (no_log_adj_changes, no_log_adj_changes_cmd, "no log-adjacency-changes", "Stop logging changes in adjacency state\n") { struct isis_area *area; area = vty->index; assert (area); area->log_adj_changes = 0; return CMD_SUCCESS; } #ifdef TOPOLOGY_GENERATE DEFUN (topology_generate_grid, topology_generate_grid_cmd, "topology generate grid <1-100> <1-100> <1-65000> [param] [param] " "[param]", "Topology generation for IS-IS\n" "Topology generation\n" "Grid topology\n" "X parameter of the grid\n" "Y parameter of the grid\n" "Random seed\n" "Optional param 1\n" "Optional param 2\n" "Optional param 3\n" "Topology\n") { struct isis_area *area; area = vty->index; assert (area); if (!spgrid_check_params (vty, argc, argv)) { if (area->topology) list_delete (area->topology); area->topology = list_new (); memcpy (area->top_params, vty->buf, 200); gen_spgrid_topology (vty, area->topology); remove_topology_lsps (area); generate_topology_lsps (area); /* Regenerate L1 LSP to get two way connection to the generated * topology. */ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); } return CMD_SUCCESS; } DEFUN (show_isis_generated_topology, show_isis_generated_topology_cmd, "show isis generated-topologies", SHOW_STR "ISIS network information\n" "Show generated topologies\n") { struct isis_area *area; struct listnode *node; struct listnode *node2; struct arc *arc; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { if (!area->topology) continue; vty_out (vty, "Topology for isis area: %s%s", area->area_tag, VTY_NEWLINE); vty_out (vty, "From node To node Distance%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (area->topology, node2, arc)) vty_out (vty, "%9ld %11ld %12ld%s", arc->from_node, arc->to_node, arc->distance, VTY_NEWLINE); } return CMD_SUCCESS; } /* Base IS for topology generation. */ DEFUN (topology_baseis, topology_baseis_cmd, "topology base-is WORD", "Topology generation for IS-IS\n" "A Network IS Base for this topology\n" "XXXX.XXXX.XXXX Network entity title (NET)\n") { struct isis_area *area; u_char buff[ISIS_SYS_ID_LEN]; area = vty->index; assert (area); if (sysid2buff (buff, argv[0])) sysid2buff (area->topology_baseis, argv[0]); return CMD_SUCCESS; } DEFUN (no_topology_baseis, no_topology_baseis_cmd, "no topology base-is WORD", NO_STR "Topology generation for IS-IS\n" "A Network IS Base for this topology\n" "XXXX.XXXX.XXXX Network entity title (NET)\n") { struct isis_area *area; area = vty->index; assert (area); memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); return CMD_SUCCESS; } ALIAS (no_topology_baseis, no_topology_baseis_noid_cmd, "no topology base-is", NO_STR "Topology generation for IS-IS\n" "A Network IS Base for this topology\n") DEFUN (topology_basedynh, topology_basedynh_cmd, "topology base-dynh WORD", "Topology generation for IS-IS\n" "Dynamic hostname base for this topology\n" "Dynamic hostname base\n") { struct isis_area *area; area = vty->index; assert (area); /* I hope that it's enough. */ area->topology_basedynh = strndup (argv[0], 16); return CMD_SUCCESS; } #endif /* TOPOLOGY_GENERATE */ /* IS-IS configuration write function */ int isis_config_write (struct vty *vty) { int write = 0; if (isis != NULL) { struct isis_area *area; struct listnode *node, *node2; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { /* ISIS - Area name */ vty_out (vty, "router isis %s%s", area->area_tag, VTY_NEWLINE); write++; /* ISIS - Net */ if (listcount (area->area_addrs) > 0) { struct area_addr *area_addr; for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node2, area_addr)) { vty_out (vty, " net %s%s", isonet_print (area_addr->area_addr, area_addr->addr_len + ISIS_SYS_ID_LEN + 1), VTY_NEWLINE); write++; } } /* ISIS - Dynamic hostname - Defaults to true so only display if * false. */ if (!area->dynhostname) { vty_out (vty, " no hostname dynamic%s", VTY_NEWLINE); write++; } /* ISIS - Metric-Style - when true displays wide */ if (area->newmetric) { if (!area->oldmetric) vty_out (vty, " metric-style wide%s", VTY_NEWLINE); else vty_out (vty, " metric-style transition%s", VTY_NEWLINE); write++; } else { vty_out (vty, " metric-style narrow%s", VTY_NEWLINE); write++; } /* ISIS - overload-bit */ if (area->overload_bit) { vty_out (vty, " set-overload-bit%s", VTY_NEWLINE); write++; } /* ISIS - Area is-type (level-1-2 is default) */ if (area->is_type == IS_LEVEL_1) { vty_out (vty, " is-type level-1%s", VTY_NEWLINE); write++; } else if (area->is_type == IS_LEVEL_2) { vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE); write++; } write += isis_redist_config_write(vty, area, AF_INET); write += isis_redist_config_write(vty, area, AF_INET6); /* ISIS - Lsp generation interval */ if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1]) { if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval %d%s", area->lsp_gen_interval[0], VTY_NEWLINE); write++; } } else { if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval level-1 %d%s", area->lsp_gen_interval[0], VTY_NEWLINE); write++; } if (area->lsp_gen_interval[1] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval level-2 %d%s", area->lsp_gen_interval[1], VTY_NEWLINE); write++; } } /* ISIS - LSP lifetime */ if (area->max_lsp_lifetime[0] == area->max_lsp_lifetime[1]) { if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME) { vty_out (vty, " max-lsp-lifetime %u%s", area->max_lsp_lifetime[0], VTY_NEWLINE); write++; } } else { if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME) { vty_out (vty, " max-lsp-lifetime level-1 %u%s", area->max_lsp_lifetime[0], VTY_NEWLINE); write++; } if (area->max_lsp_lifetime[1] != DEFAULT_LSP_LIFETIME) { vty_out (vty, " max-lsp-lifetime level-2 %u%s", area->max_lsp_lifetime[1], VTY_NEWLINE); write++; } } /* ISIS - LSP refresh interval */ if (area->lsp_refresh[0] == area->lsp_refresh[1]) { if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-refresh-interval %u%s", area->lsp_refresh[0], VTY_NEWLINE); write++; } } else { if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-refresh-interval level-1 %u%s", area->lsp_refresh[0], VTY_NEWLINE); write++; } if (area->lsp_refresh[1] != DEFAULT_MAX_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-refresh-interval level-2 %u%s", area->lsp_refresh[1], VTY_NEWLINE); write++; } } if (area->lsp_mtu != DEFAULT_LSP_MTU) { vty_out(vty, " lsp-mtu %u%s", area->lsp_mtu, VTY_NEWLINE); write++; } /* Minimum SPF interval. */ if (area->min_spf_interval[0] == area->min_spf_interval[1]) { if (area->min_spf_interval[0] != MINIMUM_SPF_INTERVAL) { vty_out (vty, " spf-interval %d%s", area->min_spf_interval[0], VTY_NEWLINE); write++; } } else { if (area->min_spf_interval[0] != MINIMUM_SPF_INTERVAL) { vty_out (vty, " spf-interval level-1 %d%s", area->min_spf_interval[0], VTY_NEWLINE); write++; } if (area->min_spf_interval[1] != MINIMUM_SPF_INTERVAL) { vty_out (vty, " spf-interval level-2 %d%s", area->min_spf_interval[1], VTY_NEWLINE); write++; } } /* Authentication passwords. */ if (area->area_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { vty_out(vty, " area-password md5 %s", area->area_passwd.passwd); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV)) vty_out(vty, "validate"); else vty_out(vty, "send-only"); } vty_out(vty, "%s", VTY_NEWLINE); write++; } else if (area->area_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) { vty_out(vty, " area-password clear %s", area->area_passwd.passwd); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV)) vty_out(vty, "validate"); else vty_out(vty, "send-only"); } vty_out(vty, "%s", VTY_NEWLINE); write++; } if (area->domain_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { vty_out(vty, " domain-password md5 %s", area->domain_passwd.passwd); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV)) vty_out(vty, "validate"); else vty_out(vty, "send-only"); } vty_out(vty, "%s", VTY_NEWLINE); write++; } else if (area->domain_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) { vty_out(vty, " domain-password clear %s", area->domain_passwd.passwd); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV)) vty_out(vty, "validate"); else vty_out(vty, "send-only"); } vty_out(vty, "%s", VTY_NEWLINE); write++; } if (area->log_adj_changes) { vty_out (vty, " log-adjacency-changes%s", VTY_NEWLINE); write++; } #ifdef TOPOLOGY_GENERATE if (memcmp (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN)) { vty_out (vty, " topology base-is %s%s", sysid_print ((u_char *)area->topology_baseis), VTY_NEWLINE); write++; } if (area->topology_basedynh) { vty_out (vty, " topology base-dynh %s%s", area->topology_basedynh, VTY_NEWLINE); write++; } /* We save the whole command line here. */ if (strlen(area->top_params)) { vty_out (vty, " %s%s", area->top_params, VTY_NEWLINE); write++; } #endif /* TOPOLOGY_GENERATE */ } isis_mpls_te_config_write_router(vty); } return write; } struct cmd_node isis_node = { ISIS_NODE, "%s(config-router)# ", 1 }; void isis_init () { /* Install IS-IS top node */ install_node (&isis_node, isis_config_write); install_element (VIEW_NODE, &show_isis_summary_cmd); install_element (VIEW_NODE, &show_isis_interface_cmd); install_element (VIEW_NODE, &show_isis_interface_detail_cmd); install_element (VIEW_NODE, &show_isis_interface_arg_cmd); install_element (VIEW_NODE, &show_isis_neighbor_cmd); install_element (VIEW_NODE, &show_isis_neighbor_detail_cmd); install_element (VIEW_NODE, &show_isis_neighbor_arg_cmd); install_element (VIEW_NODE, &clear_isis_neighbor_cmd); install_element (VIEW_NODE, &clear_isis_neighbor_arg_cmd); install_element (VIEW_NODE, &show_hostname_cmd); install_element (VIEW_NODE, &show_database_cmd); install_element (VIEW_NODE, &show_database_arg_cmd); install_element (VIEW_NODE, &show_database_arg_detail_cmd); install_element (VIEW_NODE, &show_database_detail_cmd); install_element (VIEW_NODE, &show_database_detail_arg_cmd); install_element (ENABLE_NODE, &show_debugging_isis_cmd); install_node (&debug_node, config_write_debug); install_element (ENABLE_NODE, &debug_isis_adj_cmd); install_element (ENABLE_NODE, &no_debug_isis_adj_cmd); install_element (ENABLE_NODE, &debug_isis_csum_cmd); install_element (ENABLE_NODE, &no_debug_isis_csum_cmd); install_element (ENABLE_NODE, &debug_isis_lupd_cmd); install_element (ENABLE_NODE, &no_debug_isis_lupd_cmd); install_element (ENABLE_NODE, &debug_isis_err_cmd); install_element (ENABLE_NODE, &no_debug_isis_err_cmd); install_element (ENABLE_NODE, &debug_isis_snp_cmd); install_element (ENABLE_NODE, &no_debug_isis_snp_cmd); install_element (ENABLE_NODE, &debug_isis_upd_cmd); install_element (ENABLE_NODE, &no_debug_isis_upd_cmd); install_element (ENABLE_NODE, &debug_isis_spfevents_cmd); install_element (ENABLE_NODE, &no_debug_isis_spfevents_cmd); install_element (ENABLE_NODE, &debug_isis_spfstats_cmd); install_element (ENABLE_NODE, &no_debug_isis_spfstats_cmd); install_element (ENABLE_NODE, &debug_isis_spftrigg_cmd); install_element (ENABLE_NODE, &no_debug_isis_spftrigg_cmd); install_element (ENABLE_NODE, &debug_isis_rtevents_cmd); install_element (ENABLE_NODE, &no_debug_isis_rtevents_cmd); install_element (ENABLE_NODE, &debug_isis_events_cmd); install_element (ENABLE_NODE, &no_debug_isis_events_cmd); install_element (ENABLE_NODE, &debug_isis_packet_dump_cmd); install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd); install_element (ENABLE_NODE, &debug_isis_lsp_gen_cmd); install_element (ENABLE_NODE, &no_debug_isis_lsp_gen_cmd); install_element (ENABLE_NODE, &debug_isis_lsp_sched_cmd); install_element (ENABLE_NODE, &no_debug_isis_lsp_sched_cmd); install_element (CONFIG_NODE, &debug_isis_adj_cmd); install_element (CONFIG_NODE, &no_debug_isis_adj_cmd); install_element (CONFIG_NODE, &debug_isis_csum_cmd); install_element (CONFIG_NODE, &no_debug_isis_csum_cmd); install_element (CONFIG_NODE, &debug_isis_lupd_cmd); install_element (CONFIG_NODE, &no_debug_isis_lupd_cmd); install_element (CONFIG_NODE, &debug_isis_err_cmd); install_element (CONFIG_NODE, &no_debug_isis_err_cmd); install_element (CONFIG_NODE, &debug_isis_snp_cmd); install_element (CONFIG_NODE, &no_debug_isis_snp_cmd); install_element (CONFIG_NODE, &debug_isis_upd_cmd); install_element (CONFIG_NODE, &no_debug_isis_upd_cmd); install_element (CONFIG_NODE, &debug_isis_spfevents_cmd); install_element (CONFIG_NODE, &no_debug_isis_spfevents_cmd); install_element (CONFIG_NODE, &debug_isis_spfstats_cmd); install_element (CONFIG_NODE, &no_debug_isis_spfstats_cmd); install_element (CONFIG_NODE, &debug_isis_spftrigg_cmd); install_element (CONFIG_NODE, &no_debug_isis_spftrigg_cmd); install_element (CONFIG_NODE, &debug_isis_rtevents_cmd); install_element (CONFIG_NODE, &no_debug_isis_rtevents_cmd); install_element (CONFIG_NODE, &debug_isis_events_cmd); install_element (CONFIG_NODE, &no_debug_isis_events_cmd); install_element (CONFIG_NODE, &debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &debug_isis_lsp_gen_cmd); install_element (CONFIG_NODE, &no_debug_isis_lsp_gen_cmd); install_element (CONFIG_NODE, &debug_isis_lsp_sched_cmd); install_element (CONFIG_NODE, &no_debug_isis_lsp_sched_cmd); install_element (CONFIG_NODE, &router_isis_cmd); install_element (CONFIG_NODE, &no_router_isis_cmd); install_default (ISIS_NODE); install_element (ISIS_NODE, &net_cmd); install_element (ISIS_NODE, &no_net_cmd); install_element (ISIS_NODE, &log_adj_changes_cmd); install_element (ISIS_NODE, &no_log_adj_changes_cmd); #ifdef TOPOLOGY_GENERATE install_element (ISIS_NODE, &topology_generate_grid_cmd); install_element (ISIS_NODE, &topology_baseis_cmd); install_element (ISIS_NODE, &topology_basedynh_cmd); install_element (ISIS_NODE, &no_topology_baseis_cmd); install_element (ISIS_NODE, &no_topology_baseis_noid_cmd); install_element (VIEW_NODE, &show_isis_generated_topology_cmd); #endif /* TOPOLOGY_GENERATE */ } quagga-1.2.4/isisd/isisd.conf.sample000066400000000000000000000014251325323223500173420ustar00rootroot00000000000000! -*- isis -*- ! ! ISISd sample configuration file ! hostname isisd password foo enable password foo log stdout !log file /tmp/isisd.log ! ! router isis DEAD net 47.0023.0000.0003.0300.0100.0102.0304.0506.00 ! is-type level-1 ! -- set the lifetime either for level-1, level-2 or both ! lsp-lifetime level-1 65535 ! lsp-lifetime level-2 65535 ! lsp-lifetime 65535 ! hostname isisd-router ! area-password foobar ! domain-password foobar interface eth0 ip router isis DEAD ! isis hello-interval 5 ! isis lsp-interval 1000 ! -- optional ! isis circuit-type level-1 ! isis password lallaa level-1 ! isis metric 1 level-1 ! isis csnp-interval 5 level-1 ! isis retransmit-interval 10 ! isis retransmit-throttle-interval ! isis hello-multiplier 2 level-1 ! isis priority 64 ! quagga-1.2.4/isisd/isisd.h000066400000000000000000000163321325323223500153670ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - isisd.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef ISISD_H #define ISISD_H #define ISISD_VERSION "0.0.7" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_redist.h" #include "isis_flags.h" #include "dict.h" /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ /* #define EXTREME_TLV_DEBUG */ struct isis { u_long process_id; int sysid_set; u_char sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */ u_int32_t router_id; /* Router ID from zebra */ struct list *area_list; /* list of IS-IS areas */ struct list *init_circ_list; struct list *nexthops; /* IPv4 next hops from this IS */ #ifdef HAVE_IPV6 struct list *nexthops6; /* IPv6 next hops from this IS */ #endif /* HAVE_IPV6 */ u_char max_area_addrs; /* maximumAreaAdresses */ struct area_addr *man_area_addrs; /* manualAreaAddresses */ u_int32_t debugs; /* bitmap for debug */ time_t uptime; /* when did we start */ struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */ struct route_table *ext_info[REDIST_PROTOCOL_COUNT]; }; extern struct isis *isis; struct isis_area { struct isis *isis; /* back pointer */ dict_t *lspdb[ISIS_LEVELS]; /* link-state dbs */ struct isis_spftree *spftree[ISIS_LEVELS]; /* The v4 SPTs */ struct route_table *route_table[ISIS_LEVELS]; /* IPv4 routes */ #ifdef HAVE_IPV6 struct isis_spftree *spftree6[ISIS_LEVELS]; /* The v6 SPTs */ struct route_table *route_table6[ISIS_LEVELS]; /* IPv6 routes */ #endif #define DEFAULT_LSP_MTU 1497 unsigned int lsp_mtu; /* Size of LSPs to generate */ struct list *circuit_list; /* IS-IS circuits */ struct flags flags; struct thread *t_tick; /* LSP walker */ struct thread *t_lsp_refresh[ISIS_LEVELS]; /* t_lsp_refresh is used in two ways: * a) regular refresh of LSPs * b) (possibly throttled) updates to LSPs * * The lsp_regenerate_pending flag tracks whether the timer is active * for the a) or the b) case. * * It is of utmost importance to clear this flag when the timer is * rescheduled for normal refresh, because otherwise, updates will * be delayed until the next regular refresh. */ int lsp_regenerate_pending[ISIS_LEVELS]; /* * Configurables */ struct isis_passwd area_passwd; struct isis_passwd domain_passwd; /* do we support dynamic hostnames? */ char dynhostname; /* do we support new style metrics? */ char newmetric; char oldmetric; /* identifies the routing instance */ char *area_tag; /* area addresses for this area */ struct list *area_addrs; u_int16_t max_lsp_lifetime[ISIS_LEVELS]; char is_type; /* level-1 level-1-2 or level-2-only */ /* are we overloaded? */ char overload_bit; /* L1/L2 router identifier for inter-area traffic */ char attached_bit; u_int16_t lsp_refresh[ISIS_LEVELS]; /* minimum time allowed before lsp retransmission */ u_int16_t lsp_gen_interval[ISIS_LEVELS]; /* min interval between between consequtive SPFs */ u_int16_t min_spf_interval[ISIS_LEVELS]; /* the percentage of LSP mtu size used, before generating a new frag */ int lsp_frag_threshold; int ip_circuits; /* logging adjacency changes? */ u_char log_adj_changes; #ifdef HAVE_IPV6 int ipv6_circuits; #endif /* HAVE_IPV6 */ /* Counters */ u_int32_t circuit_state_changes; struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT] [ZEBRA_ROUTE_MAX + 1][ISIS_LEVELS]; struct route_table *ext_reach[REDIST_PROTOCOL_COUNT][ISIS_LEVELS]; #ifdef TOPOLOGY_GENERATE struct list *topology; u_char topology_baseis[ISIS_SYS_ID_LEN]; /* IS for the first IS emulated. */ char *topology_basedynh; /* Dynamic hostname base. */ char top_params[200]; /* FIXME: what is reasonable? */ #endif /* TOPOLOGY_GENERATE */ }; void isis_init (void); void isis_new(unsigned long); struct isis_area *isis_area_create(const char *); struct isis_area *isis_area_lookup (const char *); int isis_area_get (struct vty *vty, const char *area_tag); void print_debug(struct vty *, int, int); void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit); void isis_area_attached_bit_set(struct isis_area *area, bool attached_bit); void isis_area_dynhostname_set(struct isis_area *area, bool dynhostname); void isis_area_metricstyle_set(struct isis_area *area, bool old_metric, bool new_metric); void isis_area_lsp_mtu_set(struct isis_area *area, unsigned int lsp_mtu); void isis_area_is_type_set(struct isis_area *area, int is_type); void isis_area_max_lsp_lifetime_set(struct isis_area *area, int level, uint16_t max_lsp_lifetime); void isis_area_lsp_refresh_set(struct isis_area *area, int level, uint16_t lsp_refresh); /* IS_LEVEL_1 sets area_passwd, IS_LEVEL_2 domain_passwd */ int isis_area_passwd_unset (struct isis_area *area, int level); int isis_area_passwd_cleartext_set (struct isis_area *area, int level, const char *passwd, u_char snp_auth); int isis_area_passwd_hmac_md5_set (struct isis_area *area, int level, const char *passwd, u_char snp_auth); void isis_vty_init (void); /* Master of threads. */ extern struct thread_master *master; #define DEBUG_ADJ_PACKETS (1<<0) #define DEBUG_CHECKSUM_ERRORS (1<<1) #define DEBUG_LOCAL_UPDATES (1<<2) #define DEBUG_PROTOCOL_ERRORS (1<<3) #define DEBUG_SNP_PACKETS (1<<4) #define DEBUG_UPDATE_PACKETS (1<<5) #define DEBUG_SPF_EVENTS (1<<6) #define DEBUG_SPF_STATS (1<<7) #define DEBUG_SPF_TRIGGERS (1<<8) #define DEBUG_RTE_EVENTS (1<<9) #define DEBUG_EVENTS (1<<10) #define DEBUG_ZEBRA (1<<11) #define DEBUG_PACKET_DUMP (1<<12) #define DEBUG_LSP_GEN (1<<13) #define DEBUG_LSP_SCHED (1<<14) #define lsp_debug(...) \ do \ { \ if (isis->debugs & DEBUG_LSP_GEN) \ zlog_debug(__VA_ARGS__); \ } \ while (0) #define sched_debug(...) \ do \ { \ if (isis->debugs & DEBUG_LSP_SCHED) \ zlog_debug(__VA_ARGS__); \ } \ while (0) #define DEBUG_TE (1<<13) #define IS_DEBUG_ISIS(x) (isis->debugs & x) #endif /* ISISD_H */ quagga-1.2.4/isisd/iso_checksum.c000066400000000000000000000037051325323223500167230ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - iso_checksum.c * ISO checksum related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #include #include "iso_checksum.h" #include "checksum.h" /* * Calculations of the OSI checksum. * ISO/IEC 8473 defines the sum as * * L * sum a (mod 255) = 0 * 1 i * * L * sum (L-i+1)a (mod 255) = 0 * 1 i * */ /* * Verifies that the checksum is correct. * Return 0 on correct and 1 on invalid checksum. * Based on Annex C.4 of ISO/IEC 8473 */ int iso_csum_verify (u_char * buffer, int len, uint16_t * csum) { u_int16_t checksum; u_int32_t c0; u_int32_t c1; c0 = *csum & 0xff00; c1 = *csum & 0x00ff; /* * If both are zero return correct */ if (c0 == 0 && c1 == 0) return 0; /* * If either, but not both are zero return incorrect */ if (c0 == 0 || c1 == 0) return 1; /* Offset of checksum from the start of the buffer */ int offset = (u_char *) csum - buffer; checksum = fletcher_checksum(buffer, len, offset); if (checksum == *csum) return 0; return 1; } quagga-1.2.4/isisd/iso_checksum.h000066400000000000000000000022241325323223500167230ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - iso_checksum.c * ISO checksum related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ #ifndef _ZEBRA_ISO_CSUM_H #define _ZEBRA_ISO_CSUM_H int iso_csum_verify (u_char * buffer, int len, uint16_t * csum); #endif /* _ZEBRA_ISO_CSUM_H */ quagga-1.2.4/isisd/topology/000077500000000000000000000000001325323223500157525ustar00rootroot00000000000000quagga-1.2.4/isisd/topology/Makefile.am000066400000000000000000000007211325323223500200060ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libtopology.a libtopology_a_SOURCES = \ spgrid.c random.c libtopology_a_DEPENDENCIES = @LIB_REGEX@ libtopology_a_LIBADD = @LIB_REGEX@ ../../lib/libzebra.la noinst_HEADERS = \ spgrid.h ## File dependency. quagga-1.2.4/isisd/topology/Makefile.in000066400000000000000000000457731325323223500200370ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = isisd/topology ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libtopology_a_AR = $(AR) $(ARFLAGS) am_libtopology_a_OBJECTS = spgrid.$(OBJEXT) random.$(OBJEXT) libtopology_a_OBJECTS = $(am_libtopology_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libtopology_a_SOURCES) DIST_SOURCES = $(libtopology_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libtopology.a libtopology_a_SOURCES = \ spgrid.c random.c libtopology_a_DEPENDENCIES = @LIB_REGEX@ libtopology_a_LIBADD = @LIB_REGEX@ ../../lib/libzebra.la noinst_HEADERS = \ spgrid.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu isisd/topology/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu isisd/topology/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libtopology.a: $(libtopology_a_OBJECTS) $(libtopology_a_DEPENDENCIES) $(EXTRA_libtopology_a_DEPENDENCIES) $(AM_V_at)-rm -f libtopology.a $(AM_V_AR)$(libtopology_a_AR) libtopology.a $(libtopology_a_OBJECTS) $(libtopology_a_LIBADD) $(AM_V_at)$(RANLIB) libtopology.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spgrid.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # 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: quagga-1.2.4/isisd/topology/random.c000066400000000000000000000130141325323223500173750ustar00rootroot00000000000000/*********************************************************************/ /* */ /* current processor time in seconds */ /* difference between two calls is processor time spent by your code */ /* needs: , */ /* depends on compiler and OS */ /* */ /*********************************************************************/ #include #include #include /* * Prototypes. */ unsigned long timer(void); void init_rand(long); double rand01(void); double randg01(void); long nrand(long); void free_arc(void *); unsigned long timer () { struct tms hold; times(&hold); return (unsigned long) ((float) (hold.tms_utime) / 60.0); } /*********************************************************************/ /* */ /* Family of random number generators */ /* */ /* Initialisation: */ /* void init_rand ( seed ); */ /* long seed - any positive number */ /* if seed<=0 init_rand takes time */ /* from timer instead of seed */ /* */ /* Whole number uniformly distributed on [0,n): */ /* long nrand (n); */ /* long n */ /* */ /* Real number uniformly distributed on [0,1] */ /* double rand01(); */ /* */ /* Real number with Gauss(0,1) disitribution: */ /* double randg01(); */ /* */ /* Algorithm: */ /* x(n+1) = (x(n) * 5^13) mod 2^31 */ /* */ /*********************************************************************/ unsigned long internal_seed; void init_rand ( init_seed ) long init_seed; { internal_seed = ( init_seed > 0 ) ? (unsigned long) init_seed : (unsigned long) timer(); /* only odd numbers are acceptable */ if ( internal_seed % 2 == 0 ) internal_seed --; } /*********************************************************************/ /* */ /* Internal function irand may depend on OS and compiler */ /* */ /* irand assumption: */ /* unsigned long i,j; */ /* if i*j > max(unsigned long) */ /* 1. No overflow interruption */ /* 2. i*j = i*j mod max(unsigned long) */ /* */ /* This assumption is true for a lot of computers. */ /* If your computer fails: */ /* rename: irand <---> xrand */ /* */ /*********************************************************************/ #define A 1220703125 #define B 2147483647 #define BF 2147483647. static long irand () { internal_seed = ( internal_seed * A ) & B; return (long) internal_seed ; } #if 0 /* Not used. */ /*********************************************************************/ /* */ /* computer independent variant of irand */ /* */ /*********************************************************************/ #define T15 32768 #define T16 65536 #define A1 37252 #define A2 29589 static long xrand() { unsigned long is1, is2; is1 = internal_seed / T15; is2 = internal_seed % T15; internal_seed = ( (((is2 * A1) + (is1 * A2))% T16 )* T15 + (is2 * A2) ) & B; return (long) ( internal_seed ) ; } #endif /*********************************************************************/ double rand01() { return (double) (irand() / BF) ; } /*********************************************************************/ #define NK 12 double randg01() { int i; double sum = 0; for ( i = 0; i < NK; i++ ) sum += rand01(); return sum - 6.; /* if NK != 12 then you must return (12/NK)*sum - (NK/2) */ } #undef NK /*********************************************************************/ long nrand ( n ) long n; { return (long) ( rand01() * (double) n ); } /*********************************************************************/ #undef A #undef A1 #undef A2 #undef B #undef BF #undef T15 #undef T16 quagga-1.2.4/isisd/topology/spgrid.c000066400000000000000000000445051325323223500174160ustar00rootroot00000000000000#include #include #include #include #include "random.c" #include "thread.h" #include "vty.h" #include "log.h" #include "linklist.h" #include "spgrid.h" #define DASH '-' #define VERY_FAR 100000000 #define DOUBLE_CYCLE 0 #define CYCLE 1 #define PATH 2 #define NO 0 #define YES 1 #define NODE( x, y ) (x*Y + y + 1) /* * Prototypes. */ void free_arc(void *); void help(struct vty *); void print_arc(struct vty *, struct list *, long, long, long); void hhelp(struct vty *); void usage(struct vty *); const char *graph_type[] = { "double cycle", "cycle", "path" }; struct arc *arc; char args[30]; long X, /* horizontal size of grid */ Y; /* vertical size of grid */ long x, y, yy1, yy2, yyp, dl, dx, xn, yyn, count, *mess; double n; long n0, source, i, i0, j, dij; double m; long m0, mc, k; long *p, p_t, l, lx; long seed, seed1, seed2; int ext=0; /* initialized by default values */ /* variables for generating one layer */ /* variables for generating spanning graph */ int c_f = 0, cw_f = 0, cm_f = 0, cl_f = 0; int cw = DOUBLE_CYCLE; /* type of spanning graph */ long cm = 0, /* lower bound of the interval */ cl = 100; /* upper bound of the interval */ /* variables for generating additional arcs */ int a_f = 0, ax_f = 0, am_f = 0, al_f = 0; long ax = 0, /* number of additional arcs */ am = 0, /* lower bound of the interval */ al = 100; /* upper bound of the interval */ /* variables for inter-layer arcs */ int i_f = 0, ip_f = 0, ix_f = 0, ih_f = 0, im_f = 0, il_f = 0, in_f = 0, is_f = 0; int ip = NO; /* to mess or not to mess */ long ix = 1, /* number of interlayered arcs in a NODE */ ih = 1, /* step between two layeres */ il = 10000, /* upper bound of the interval */ im = 1000; /* lower bound of the interval */ double in = 1, /* l *= in * |x1-x2| */ is = 0; /* l *= is * |x1-x2|^2 */ /* variables for artifical source */ int s_f = 0, sl_f = 0, sm_f = 0; long sl = VERY_FAR, /* upper bound of artifical arc */ sm, /* lower bound of artifical arc */ s; /* variables for potentials */ int p_f = 0, pl_f = 0, pm_f = 0, pn_f = 0, ps_f = 0; long pl, /* upper bound of the interval */ pm; /* lower bound of the interval */ double pn = 0, /* p += ln * (x+1) */ ps = 0; /* p += ls * (x+1)^2 */ int np; /* number of parameter parsing now */ void free_arc (void *val) { free(val); } void print_arc (struct vty *vty, struct list *topology, long i, long j, long length) { struct arc *myarc; l = length; if ( p_f ) l += ( p[i] - p[j] ); // vty_out (vty,"a %8ld %8ld %12ld%s", i, j, l ,VTY_NEWLINE); myarc = malloc (sizeof(struct arc)); myarc->from_node = i; myarc->to_node = j; myarc->distance = l; topology->del = free_arc; listnode_add (topology, myarc); } /* ---- help ---- */ void help (struct vty *vty) { // if ( args[2] == 'h') hhelp (vty); vty_out (vty,"grid network generator for shortest paths problem.%s",VTY_NEWLINE); vty_out (vty,"Generates problems in extended DIMACS format.%s",VTY_NEWLINE); vty_out (vty,"X Y seed [ -cl#i -cm#i -c{c|d|p} -ip -il#i -im#i -p -pl#i -pm#i... ]%s",VTY_NEWLINE); vty_out (vty,"#i - integer number%s",VTY_NEWLINE); vty_out (vty,"-cl#i - #i is the upper bound on layer arc lengths (default 100)%s",VTY_NEWLINE); vty_out (vty,"-cm#i - #i is the lower bound on layer arc lengths (default 0)%s",VTY_NEWLINE); vty_out (vty,"-c#t - #t is the type of connecting graph: { c | d | p }%s",VTY_NEWLINE); vty_out (vty," c - cycle, d - double cycle, p - path (default d)%s",VTY_NEWLINE); vty_out (vty,"-ip - shuffle inter-layer arcs (default NO)%s",VTY_NEWLINE); vty_out (vty,"-il#i - #i is the upper bound on inter-layer arc lengths (default 10000)%s",VTY_NEWLINE); vty_out (vty,"-im#i - #i is the lower bound on inter-layer arc lengths (default 1000)%s",VTY_NEWLINE); vty_out (vty,"-p - generate potentials%s",VTY_NEWLINE); vty_out (vty,"-pl#i - #i is the upper bound on potentials (default il)%s",VTY_NEWLINE); vty_out (vty,"-pm#i - #i is the lower bound on potentials (default im)%s",VTY_NEWLINE); vty_out (vty,"%s",VTY_NEWLINE); vty_out (vty,"-hh - extended help%s",VTY_NEWLINE); } /* --------- sophisticated help ------------ */ void hhelp (struct vty *vty) { /* zlog_info ( "\n'%s' - grid network generator for shortest paths problem.\n\ Generates problems in extended DIMACS format.\n\ \n\ %s X Y seed [ -cl#i -cm#i -c{c|d|p}\n\ -ax#i -al#i -am#i\n\ -ip -il#i -im#i -in#i -is#i -ix#i -ih#i\n\ -p -pl#i -pm#i -pn#f -ps#f\n\ -s -sl#i -sm#i\n\ ]\n\ %s -hh file_name\n\ \n\ #i - integer number #f - real number\n\ \n\ Parameters of connecting arcs within one layer:\n\ -cl#i - #i is the upper bound on arc lengths (default 100)\n\ -cm#i - #i is the lower bound on arc lengths (default 0)\n\ -c#t - #t is the type of connecting graph: { c | d | p }\n\ c - cycle, d - double cycle, p - path (default d)\n\ \n\ Parameters of additional arcs within one layer:\n\ -ax#i - #i is the number of additional arcs (default 0)\n\ -al#i - #i is the upper bound on arc lengths (default 100)\n\ -am#i - #i is the lower bound on arc lengths (default 0)\n\ \n\ Interlayerd arc parameters:\n\ -ip - shuffle inter-layer arcs (default NO)\n\ -il#i - #i is the upper bound on arc lengths (default 10000)\n\ -im#i - #i is the lower bound on arc lengths (default 1000)\n\ -in#f - multiply l(i, j) by #f * x(j)-x(i) (default 1)\n\ if #f=0 - don't multiply\n\ -is#f - multiply l(i, j) by #f * (x(j)-x(i))^2 (default NO)\n\ -ix#i - #i - is the number of arcs from a node (default 1)\n\ -ih#i - #i - is the step between connected layers (default 1)\n\ \n\ Potential parameters:\n\ -p - generate potentials \n\ -pl#i - #i is the upper bound on potentials (default ll)\n\ -pm#i - #i is the lower bound on potentials (default lm)\n\ -pn#f - multiply p(i) by #f * x(i) (default NO)\n\ -ps#f - multiply p(i) by #f * x(i)^2 (default NO)\n\ \n"); zlog_info ( " Artificial source parameters:\n\ -s - generate artificial source with default connecting arc lengths\n\ -sl#i - #i is the upper bound on art. arc lengths (default 100000000)\n\ -sm#i - #i is the lower bound on art. arc lengths (default sl)\n\" );*/ } /* ----- wrong usage ----- */ void usage (struct vty *vty) { vty_out (vty,"usage: X Y seed [-ll#i -lm#i -cl#i -p -pl#i -pm#i ...]%s",VTY_NEWLINE); vty_out (vty,"help: -h or -hh%s",VTY_NEWLINE); if ( np > 0 ) zlog_err ("error in parameter # %d\n\n", np ); } /* parsing parameters */ /* checks the validity of incoming parameters */ int spgrid_check_params ( struct vty *vty, int argc, const char **argv) { /* initialized by default values */ ext=0; /* variables for generating one layer */ /* variables for generating spanning graph */ c_f = 0; cw_f = 0; cm_f = 0; cl_f = 0; cw = PATH; /* type of spanning graph */ cm = 0; /* lower bound of the interval */ cl = 63; /* upper bound of the interval */ /* variables for generating additional arcs */ a_f = 0; ax_f = 0; am_f = 0; al_f = 0; ax = 0; /* number of additional arcs */ am = 0; /* lower bound of the interval */ al = 63; /* upper bound of the interval */ /* variables for inter-layer arcs */ i_f = 0; ip_f = 0; ix_f = 0; ih_f = 0; im_f = 0; il_f = 0; in_f = 0; is_f = 0; ip = NO; /* to mess or not to mess */ ix = 1; /* number of interlayered arcs in a NODE */ ih = 1; /* step between two layeres */ il = 63; //was 10000; /* upper bound of the interval */ im = 0; //was 1000; /* lower bound of the interval */ in = 1; /* l *= in * |x1-x2| */ is = 0; /* l *= is * |x1-x2|^2 */ /* variables for artifical source */ s_f = 0; sl_f = 0; sm_f = 0; sl = VERY_FAR; /* upper bound of artifical arc */ /* variables for potentials */ p_f = 0; pl_f = 0; pm_f = 0; pn_f = 0; ps_f = 0; pn = 0; /* p += ln * (x+1) */ ps = 0; /* p += ls * (x+1)^2 */ if ( argc < 1 ) { usage (vty); return 1; } np = 0; strcpy ( args, argv[0] ); if ((args[0] == DASH) && (args[1] == 'h')) help (vty); if ( argc < 3 ) { usage (vty); return 1; } /* first parameter - horizontal size */ np = 1; if ( ( X = atoi ( argv[0] ) ) < 1 ) { usage (vty); return 1; } /* second parameter - vertical size */ np = 2; if ( ( Y = atoi ( argv[1] ) ) < 1 ) { usage (vty); return 1; } /* third parameter - seed */ np=3; if ( ( seed = atoi ( argv[2] ) ) <= 0 ) { usage (vty); return 1; } /* other parameters */ for ( np = 3; np < argc; np ++ ) { strcpy ( args, argv[np] ); if ( args[0] != DASH ) { usage (vty); return 1; } switch ( args[1] ) { case 'c' : /* spanning graph in one layer */ c_f = 1; switch ( args[2] ) { case 'l': /* upper bound of the interval */ cl_f = 1; cl = atol ( &args[3] ); break; case 'm': /* lower bound */ cm_f = 1; cm = atol ( &args[3] ); break; case 'c': /* type - cycle */ cw_f = 1; cw = CYCLE; break; case 'd': /* type - double cycle */ cw_f = 1; cw = DOUBLE_CYCLE; break; case 'p': /* type - path */ cw_f = 1; cw = PATH; break; default: /* unknown switch value */ usage (vty); return 1; } break; case 'a' : /* additional arcs in one layer */ a_f = 1; switch ( args[2] ) { case 'l': /* upper bound of the interval */ al_f = 1; al = atol ( &args[3] ); break; case 'm': /* lower bound */ am_f = 1; am = atol ( &args[3] ); break; case 'x': /* number of additional arcs */ ax_f = 1; ax = atol ( &args[3] ); if ( ax < 0 ) { usage (vty); return 1; } break; default: /* unknown switch value */ { usage (vty); return 1; } } break; case 'i' : /* interlayered arcs */ i_f = 1; switch ( args[2] ) { case 'l': /* upper bound */ il_f = 1; il = atol ( &args[3] ); break; case 'm': /* lower bound */ im_f = 1; im = atol ( &args[3] ); break; case 'n': /* additional length: l *= in*|i1-i2| */ in_f = 1; in = atof ( &args[3] ); break; case 's': /* additional length: l *= is*|i1-i2|^2 */ is_f = 1; is = atof ( &args[3] ); break; case 'p': /* mess interlayered arcs */ ip_f = 1; ip = YES; break; case 'x': /* number of interlayered arcs */ ix_f = 1; ix = atof ( &args[3] ); if ( ix < 1 ) { usage (vty); return 1; } break; case 'h': /* step between two layeres */ ih_f = 1; ih = atof ( &args[3] ); if ( ih < 1 ) { usage (vty); return 1; } break; default: /* unknown switch value */ usage (vty); return 1; } break; case 's' : /* additional source */ s_f = 1; if ( strlen ( args ) > 2 ) { switch ( args[2] ) { case 'l': /* upper bound of art. arc */ sl_f = 1; sl = atol ( &args[3] ); break; case 'm': /* lower bound of art. arc */ sm_f = 1; sm = atol ( &args[3] ); break; default: /* unknown switch value */ usage (vty); return 1; } } break; case 'p' : /* potentials */ p_f = 1; if ( strlen ( args ) > 2 ) { switch ( args[2] ) { case 'l': /* upper bound */ pl_f = 1; pl = atol ( &args[3] ); break; case 'm': /* lower bound */ pm_f = 1; pm = atol ( &args[3] ); break; case 'n': /* additional: p *= pn*(x+1) */ pn_f = 1; pn = atof ( &args[3] ); break; case 's': /* additional: p = ps* (x+1)^2 */ ps_f = 1; ps = atof ( &args[3] ); break; default: /* unknown switch value */ usage (vty); return 1; } } break; default: /* unknoun case */ usage (vty); return 1; } } return 0; } /* generator of layered networks for the shortest paths problem; extended DIMACS format for output */ int gen_spgrid_topology (struct vty *vty, struct list *topology) { /* ----- ajusting parameters ----- */ /* spanning */ if ( cl < cm ) { lx = cl; cl = cm; cm = lx; } /* additional arcs */ if ( al < am ) { lx = al; al = am; am = lx; } /* interlayered arcs */ if ( il < im ) { lx = il; il = im; im = lx; } /* potential parameters */ if ( p_f ) { if ( ! pl_f ) pl = il; if ( ! pm_f ) pm = im; if ( pl < pm ) { lx = pl; pl = pm; pm = lx; } } /* number of nodes and arcs */ n = (double)X *(double)Y + 1; m = (double)Y; /* arcs from source */ switch ( cw ) { case PATH: mc = (double)Y - 1; break; case CYCLE: mc = (double)Y; break; case DOUBLE_CYCLE: mc = 2*(double)Y; } m += (double)X * (double)mc; /* spanning arcs */ m += (double)X * (double)ax; /* additional arcs */ /* interlayered arcs */ for ( x = 0; x < X; x ++ ) { dl = ( ( X - x - 1 ) + ( ih - 1 ) ) / ih; if ( dl > ix ) dl = ix; m += (double)Y * (double)dl; } /* artifical source parameters */ if ( s_f ) { m += n; n ++ ; if ( ! sm_f ) sm = sl; if ( sl < sm ) { lx = sl; sl = sm; sm = lx; } } if ( n >= (double)LONG_MAX || m >= (double)LONG_MAX ) { zlog_err ("Too large problem. It can't be generated\n"); exit (4); } else { n0 = (long)n; m0 = (long)m; } if ( ip_f ) mess = (long*) calloc ( Y, sizeof ( long ) ); /* printing title */ zlog_info ("Generating topology for ISIS"); source = ( s_f ) ? n0-1 : n0; if ( p_f ) /* generating potentials */ { p = (long*) calloc ( n0+1, sizeof (long) ); seed1 = 2*seed + 1; init_rand ( seed1); pl = pl - pm + 1; for ( x = 0; x < X; x ++ ) { for ( y = 0; y < Y; y ++ ) { p_t = pm + nrand ( pl ); if ( pn_f ) p_t *= (long) ( (1 + x) * pn ); if ( ps_f ) p_t *= (long) ( (1 + x) * ( (1 + x) * ps )); p[ NODE ( x, y ) ] = p_t; } } p[n0] = 0; if ( s_f ) p[n0-1] = 0; } if ( s_f ) /* additional arcs from artifical source */ { seed2 = 3*seed + 1; init_rand ( seed2 ); sl = sl - sm + 1; for ( x = X - 1; x >= 0; x -- ) for ( y = Y - 1; y >= 0; y -- ) { i = NODE ( x, y ); s = sm + nrand ( sl ); print_arc (vty, topology, n0, i, s ); } print_arc (vty, topology, n0, n0-1, 0 ); } /* ----- generating arcs within layers ----- */ init_rand ( seed ); cl = cl - cm + 1; al = al - am + 1; for ( x = 0; x < X; x ++ ) { /* generating arcs within one layer */ for ( y = 0; y < Y-1; y ++ ) { /* generating spanning graph */ i = NODE ( x, y ); j = NODE ( x, y+1 ); l = cm + nrand ( cl ); print_arc (vty, topology, i, j, l ); if ( cw == DOUBLE_CYCLE ) { l = cm + nrand ( cl ); print_arc (vty, topology, j, i, l ); } } if ( cw <= CYCLE ) { i = NODE ( x, Y-1 ); j = NODE ( x, 0 ); l = cm + nrand ( cl ); print_arc (vty, topology, i, j, l ); if ( cw == DOUBLE_CYCLE ) { l = cm + nrand ( cl ); print_arc (vty, topology, j, i, l ); } } /* generating additional arcs */ for ( k = ax; k > 0; k -- ) { yy1 = nrand ( Y ); do yy2 = nrand ( Y ); while ( yy2 == yy1 ); i = NODE ( x, yy1 ); j = NODE ( x, yy2 ); l = am + nrand ( al ); print_arc (vty, topology, i, j, l ); } } /* ----- generating interlayered arcs ------ */ il = il - im + 1; /* arcs from the source */ for ( y = 0; y < Y; y ++ ) { l = im + nrand ( il ); i = NODE ( 0, y ); print_arc (vty, topology, source, i, l ); } for ( x = 0; x < X-1; x ++ ) { /* generating arcs from one layer */ for ( count = 0, xn = x + 1; count < ix && xn < X; count ++, xn += ih ) { if ( ip_f ) for ( y = 0; y < Y; y ++ ) mess[y] = y; for ( y = 0; y < Y; y ++ ) { i = NODE ( x, y ); dx = xn - x; if ( ip_f ) { yyp = nrand(Y-y); yyn = mess[ yyp ]; mess[ yyp ] = mess[ Y - y - 1 ]; } else yyn = y; j = NODE ( xn, yyn ); l = im + nrand ( il ); if ( in != 0 ) l *= (long) ( in * dx ); if ( is_f ) l *= (long) ( ( is * dx ) * dx ); print_arc (vty, topology, i, j, l ); } } } /* all is done */ return ext; return 0; } quagga-1.2.4/isisd/topology/spgrid.h000066400000000000000000000025001325323223500174100ustar00rootroot00000000000000/* * IS-IS Rout(e)ing protocol - topology/spgrid.h Routines for manipulation of SSN and SRM flags * Copyright (C) 2001 Sampo Saaristo, Ofer Wald * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas 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. */ /* * Based on: * SPLIB Copyright C 1994 by Cherkassky, Goldberg, and Radzik * */ #ifndef _ZEBRA_ISIS_TOPOLOGY_SPGRID_H #define _ZEBRA_ISIS_TOPOLOGY_SPGRID_H struct arc { long from_node; long to_node; long distance; }; int gen_spgrid_topology (struct vty *vty, struct list *topology); int spgrid_check_params (struct vty *vty, int argc, const char **argv); #endif /* _ZEBRA_ISIS_TOPOLOGY_SPGRID_H */ quagga-1.2.4/lib/000077500000000000000000000000001325323223500135315ustar00rootroot00000000000000quagga-1.2.4/lib/Makefile.am000066400000000000000000000045311325323223500155700ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" lib_LTLIBRARIES = libzebra.la libzebra_la_LDFLAGS = -version-info 1:0:0 libzebra_la_SOURCES = \ network.c pid_output.c getopt.c getopt1.c daemon.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 agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c \ event_counter.c nexthop.c BUILT_SOURCES = memtypes.h route_types.h gitversion.h libzebra_la_DEPENDENCIES = @LIB_REGEX@ libzebra_la_LIBADD = @LIB_REGEX@ @LIBCAP@ pkginclude_HEADERS = \ buffer.h checksum.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 vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ workqueue.h route_types.h libospf.h vrf.h fifo.h event_counter.h \ nexthop.h noinst_HEADERS = \ plist_int.h EXTRA_DIST = \ regex.c regex-gnu.h \ queue.h \ memtypes.awk \ route_types.pl route_types.txt \ gitversion.pl memtypes.h: $(srcdir)/memtypes.c $(srcdir)/memtypes.awk ($(GAWK) -f $(srcdir)/memtypes.awk $(srcdir)/memtypes.c > $@) route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.pl @PERL@ $(srcdir)/route_types.pl < $(srcdir)/route_types.txt > $@ if GIT_VERSION # bit of a trick here to always have up-to-date git stamps without triggering # unneccessary rebuilds. .PHONY causes the .tmp file to be rebuilt always, # but if we use that on gitversion.h it'll ripple through the .c file deps. # (even if gitversion.h's file timestamp doesn't change, make will think it # did, because of .PHONY...) .PHONY: gitversion.h.tmp .SILENT: gitversion.h gitversion.h.tmp GITH=gitversion.h gitversion.h.tmp: $(srcdir)/../.git @PERL@ $(srcdir)/gitversion.pl $(srcdir) > ${GITH}.tmp gitversion.h: gitversion.h.tmp { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp -v ${GITH}.tmp ${GITH} else .PHONY: gitversion.h gitversion.h: true endif quagga-1.2.4/lib/Makefile.in000066400000000000000000000702031325323223500156000ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = lib ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ $(pkginclude_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = version.h CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgincludedir)" LTLIBRARIES = $(lib_LTLIBRARIES) am_libzebra_la_OBJECTS = network.lo pid_output.lo getopt.lo getopt1.lo \ daemon.lo checksum.lo vector.lo linklist.lo vty.lo command.lo \ sockunion.lo prefix.lo thread.lo if.lo memory.lo buffer.lo \ table.lo hash.lo filter.lo routemap.lo distribute.lo stream.lo \ str.lo log.lo plist.lo zclient.lo sockopt.lo smux.lo agentx.lo \ snmp.lo md5.lo if_rmap.lo keychain.lo privs.lo sigevent.lo \ pqueue.lo jhash.lo memtypes.lo workqueue.lo vrf.lo \ event_counter.lo nexthop.lo libzebra_la_OBJECTS = $(am_libzebra_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libzebra_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libzebra_la_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libzebra_la_SOURCES) DIST_SOURCES = $(libzebra_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) $(pkginclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/version.h.in \ $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) lib_LTLIBRARIES = libzebra.la libzebra_la_LDFLAGS = -version-info 1:0:0 libzebra_la_SOURCES = \ network.c pid_output.c getopt.c getopt1.c daemon.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 agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c memtypes.c workqueue.c vrf.c \ event_counter.c nexthop.c BUILT_SOURCES = memtypes.h route_types.h gitversion.h libzebra_la_DEPENDENCIES = @LIB_REGEX@ libzebra_la_LIBADD = @LIB_REGEX@ @LIBCAP@ pkginclude_HEADERS = \ buffer.h checksum.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 vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ workqueue.h route_types.h libospf.h vrf.h fifo.h event_counter.h \ nexthop.h noinst_HEADERS = \ plist_int.h EXTRA_DIST = \ regex.c regex-gnu.h \ queue.h \ memtypes.awk \ route_types.pl route_types.txt \ gitversion.pl @GIT_VERSION_TRUE@GITH = gitversion.h all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu lib/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): version.h: $(top_builddir)/config.status $(srcdir)/version.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libzebra.la: $(libzebra_la_OBJECTS) $(libzebra_la_DEPENDENCIES) $(EXTRA_libzebra_la_DEPENDENCIES) $(AM_V_CCLD)$(libzebra_la_LINK) -rpath $(libdir) $(libzebra_la_OBJECTS) $(libzebra_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/agentx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checksum.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/distribute.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_counter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/if.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/if_rmap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jhash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keychain.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linklist.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memtypes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nexthop.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pid_output.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plist.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pqueue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prefix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/privs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/routemap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigevent.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockopt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockunion.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vrf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vty.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zclient.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgincludeHEADERS: $(pkginclude_HEADERS) @$(NORMAL_INSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ done uninstall-pkgincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgincludeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES uninstall-pkgincludeHEADERS .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgincludeHEADERS install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libLTLIBRARIES \ uninstall-pkgincludeHEADERS .PRECIOUS: Makefile memtypes.h: $(srcdir)/memtypes.c $(srcdir)/memtypes.awk ($(GAWK) -f $(srcdir)/memtypes.awk $(srcdir)/memtypes.c > $@) route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.pl @PERL@ $(srcdir)/route_types.pl < $(srcdir)/route_types.txt > $@ # bit of a trick here to always have up-to-date git stamps without triggering # unneccessary rebuilds. .PHONY causes the .tmp file to be rebuilt always, # but if we use that on gitversion.h it'll ripple through the .c file deps. # (even if gitversion.h's file timestamp doesn't change, make will think it # did, because of .PHONY...) @GIT_VERSION_TRUE@.PHONY: gitversion.h.tmp @GIT_VERSION_TRUE@.SILENT: gitversion.h gitversion.h.tmp @GIT_VERSION_TRUE@gitversion.h.tmp: $(srcdir)/../.git @GIT_VERSION_TRUE@ @PERL@ $(srcdir)/gitversion.pl $(srcdir) > ${GITH}.tmp @GIT_VERSION_TRUE@gitversion.h: gitversion.h.tmp @GIT_VERSION_TRUE@ { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp -v ${GITH}.tmp ${GITH} @GIT_VERSION_FALSE@.PHONY: gitversion.h @GIT_VERSION_FALSE@gitversion.h: @GIT_VERSION_FALSE@ true # 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: quagga-1.2.4/lib/agentx.c000066400000000000000000000207531325323223500151720ustar00rootroot00000000000000/* SNMP support * Copyright (C) 2012 Vincent Bernat * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 #if defined HAVE_SNMP && defined SNMP_AGENTX #include #include #include #include #include "command.h" #include "smux.h" static int agentx_enabled = 0; static struct thread_master *agentx_tm; static struct thread *timeout_thr = NULL; static struct list *events = NULL; static void agentx_events_update(void); static int agentx_timeout(struct thread *t) { timeout_thr = NULL; snmp_timeout (); run_alarms (); netsnmp_check_outstanding_agent_requests (); agentx_events_update (); return 0; } static int agentx_read(struct thread *t) { fd_set fds; struct listnode *ln = THREAD_ARG (t); list_delete_node (events, ln); FD_ZERO (&fds); FD_SET (THREAD_FD (t), &fds); snmp_read (&fds); netsnmp_check_outstanding_agent_requests (); agentx_events_update (); return 0; } static void agentx_events_update(void) { int maxfd = 0; int block = 1; struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; fd_set fds; struct listnode *ln; struct thread *thr; int fd, thr_fd; THREAD_OFF (timeout_thr); FD_ZERO (&fds); snmp_select_info (&maxfd, &fds, &timeout, &block); if (!block) timeout_thr = thread_add_timer_tv (agentx_tm, agentx_timeout, NULL, &timeout); ln = listhead (events); thr = ln ? listgetdata (ln) : NULL; thr_fd = thr ? THREAD_FD (thr) : -1; /* "two-pointer" / two-list simultaneous iteration * ln/thr/thr_fd point to the next existing event listener to hit while * fd counts to catch up */ for (fd = 0; fd < maxfd; fd++) { /* caught up */ if (thr_fd == fd) { struct listnode *nextln = listnextnode (ln); if (!FD_ISSET (fd, &fds)) { thread_cancel (thr); list_delete_node (events, ln); } ln = nextln; thr = ln ? listgetdata (ln) : NULL; thr_fd = thr ? THREAD_FD (thr) : -1; } /* need listener, but haven't hit one where it would be */ else if (FD_ISSET (fd, &fds)) { struct listnode *newln; thr = thread_add_read (agentx_tm, agentx_read, NULL, fd); newln = listnode_add_before (events, ln, thr); thr->arg = newln; } } /* leftover event listeners at this point have fd > maxfd, delete them */ while (ln) { struct listnode *nextln = listnextnode (ln); thread_cancel (listgetdata (ln)); list_delete_node (events, ln); ln = nextln; } } /* AgentX node. */ static struct cmd_node agentx_node = { SMUX_NODE, "" /* AgentX has no interface. */ }; /* Logging NetSNMP messages */ static int agentx_log_callback(int major, int minor, void *serverarg, void *clientarg) { struct snmp_log_message *slm = (struct snmp_log_message *)serverarg; char *msg = strdup (slm->msg); if (msg) msg[strlen(msg)-1] = '\0'; switch (slm->priority) { case LOG_EMERG: zlog_err ("snmp[emerg]: %s", msg?msg:slm->msg); break; case LOG_ALERT: zlog_err ("snmp[alert]: %s", msg?msg:slm->msg); break; case LOG_CRIT: zlog_err ("snmp[crit]: %s", msg?msg:slm->msg); break; case LOG_ERR: zlog_err ("snmp[err]: %s", msg?msg:slm->msg); break; case LOG_WARNING: zlog_warn ("snmp[warning]: %s", msg?msg:slm->msg); break; case LOG_NOTICE: zlog_notice("snmp[notice]: %s", msg?msg:slm->msg); break; case LOG_INFO: zlog_info ("snmp[info]: %s", msg?msg:slm->msg); break; case LOG_DEBUG: zlog_debug ("snmp[debug]: %s", msg?msg:slm->msg); break; } free(msg); return SNMP_ERR_NOERROR; } static int config_write_agentx (struct vty *vty) { if (agentx_enabled) vty_out (vty, "agentx%s", VTY_NEWLINE); return 0; } DEFUN (agentx_enable, agentx_enable_cmd, "agentx", "SNMP AgentX protocol settings\n" "SNMP AgentX settings\n") { if (!agentx_enabled) { init_snmp("quagga"); events = list_new(); agentx_events_update (); agentx_enabled = 1; return CMD_SUCCESS; } vty_out (vty, "SNMP AgentX already enabled%s", VTY_NEWLINE); return CMD_WARNING; } DEFUN (no_agentx, no_agentx_cmd, "no agentx", NO_STR "SNMP AgentX protocol settings\n" "SNMP AgentX settings\n") { if (!agentx_enabled) return CMD_SUCCESS; vty_out (vty, "SNMP AgentX support cannot be disabled once enabled%s", VTY_NEWLINE); return CMD_WARNING; } void smux_init (struct thread_master *tm) { agentx_tm = tm; netsnmp_enable_subagent (); snmp_disable_log (); snmp_enable_calllog (); snmp_register_callback (SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, agentx_log_callback, NULL); init_agent ("quagga"); install_node (&agentx_node, config_write_agentx); install_element (CONFIG_NODE, &agentx_enable_cmd); install_element (CONFIG_NODE, &no_agentx_cmd); } void smux_register_mib (const char *descr, struct variable *var, size_t width, int num, oid name[], size_t namelen) { register_mib (descr, var, width, num, name, namelen); } int smux_trap (struct variable *vp, size_t vp_len, const oid *ename, size_t enamelen, const oid *name, size_t namelen, const oid *iname, size_t inamelen, const struct trap_object *trapobj, size_t trapobjlen, u_char sptrap) { oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 }; size_t objid_snmptrap_len = sizeof objid_snmptrap / sizeof (oid); oid notification_oid[MAX_OID_LEN]; size_t notification_oid_len; unsigned int i; netsnmp_variable_list *notification_vars = NULL; if (!agentx_enabled) return 0; /* snmpTrapOID */ oid_copy (notification_oid, ename, enamelen); notification_oid[enamelen] = sptrap; notification_oid_len = enamelen + 1; snmp_varlist_add_variable (¬ification_vars, objid_snmptrap, objid_snmptrap_len, ASN_OBJECT_ID, (u_char *) notification_oid, notification_oid_len * sizeof(oid)); /* Provided bindings */ for (i = 0; i < trapobjlen; i++) { unsigned int j; oid oid[MAX_OID_LEN]; size_t oid_len, onamelen; u_char *val; size_t val_len; WriteMethod *wm = NULL; struct variable cvp; /* Make OID. */ if (trapobj[i].namelen > 0) { /* Columnar object */ onamelen = trapobj[i].namelen; oid_copy (oid, name, namelen); oid_copy (oid + namelen, trapobj[i].name, onamelen); oid_copy (oid + namelen + onamelen, iname, inamelen); oid_len = namelen + onamelen + inamelen; } else { /* Scalar object */ onamelen = trapobj[i].namelen * (-1); oid_copy (oid, name, namelen); oid_copy (oid + namelen, trapobj[i].name, onamelen); oid[onamelen + namelen] = 0; oid_len = namelen + onamelen + 1; } /* Locate the appropriate function and type in the MIB registry. */ for (j = 0; j < vp_len; j++) { if (oid_compare (trapobj[i].name, onamelen, vp[j].name, vp[j].namelen) != 0) continue; /* We found the appropriate variable in the MIB registry. */ oid_copy(cvp.name, name, namelen); oid_copy(cvp.name + namelen, vp[j].name, vp[j].namelen); cvp.namelen = namelen + vp[j].namelen; cvp.type = vp[j].type; cvp.magic = vp[j].magic; cvp.acl = vp[j].acl; cvp.findVar = vp[j].findVar; /* Grab the result. */ val = cvp.findVar (&cvp, oid, &oid_len, 1, &val_len, &wm); if (!val) break; snmp_varlist_add_variable (¬ification_vars, oid, oid_len, vp[j].type, val, val_len); break; } } send_v2trap (notification_vars); snmp_free_varbind (notification_vars); agentx_events_update (); return 1; } #endif /* HAVE_SNMP */ quagga-1.2.4/lib/buffer.c000066400000000000000000000276111325323223500151550ustar00rootroot00000000000000/* * 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" #include "log.h" #include "network.h" #include /* Buffer master. */ struct buffer { /* Data list. */ struct buffer_data *head; struct buffer_data *tail; /* Size of each buffer_data chunk. */ size_t size; }; /* Data container. */ struct buffer_data { struct buffer_data *next; /* Location to add new data. */ size_t cp; /* Pointer to data not yet flushed. */ size_t sp; /* Actual data stream (variable length). */ unsigned char data[]; /* real dimension is buffer->size */ }; /* It should always be true that: 0 <= sp <= cp <= size */ /* Default buffer size (used if none specified). It is rounded up to the next page boundery. */ #define BUFFER_SIZE_DEFAULT 4096 #define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D)) /* Make new buffer. */ struct buffer * buffer_new (size_t size) { struct buffer *b; b = XCALLOC (MTYPE_BUFFER, sizeof (struct buffer)); if (size) b->size = size; else { static size_t default_size; if (!default_size) { long pgsz = sysconf(_SC_PAGESIZE); default_size = ((((BUFFER_SIZE_DEFAULT-1)/pgsz)+1)*pgsz); } b->size = default_size; } return b; } /* Free buffer. */ void buffer_free (struct buffer *b) { buffer_reset(b); XFREE (MTYPE_BUFFER, b); } /* Make string clone. */ char * buffer_getstr (struct buffer *b) { size_t totlen = 0; struct buffer_data *data; char *s; char *p; for (data = b->head; data; data = data->next) totlen += data->cp - data->sp; if (!(s = XMALLOC(MTYPE_TMP, totlen+1))) return NULL; p = s; for (data = b->head; data; data = data->next) { memcpy(p, data->data + data->sp, data->cp - data->sp); p += data->cp - data->sp; } *p = '\0'; return s; } /* Return 1 if buffer is empty. */ int buffer_empty (struct buffer *b) { return (b->head == NULL); } /* 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; } /* Add buffer_data to the end of buffer. */ static struct buffer_data * buffer_add (struct buffer *b) { struct buffer_data *d; d = XMALLOC(MTYPE_BUFFER_DATA, offsetof(struct buffer_data, data) + b->size); d->cp = d->sp = 0; d->next = NULL; if (b->tail) b->tail->next = d; else b->head = d; b->tail = d; return d; } /* Write data to buffer. */ void buffer_put(struct buffer *b, const void *p, size_t size) { struct buffer_data *data = b->tail; const char *ptr = p; /* We use even last one byte of data buffer. */ while (size) { size_t chunk; /* If there is no data buffer add it. */ if (data == NULL || data->cp == b->size) data = buffer_add (b); chunk = ((size <= (b->size - data->cp)) ? size : (b->size - data->cp)); memcpy ((data->data + data->cp), ptr, chunk); size -= chunk; ptr += chunk; data->cp += chunk; } } /* Insert character into the buffer. */ void buffer_putc (struct buffer *b, u_char c) { buffer_put(b, &c, 1); } /* Put string to the buffer. */ void buffer_putstr (struct buffer *b, const char *c) { buffer_put(b, c, strlen(c)); } /* Keep flushing data to the fd until the buffer is empty or an error is encountered or the operation would block. */ buffer_status_t buffer_flush_all (struct buffer *b, int fd) { buffer_status_t ret; struct buffer_data *head; size_t head_sp; if (!b->head) return BUFFER_EMPTY; head_sp = (head = b->head)->sp; /* Flush all data. */ while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING) { if ((b->head == head) && (head_sp == head->sp) && (errno != EINTR)) /* No data was flushed, so kernel buffer must be full. */ return ret; head_sp = (head = b->head)->sp; } return ret; } /* Flush enough data to fill a terminal window of the given scene (used only by vty telnet interface). */ buffer_status_t buffer_flush_window (struct buffer *b, int fd, int width, int height, int erase_flag, int no_more_flag) { int nbytes; int iov_alloc; 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; int column; if (!b->head) return BUFFER_EMPTY; if (height < 1) { zlog_warn("%s called with non-positive window height %d, forcing to 1", __func__, height); height = 1; } else if (height >= 2) height--; if (width < 1) { zlog_warn("%s called with non-positive window width %d, forcing to 1", __func__, width); width = 1; } /* For erase and more data add two to b's buffer_data count.*/ if (b->head->next == NULL) { iov_alloc = array_size(small_iov); iov = small_iov; } else { iov_alloc = ((height*(width+2))/b->size)+10; iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov)); } 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. */ column = 1; /* Column position of next character displayed. */ for (data = b->head; data && (height > 0); data = data->next) { size_t cp; cp = data->sp; while ((cp < data->cp) && (height > 0)) { /* Calculate lines remaining and column position after displaying this character. */ if (data->data[cp] == '\r') column = 1; else if ((data->data[cp] == '\n') || (column == width)) { column = 1; height--; } else column++; cp++; } iov[iov_index].iov_base = (char *)(data->data + data->sp); iov[iov_index++].iov_len = cp-data->sp; data->sp = cp; if (iov_index == iov_alloc) /* This should not ordinarily happen. */ { iov_alloc *= 2; if (iov != small_iov) { zlog_warn("%s: growing iov array to %d; " "width %d, height %d, size %lu", __func__, iov_alloc, width, height, (u_long)b->size); iov = XREALLOC(MTYPE_TMP, iov, iov_alloc*sizeof(*iov)); } else { /* This should absolutely never occur. */ zlog_err("%s: corruption detected: iov_small overflowed; " "head %p, tail %p, head->next %p", __func__, (void *)b->head, (void *)b->tail, (void *)b->head->next); iov = XMALLOC(MTYPE_TMP, iov_alloc*sizeof(*iov)); memcpy(iov, small_iov, sizeof(small_iov)); } } } /* In case of `more' display need. */ if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag) { iov[iov_index].iov_base = more; iov[iov_index].iov_len = sizeof more; iov_index++; } #ifdef IOV_MAX /* IOV_MAX are normally defined in , Posix.1g. example: Solaris2.6 are defined IOV_MAX size at 16. */ { struct iovec *c_iov = iov; nbytes = 0; /* Make sure it's initialized. */ while (iov_index > 0) { int iov_size; iov_size = ((iov_index > IOV_MAX) ? IOV_MAX : iov_index); if ((nbytes = writev(fd, c_iov, iov_size)) < 0) { zlog_warn("%s: writev to fd %d failed: %s", __func__, fd, safe_strerror(errno)); break; } /* move pointer io-vector */ c_iov += iov_size; iov_index -= iov_size; } } #else /* IOV_MAX */ if ((nbytes = writev (fd, iov, iov_index)) < 0) zlog_warn("%s: writev to fd %d failed: %s", __func__, fd, safe_strerror(errno)); #endif /* IOV_MAX */ /* Free printed buffer data. */ while (b->head && (b->head->sp == b->head->cp)) { struct buffer_data *del; if (!(b->head = (del = b->head)->next)) b->tail = NULL; BUFFER_DATA_FREE(del); } if (iov != small_iov) XFREE (MTYPE_TMP, iov); return (nbytes < 0) ? BUFFER_ERROR : (b->head ? BUFFER_PENDING : BUFFER_EMPTY); } /* This function (unlike other buffer_flush* functions above) is designed to work with non-blocking sockets. It does not attempt to write out all of the queued data, just a "big" chunk. It returns 0 if it was able to empty out the buffers completely, 1 if more flushing is required later, or -1 on a fatal write error. */ buffer_status_t buffer_flush_available(struct buffer *b, int fd) { /* These are just reasonable values to make sure a significant amount of data is written. There's no need to go crazy and try to write it all in one shot. */ #ifdef IOV_MAX #define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX) #else #define MAX_CHUNKS 16 #endif #define MAX_FLUSH 131072 struct buffer_data *d; size_t written; struct iovec iov[MAX_CHUNKS]; size_t iovcnt = 0; size_t nbyte = 0; for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH); d = d->next, iovcnt++) { iov[iovcnt].iov_base = d->data+d->sp; nbyte += (iov[iovcnt].iov_len = d->cp-d->sp); } if (!nbyte) /* No data to flush: should we issue a warning message? */ return BUFFER_EMPTY; /* only place where written should be sign compared */ if ((ssize_t)(written = writev(fd,iov,iovcnt)) < 0) { if (ERRNO_IO_RETRY(errno)) /* Calling code should try again later. */ return BUFFER_PENDING; zlog_warn("%s: write error on fd %d: %s", __func__, fd, safe_strerror(errno)); return BUFFER_ERROR; } /* Free printed buffer data. */ while (written > 0) { struct buffer_data *d; if (!(d = b->head)) { zlog_err("%s: corruption detected: buffer queue empty, " "but written is %lu", __func__, (u_long)written); break; } if (written < d->cp-d->sp) { d->sp += written; return BUFFER_PENDING; } written -= (d->cp-d->sp); if (!(b->head = d->next)) b->tail = NULL; BUFFER_DATA_FREE(d); } return b->head ? BUFFER_PENDING : BUFFER_EMPTY; #undef MAX_CHUNKS #undef MAX_FLUSH } buffer_status_t buffer_write(struct buffer *b, int fd, const void *p, size_t size) { ssize_t nbytes; #if 0 /* Should we attempt to drain any previously buffered data? This could help reduce latency in pushing out the data if we are stuck in a long-running thread that is preventing the main select loop from calling the flush thread... */ if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR)) return BUFFER_ERROR; #endif if (b->head) /* Buffer is not empty, so do not attempt to write the new data. */ nbytes = 0; else if ((nbytes = write(fd, p, size)) < 0) { if (ERRNO_IO_RETRY(errno)) nbytes = 0; else { zlog_warn("%s: write error on fd %d: %s", __func__, fd, safe_strerror(errno)); return BUFFER_ERROR; } } /* Add any remaining data to the buffer. */ { size_t written = nbytes; if (written < size) buffer_put(b, ((const char *)p)+written, size-written); } return b->head ? BUFFER_PENDING : BUFFER_EMPTY; } quagga-1.2.4/lib/buffer.h000066400000000000000000000100221325323223500151460ustar00rootroot00000000000000/* * 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 /* Create a new buffer. Memory will be allocated in chunks of the given size. If the argument is 0, the library will supply a reasonable default size suitable for buffering socket I/O. */ extern struct buffer *buffer_new (size_t); /* Free all data in the buffer. */ extern void buffer_reset (struct buffer *); /* This function first calls buffer_reset to release all buffered data. Then it frees the struct buffer itself. */ extern void buffer_free (struct buffer *); /* Add the given data to the end of the buffer. */ extern void buffer_put (struct buffer *, const void *, size_t); /* Add a single character to the end of the buffer. */ extern void buffer_putc (struct buffer *, u_char); /* Add a NUL-terminated string to the end of the buffer. */ extern void buffer_putstr (struct buffer *, const char *); /* Combine all accumulated (and unflushed) data inside the buffer into a single NUL-terminated string allocated using XMALLOC(MTYPE_TMP). Note that this function does not alter the state of the buffer, so the data is still inside waiting to be flushed. */ char *buffer_getstr (struct buffer *); /* Returns 1 if there is no pending data in the buffer. Otherwise returns 0. */ int buffer_empty (struct buffer *); typedef enum { /* An I/O error occurred. The buffer should be destroyed and the file descriptor should be closed. */ BUFFER_ERROR = -1, /* The data was written successfully, and the buffer is now empty (there is no pending data waiting to be flushed). */ BUFFER_EMPTY = 0, /* There is pending data in the buffer waiting to be flushed. Please try flushing the buffer when select indicates that the file descriptor is writeable. */ BUFFER_PENDING = 1 } buffer_status_t; /* Try to write this data to the file descriptor. Any data that cannot be written immediately is added to the buffer queue. */ extern buffer_status_t buffer_write(struct buffer *, int fd, const void *, size_t); /* This function attempts to flush some (but perhaps not all) of the queued data to the given file descriptor. */ extern buffer_status_t buffer_flush_available(struct buffer *, int fd); /* The following 2 functions (buffer_flush_all and buffer_flush_window) are for use in lib/vty.c only. They should not be used elsewhere. */ /* Call buffer_flush_available repeatedly until either all data has been flushed, or an I/O error has been encountered, or the operation would block. */ extern buffer_status_t buffer_flush_all (struct buffer *, int fd); /* Attempt to write enough data to the given fd to fill a window of the given width and height (and remove the data written from the buffer). If !no_more, then a message saying " --More-- " is appended. If erase is true, then first overwrite the previous " --More-- " message with spaces. Any write error (including EAGAIN or EINTR) will cause this function to return -1 (because the logic for handling the erase and more features is too complicated to retry the write later). */ extern buffer_status_t buffer_flush_window (struct buffer *, int fd, int width, int height, int erase, int no_more); #endif /* _ZEBRA_BUFFER_H */ quagga-1.2.4/lib/checksum.c000066400000000000000000000060151325323223500155010ustar00rootroot00000000000000/* * 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 #include "checksum.h" int /* return checksum in low-order 16 bits */ in_cksum(void *parg, int nbytes) { u_short *ptr = parg; 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); } /* Fletcher Checksum -- Refer to RFC1008. */ #define MODX 4102 /* 5802 should be fine */ /* To be consistent, offset is 0-based index, rather than the 1-based index required in the specification ISO 8473, Annex C.1 */ /* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum without modifying the buffer; a valid checksum returns 0 */ u_int16_t fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) { u_int8_t *p; int x, y, c0, c1; u_int16_t checksum; u_int16_t *csum; size_t partial_len, i, left = len; checksum = 0; if (offset != FLETCHER_CHECKSUM_VALIDATE) /* Zero the csum in the packet. */ { assert (offset < (len - 1)); /* account for two bytes of checksum */ csum = (u_int16_t *) (buffer + offset); *(csum) = 0; } p = buffer; c0 = 0; c1 = 0; while (left != 0) { partial_len = MIN(left, MODX); for (i = 0; i < partial_len; i++) { c0 = c0 + *(p++); c1 += c0; } c0 = c0 % 255; c1 = c1 % 255; left -= partial_len; } /* The cast is important, to ensure the mod is taken as a signed value. */ x = (int)((len - offset - 1) * c0 - c1) % 255; if (x <= 0) x += 255; y = 510 - c0 - x; if (y > 255) y -= 255; if (offset == FLETCHER_CHECKSUM_VALIDATE) { checksum = (c1 << 8) + c0; } else { /* * Now we write this to the packet. * We could skip this step too, since the checksum returned would * be stored into the checksum field by the caller. */ buffer[offset] = x; buffer[offset + 1] = y; /* Take care of the endian issue */ checksum = htons((x << 8) | (y & 0xFF)); } return checksum; } quagga-1.2.4/lib/checksum.h000066400000000000000000000002431325323223500155030ustar00rootroot00000000000000extern int in_cksum(void *, int); #define FLETCHER_CHECKSUM_VALIDATE 0xffff extern u_int16_t fletcher_checksum(u_char *, const size_t len, const uint16_t offset); quagga-1.2.4/lib/command.c000066400000000000000000003253451325323223500153270ustar00rootroot00000000000000/* Command interpreter routine for virtual terminal [aka TeletYpe] Copyright (C) 1997, 98, 99 Kunihiro Ishiguro Copyright (C) 2013 by Open Source Routing. Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU 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 #include "thread.h" #include "vector.h" #include "vty.h" #include "command.h" #include "workqueue.h" /* Command vector which includes some level of command lists. Normally each daemon maintains each own cmdvec. */ vector cmdvec = NULL; struct cmd_token token_cr; char *command_cr = NULL; enum filter_type { FILTER_RELAXED, FILTER_STRICT }; enum matcher_rv { MATCHER_OK, MATCHER_COMPLETE, MATCHER_INCOMPLETE, MATCHER_NO_MATCH, MATCHER_AMBIGUOUS, MATCHER_EXCEED_ARGC_MAX }; #define MATCHER_ERROR(matcher_rv) \ ( (matcher_rv) == MATCHER_INCOMPLETE \ || (matcher_rv) == MATCHER_NO_MATCH \ || (matcher_rv) == MATCHER_AMBIGUOUS \ || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \ ) /* Host information structure. */ struct host host; /* Standard command node structures. */ static struct cmd_node auth_node = { AUTH_NODE, "Password: ", }; static struct cmd_node view_node = { VIEW_NODE, "%s> ", }; static struct cmd_node restricted_node = { RESTRICTED_NODE, "%s$ ", }; static struct cmd_node auth_enable_node = { AUTH_ENABLE_NODE, "Password: ", }; static struct cmd_node enable_node = { ENABLE_NODE, "%s# ", }; static struct cmd_node config_node = { CONFIG_NODE, "%s(config)# ", 1 }; /* Default motd string. */ static const char *default_motd = "\r\n\ Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\ " QUAGGA_COPYRIGHT "\r\n\ " GIT_INFO "\r\n"; static const struct facility_map { int facility; const char *name; size_t match; } syslog_facilities[] = { { LOG_KERN, "kern", 1 }, { LOG_USER, "user", 2 }, { LOG_MAIL, "mail", 1 }, { LOG_DAEMON, "daemon", 1 }, { LOG_AUTH, "auth", 1 }, { LOG_SYSLOG, "syslog", 1 }, { LOG_LPR, "lpr", 2 }, { LOG_NEWS, "news", 1 }, { LOG_UUCP, "uucp", 2 }, { LOG_CRON, "cron", 1 }, #ifdef LOG_FTP { LOG_FTP, "ftp", 1 }, #endif { LOG_LOCAL0, "local0", 6 }, { LOG_LOCAL1, "local1", 6 }, { LOG_LOCAL2, "local2", 6 }, { LOG_LOCAL3, "local3", 6 }, { LOG_LOCAL4, "local4", 6 }, { LOG_LOCAL5, "local5", 6 }, { LOG_LOCAL6, "local6", 6 }, { LOG_LOCAL7, "local7", 6 }, { 0, NULL, 0 }, }; static const char * facility_name(int facility) { const struct facility_map *fm; for (fm = syslog_facilities; fm->name; fm++) if (fm->facility == facility) return fm->name; return ""; } static int facility_match(const char *str) { const struct facility_map *fm; for (fm = syslog_facilities; fm->name; fm++) if (!strncmp(str,fm->name,fm->match)) return fm->facility; return -1; } static int level_match(const char *s) { int level ; for ( level = 0 ; zlog_priority [level] != NULL ; level ++ ) if (!strncmp (s, zlog_priority[level], 2)) return level; return ZLOG_DISABLED; } /* This is called from main when a daemon is invoked with -v or --version. */ void print_version (const char *progname) { printf ("%s version %s\n", progname, QUAGGA_VERSION); printf ("%s\n", QUAGGA_COPYRIGHT); printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS); } /* Utility function to concatenate argv argument into a single string with inserting ' ' character between each argument. */ char * argv_concat (const char **argv, int argc, int shift) { int i; size_t len; char *str; char *p; len = 0; for (i = shift; i < argc; i++) len += strlen(argv[i])+1; if (!len) return NULL; p = str = XMALLOC(MTYPE_TMP, len); for (i = shift; i < argc; i++) { size_t arglen; memcpy(p, argv[i], (arglen = strlen(argv[i]))); p += arglen; *p++ = ' '; } *(p-1) = '\0'; return str; } static unsigned int cmd_hash_key (void *p) { return (uintptr_t) p; } static int cmd_hash_cmp (const void *a, const void *b) { return a == b; } /* 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); node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp); } /* 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 (const char *string) { const char *cp, *start; char *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) { unsigned int i; char *cp; if (!v) return; for (i = 0; i < vector_active (v); i++) if ((cp = vector_slot (v, i)) != NULL) XFREE (MTYPE_STRVEC, cp); vector_free (v); } struct format_parser_state { vector topvect; /* Top level vector */ vector intvect; /* Intermediate level vector, used when there's * a multiple in a keyword. */ vector curvect; /* current vector where read tokens should be appended. */ const char *string; /* pointer to command string, not modified */ const char *cp; /* pointer in command string, moved along while parsing */ const char *dp; /* pointer in description string, moved along while parsing */ int in_keyword; /* flag to remember if we are in a keyword group */ int in_multiple; /* flag to remember if we are in a multiple group */ int just_read_word; /* flag to remember if the last thing we red was a * real word and not some abstract token */ }; static void format_parser_error(struct format_parser_state *state, const char *message) { int offset = state->cp - state->string + 1; fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string); fprintf(stderr, " %*c\n", offset, '^'); fprintf(stderr, "%s at offset %d.\n", message, offset); fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n"); exit(1); } static char * format_parser_desc_str(struct format_parser_state *state) { const char *cp, *start; char *token; int strlen; cp = state->dp; 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_CMD_TOKENS, strlen + 1); memcpy (token, start, strlen); *(token + strlen) = '\0'; state->dp = cp; return token; } static void format_parser_begin_keyword(struct format_parser_state *state) { struct cmd_token *token; vector keyword_vect; if (state->in_keyword || state->in_multiple) format_parser_error(state, "Unexpected '{'"); state->cp++; state->in_keyword = 1; token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token)); token->type = TOKEN_KEYWORD; token->keyword = vector_init(VECTOR_MIN_SIZE); keyword_vect = vector_init(VECTOR_MIN_SIZE); vector_set(token->keyword, keyword_vect); vector_set(state->curvect, token); state->curvect = keyword_vect; } static void format_parser_begin_multiple(struct format_parser_state *state) { struct cmd_token *token; if (state->in_keyword == 1) format_parser_error(state, "Keyword starting with '('"); if (state->in_multiple) format_parser_error(state, "Nested group"); state->cp++; state->in_multiple = 1; state->just_read_word = 0; token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token)); token->type = TOKEN_MULTIPLE; token->multiple = vector_init(VECTOR_MIN_SIZE); vector_set(state->curvect, token); if (state->curvect != state->topvect) state->intvect = state->curvect; state->curvect = token->multiple; } static void format_parser_end_keyword(struct format_parser_state *state) { if (state->in_multiple || !state->in_keyword) format_parser_error(state, "Unexpected '}'"); if (state->in_keyword == 1) format_parser_error(state, "Empty keyword group"); state->cp++; state->in_keyword = 0; state->curvect = state->topvect; } static void format_parser_end_multiple(struct format_parser_state *state) { char *dummy; if (!state->in_multiple) format_parser_error(state, "Unexpected ')'"); if (vector_active(state->curvect) == 0) format_parser_error(state, "Empty multiple section"); if (!state->just_read_word) { /* There are constructions like * 'show ip ospf database ... (self-originate|)' * in use. * The old parser reads a description string for the * word '' between |) which will never match. * Simulate this behvaior by dropping the next desc * string in such a case. */ dummy = format_parser_desc_str(state); XFREE(MTYPE_CMD_TOKENS, dummy); } state->cp++; state->in_multiple = 0; if (state->intvect) state->curvect = state->intvect; else state->curvect = state->topvect; } static void format_parser_handle_pipe(struct format_parser_state *state) { struct cmd_token *keyword_token; vector keyword_vect; if (state->in_multiple) { state->just_read_word = 0; state->cp++; } else if (state->in_keyword) { state->in_keyword = 1; state->cp++; keyword_token = vector_slot(state->topvect, vector_active(state->topvect) - 1); keyword_vect = vector_init(VECTOR_MIN_SIZE); vector_set(keyword_token->keyword, keyword_vect); state->curvect = keyword_vect; } else { format_parser_error(state, "Unexpected '|'"); } } static void format_parser_read_word(struct format_parser_state *state) { const char *start; int len; char *cmd; struct cmd_token *token; start = state->cp; while (state->cp[0] != '\0' && !strchr("\r\n(){}|", state->cp[0]) && !isspace((int)state->cp[0])) state->cp++; len = state->cp - start; cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1); memcpy(cmd, start, len); cmd[len] = '\0'; token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token)); token->type = TOKEN_TERMINAL; if (strcmp (cmd, "A.B.C.D") == 0) token->terminal = TERMINAL_IPV4; else if (strcmp (cmd, "A.B.C.D/M") == 0) token->terminal = TERMINAL_IPV4_PREFIX; else if (strcmp (cmd, "X:X::X:X") == 0) token->terminal = TERMINAL_IPV6; else if (strcmp (cmd, "X:X::X:X/M") == 0) token->terminal = TERMINAL_IPV6_PREFIX; else if (cmd[0] == '[') token->terminal = TERMINAL_OPTION; else if (cmd[0] == '.') token->terminal = TERMINAL_VARARG; else if (cmd[0] == '<') token->terminal = TERMINAL_RANGE; else if (cmd[0] >= 'A' && cmd[0] <= 'Z') token->terminal = TERMINAL_VARIABLE; else token->terminal = TERMINAL_LITERAL; token->cmd = cmd; token->desc = format_parser_desc_str(state); vector_set(state->curvect, token); if (state->in_keyword == 1) state->in_keyword = 2; state->just_read_word = 1; } /** * Parse a given command format string and build a tree of tokens from * it that is suitable to be used by the command subsystem. * * @param string Command format string. * @param descstr Description string. * @return A vector of struct cmd_token representing the given command, * or NULL on error. */ static vector cmd_parse_format(const char *string, const char *descstr) { struct format_parser_state state; if (string == NULL) return NULL; memset(&state, 0, sizeof(state)); state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE); state.cp = state.string = string; state.dp = descstr; while (1) { while (isspace((int)state.cp[0]) && state.cp[0] != '\0') state.cp++; switch (state.cp[0]) { case '\0': if (state.in_keyword || state.in_multiple) format_parser_error(&state, "Unclosed group/keyword"); return state.topvect; case '{': format_parser_begin_keyword(&state); break; case '(': format_parser_begin_multiple(&state); break; case '}': format_parser_end_keyword(&state); break; case ')': format_parser_end_multiple(&state); break; case '|': format_parser_handle_pipe(&state); break; default: format_parser_read_word(&state); } } } /* Return prompt character of specified node. */ const 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; /* cmd_init hasn't been called */ if (!cmdvec) { fprintf (stderr, "%s called before cmd_init, breakage likely\n", __func__); return; } cnode = vector_slot (cmdvec, ntype); if (cnode == NULL) { fprintf (stderr, "Command node %d doesn't exist, please check it\n", ntype); exit (1); } if (hash_lookup (cnode->cmd_hash, cmd) != NULL) { #ifdef DEV_BUILD fprintf (stderr, "Multiple command installs to node %d of command:\n%s\n", ntype, cmd->string); #endif return; } assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern)); vector_set (cnode->cmd_vector, cmd); if (cmd->tokens == NULL) cmd->tokens = cmd_parse_format(cmd->string, cmd->doc); if (ntype == VIEW_NODE) install_element (ENABLE_NODE, cmd); } static const unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static void to64(char *s, long v, int n) { while (--n >= 0) { *s++ = itoa64[v&0x3f]; v >>= 6; } } static char * zencrypt (const 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); } /* This function write configuration of this host. */ static 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); if (host.enable) vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE); } if (zlog_default->default_lvl != LOG_DEBUG) { vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s", VTY_NEWLINE); vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->default_lvl], VTY_NEWLINE); } if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) { vty_out (vty, "log file %s", host.logfile); if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl) vty_out (vty, " %s", zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]); vty_out (vty, "%s", VTY_NEWLINE); } if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) { vty_out (vty, "log stdout"); if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl) vty_out (vty, " %s", zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]); vty_out (vty, "%s", VTY_NEWLINE); } if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) vty_out(vty,"no log monitor%s",VTY_NEWLINE); else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl) vty_out(vty,"log monitor %s%s", zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE); if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) { vty_out (vty, "log syslog"); if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl) vty_out (vty, " %s", zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]); vty_out (vty, "%s", VTY_NEWLINE); } if (zlog_default->facility != LOG_DAEMON) vty_out (vty, "log facility %s%s", facility_name(zlog_default->facility), VTY_NEWLINE); if (zlog_default->record_priority == 1) vty_out (vty, "log record-priority%s", VTY_NEWLINE); if (zlog_default->timestamp_precision > 0) vty_out (vty, "log timestamp precision %d%s", zlog_default->timestamp_precision, 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.motdfile) vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE); else if (! host.motd) vty_out (vty, "no banner motd%s", VTY_NEWLINE); return 1; } /* Utility function for getting command vector. */ static vector cmd_node_vector (vector v, enum node_type ntype) { struct cmd_node *cnode = vector_slot (v, ntype); return cnode->cmd_vector; } /* 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 }; static enum match_type cmd_ipv4_match (const char *str) { const 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; } static enum match_type cmd_ipv4_prefix_match (const char *str) { const 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 #ifdef HAVE_IPV6 static enum match_type cmd_ipv6_match (const char *str) { struct sockaddr_in6 sin6_dummy; int ret; if (str == NULL) return partly_match; if (strspn (str, IPV6_ADDR_STR) != strlen (str)) return no_match; /* use inet_pton that has a better support, * for example inet_pton can support the automatic addresses: * ::1.2.3.4 */ ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr); if (ret == 1) return exact_match; return no_match; } static enum match_type cmd_ipv6_prefix_match (const char *str) { int state = STATE_START; int colons = 0, nums = 0, double_colon = 0; int mask; const 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) == '.') { if (colons || double_colon) state = STATE_DOT; else return no_match; } 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; return exact_match; } #endif /* HAVE_IPV6 */ #define DECIMAL_STRLEN_MAX 10 static int cmd_range_match (const char *range, const 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; } static enum match_type cmd_word_match(struct cmd_token *token, enum filter_type filter, const char *word) { const char *str; enum match_type match_type; str = token->cmd; if (filter == FILTER_RELAXED) if (!word || !strlen(word)) return partly_match; if (!word) return no_match; switch (token->terminal) { case TERMINAL_VARARG: return vararg_match; case TERMINAL_RANGE: if (cmd_range_match(str, word)) return range_match; break; case TERMINAL_IPV6: match_type = cmd_ipv6_match(word); if ((filter == FILTER_RELAXED && match_type != no_match) || (filter == FILTER_STRICT && match_type == exact_match)) return ipv6_match; break; case TERMINAL_IPV6_PREFIX: match_type = cmd_ipv6_prefix_match(word); if ((filter == FILTER_RELAXED && match_type != no_match) || (filter == FILTER_STRICT && match_type == exact_match)) return ipv6_prefix_match; break; case TERMINAL_IPV4: match_type = cmd_ipv4_match(word); if ((filter == FILTER_RELAXED && match_type != no_match) || (filter == FILTER_STRICT && match_type == exact_match)) return ipv4_match; break; case TERMINAL_IPV4_PREFIX: match_type = cmd_ipv4_prefix_match(word); if ((filter == FILTER_RELAXED && match_type != no_match) || (filter == FILTER_STRICT && match_type == exact_match)) return ipv4_prefix_match; break; case TERMINAL_OPTION: case TERMINAL_VARIABLE: return extend_match; case TERMINAL_LITERAL: if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word))) { if (!strcmp(str, word)) return exact_match; return partly_match; } if (filter == FILTER_STRICT && !strcmp(str, word)) return exact_match; break; default: assert (0); } return no_match; } struct cmd_matcher { struct cmd_element *cmd; /* The command element the matcher is using */ enum filter_type filter; /* Whether to use strict or relaxed matching */ vector vline; /* The tokenized commandline which is to be matched */ unsigned int index; /* The index up to which matching should be done */ /* If set, construct a list of matches at the position given by index */ enum match_type *match_type; vector *match; unsigned int word_index; /* iterating over vline */ }; static int push_argument(int *argc, const char **argv, const char *arg) { if (!arg || !strlen(arg)) arg = NULL; if (!argc || !argv) return 0; if (*argc >= CMD_ARGC_MAX) return -1; argv[(*argc)++] = arg; return 0; } static void cmd_matcher_record_match(struct cmd_matcher *matcher, enum match_type match_type, struct cmd_token *token) { if (matcher->word_index != matcher->index) return; if (matcher->match) { if (!*matcher->match) *matcher->match = vector_init(VECTOR_MIN_SIZE); vector_set(*matcher->match, token); } if (matcher->match_type) { if (match_type > *matcher->match_type) *matcher->match_type = match_type; } } static int cmd_matcher_words_left(struct cmd_matcher *matcher) { return matcher->word_index < vector_active(matcher->vline); } static const char* cmd_matcher_get_word(struct cmd_matcher *matcher) { assert(cmd_matcher_words_left(matcher)); return vector_slot(matcher->vline, matcher->word_index); } static enum matcher_rv cmd_matcher_match_terminal(struct cmd_matcher *matcher, struct cmd_token *token, int *argc, const char **argv) { const char *word; enum match_type word_match; assert(token->type == TOKEN_TERMINAL); if (!cmd_matcher_words_left(matcher)) { if (token->terminal == TERMINAL_OPTION) return MATCHER_OK; /* missing optional args are NOT pushed as NULL */ else return MATCHER_INCOMPLETE; } word = cmd_matcher_get_word(matcher); word_match = cmd_word_match(token, matcher->filter, word); if (word_match == no_match) return MATCHER_NO_MATCH; /* We have to record the input word as argument if it matched * against a variable. */ if (TERMINAL_RECORD (token->terminal)) { if (push_argument(argc, argv, word)) return MATCHER_EXCEED_ARGC_MAX; } cmd_matcher_record_match(matcher, word_match, token); matcher->word_index++; /* A vararg token should consume all left over words as arguments */ if (token->terminal == TERMINAL_VARARG) while (cmd_matcher_words_left(matcher)) { word = cmd_matcher_get_word(matcher); if (word && strlen(word)) push_argument(argc, argv, word); matcher->word_index++; } return MATCHER_OK; } static enum matcher_rv cmd_matcher_match_multiple(struct cmd_matcher *matcher, struct cmd_token *token, int *argc, const char **argv) { enum match_type multiple_match; unsigned int multiple_index; const char *word; const char *arg = NULL; struct cmd_token *word_token; enum match_type word_match; assert(token->type == TOKEN_MULTIPLE); multiple_match = no_match; if (!cmd_matcher_words_left(matcher)) return MATCHER_INCOMPLETE; word = cmd_matcher_get_word(matcher); for (multiple_index = 0; multiple_index < vector_active(token->multiple); multiple_index++) { word_token = vector_slot(token->multiple, multiple_index); word_match = cmd_word_match(word_token, matcher->filter, word); if (word_match == no_match) continue; cmd_matcher_record_match(matcher, word_match, word_token); if (word_match > multiple_match) { multiple_match = word_match; arg = word; } /* To mimic the behavior of the old command implementation, we * tolerate any ambiguities here :/ */ } matcher->word_index++; if (multiple_match == no_match) return MATCHER_NO_MATCH; if (push_argument(argc, argv, arg)) return MATCHER_EXCEED_ARGC_MAX; return MATCHER_OK; } static enum matcher_rv cmd_matcher_read_keywords(struct cmd_matcher *matcher, struct cmd_token *token, vector args_vector) { unsigned int i; unsigned long keyword_mask; unsigned int keyword_found; enum match_type keyword_match; enum match_type word_match; vector keyword_vector; struct cmd_token *word_token; const char *word; int keyword_argc; const char **keyword_argv; enum matcher_rv rv = MATCHER_NO_MATCH; keyword_mask = 0; while (1) { if (!cmd_matcher_words_left(matcher)) return MATCHER_OK; word = cmd_matcher_get_word(matcher); keyword_found = -1; keyword_match = no_match; for (i = 0; i < vector_active(token->keyword); i++) { if (keyword_mask & (1 << i)) continue; keyword_vector = vector_slot(token->keyword, i); word_token = vector_slot(keyword_vector, 0); word_match = cmd_word_match(word_token, matcher->filter, word); if (word_match == no_match) continue; cmd_matcher_record_match(matcher, word_match, word_token); if (word_match > keyword_match) { keyword_match = word_match; keyword_found = i; } else if (word_match == keyword_match) { if (matcher->word_index != matcher->index || args_vector) return MATCHER_AMBIGUOUS; } } if (keyword_found == (unsigned int)-1) return MATCHER_NO_MATCH; matcher->word_index++; if (matcher->word_index > matcher->index) return MATCHER_OK; keyword_mask |= (1 << keyword_found); if (args_vector) { keyword_argc = 0; keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*)); /* We use -1 as a marker for unused fields as NULL might be a valid value */ for (i = 0; i < CMD_ARGC_MAX + 1; i++) keyword_argv[i] = (void*)-1; vector_set_index(args_vector, keyword_found, keyword_argv); } else { keyword_argv = NULL; } keyword_vector = vector_slot(token->keyword, keyword_found); /* the keyword itself is at 0. We are only interested in the arguments, * so start counting at 1. */ for (i = 1; i < vector_active(keyword_vector); i++) { word_token = vector_slot(keyword_vector, i); switch (word_token->type) { case TOKEN_TERMINAL: rv = cmd_matcher_match_terminal(matcher, word_token, &keyword_argc, keyword_argv); break; case TOKEN_MULTIPLE: rv = cmd_matcher_match_multiple(matcher, word_token, &keyword_argc, keyword_argv); break; case TOKEN_KEYWORD: assert(!"Keywords should never be nested."); break; } if (MATCHER_ERROR(rv)) return rv; if (matcher->word_index > matcher->index) return MATCHER_OK; } } /* not reached */ } static enum matcher_rv cmd_matcher_build_keyword_args(struct cmd_matcher *matcher, struct cmd_token *token, int *argc, const char **argv, vector keyword_args_vector) { unsigned int i, j; const char **keyword_args; vector keyword_vector; struct cmd_token *word_token; const char *arg; enum matcher_rv rv; rv = MATCHER_OK; if (keyword_args_vector == NULL) return rv; for (i = 0; i < vector_active(token->keyword); i++) { keyword_vector = vector_slot(token->keyword, i); keyword_args = vector_lookup(keyword_args_vector, i); if (vector_active(keyword_vector) == 1) { /* this is a keyword without arguments */ if (keyword_args) { word_token = vector_slot(keyword_vector, 0); arg = word_token->cmd; } else { arg = NULL; } if (push_argument(argc, argv, arg)) rv = MATCHER_EXCEED_ARGC_MAX; } else { /* this is a keyword with arguments */ if (keyword_args) { /* the keyword was present, so just fill in the arguments */ for (j = 0; keyword_args[j] != (void*)-1; j++) if (push_argument(argc, argv, keyword_args[j])) rv = MATCHER_EXCEED_ARGC_MAX; XFREE(MTYPE_TMP, keyword_args); } else { /* the keyword was not present, insert NULL for the arguments * the keyword would have taken. */ for (j = 1; j < vector_active(keyword_vector); j++) { word_token = vector_slot(keyword_vector, j); if ((word_token->type == TOKEN_TERMINAL && TERMINAL_RECORD (word_token->terminal)) || word_token->type == TOKEN_MULTIPLE) { if (push_argument(argc, argv, NULL)) rv = MATCHER_EXCEED_ARGC_MAX; } } } } } vector_free(keyword_args_vector); return rv; } static enum matcher_rv cmd_matcher_match_keyword(struct cmd_matcher *matcher, struct cmd_token *token, int *argc, const char **argv) { vector keyword_args_vector; enum matcher_rv reader_rv; enum matcher_rv builder_rv; assert(token->type == TOKEN_KEYWORD); if (argc && argv) keyword_args_vector = vector_init(VECTOR_MIN_SIZE); else keyword_args_vector = NULL; reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector); builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc, argv, keyword_args_vector); /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */ if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv)) return builder_rv; return reader_rv; } static void cmd_matcher_init(struct cmd_matcher *matcher, struct cmd_element *cmd, enum filter_type filter, vector vline, unsigned int index, enum match_type *match_type, vector *match) { memset(matcher, 0, sizeof(*matcher)); matcher->cmd = cmd; matcher->filter = filter; matcher->vline = vline; matcher->index = index; matcher->match_type = match_type; if (matcher->match_type) *matcher->match_type = no_match; matcher->match = match; matcher->word_index = 0; } static enum matcher_rv cmd_element_match(struct cmd_element *cmd_element, enum filter_type filter, vector vline, unsigned int index, enum match_type *match_type, vector *match, int *argc, const char **argv) { struct cmd_matcher matcher; unsigned int token_index; enum matcher_rv rv = MATCHER_NO_MATCH; cmd_matcher_init(&matcher, cmd_element, filter, vline, index, match_type, match); if (argc != NULL) *argc = 0; for (token_index = 0; token_index < vector_active(cmd_element->tokens); token_index++) { struct cmd_token *token = vector_slot(cmd_element->tokens, token_index); switch (token->type) { case TOKEN_TERMINAL: rv = cmd_matcher_match_terminal(&matcher, token, argc, argv); break; case TOKEN_MULTIPLE: rv = cmd_matcher_match_multiple(&matcher, token, argc, argv); break; case TOKEN_KEYWORD: rv = cmd_matcher_match_keyword(&matcher, token, argc, argv); } if (MATCHER_ERROR(rv)) return rv; if (matcher.word_index > index) return MATCHER_OK; } /* return MATCHER_COMPLETE if all words were consumed */ if (matcher.word_index >= vector_active(vline)) return MATCHER_COMPLETE; /* return MATCHER_COMPLETE also if only an empty word is left. */ if (matcher.word_index == vector_active(vline) - 1 && (!vector_slot(vline, matcher.word_index) || !strlen((char*)vector_slot(vline, matcher.word_index)))) return MATCHER_COMPLETE; return MATCHER_NO_MATCH; /* command is too long to match */ } /** * Filter a given vector of commands against a given commandline and * calculate possible completions. * * @param commands A vector of struct cmd_element*. Commands that don't * match against the given command line will be overwritten * with NULL in that vector. * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically * determines how incomplete commands are handled, compare with * cmd_word_match for details. * @param vline A vector of char* containing the tokenized commandline. * @param index Only match up to the given token of the commandline. * @param match_type Record the type of the best match here. * @param matches Record the matches here. For each cmd_element in the commands * vector, a match vector will be created in the matches vector. * That vector will contain all struct command_token* of the * cmd_element which matched against the given vline at the given * index. * @return A code specifying if an error occurred. If all went right, it's * CMD_SUCCESS. */ static int cmd_vector_filter(vector commands, enum filter_type filter, vector vline, unsigned int index, enum match_type *match_type, vector *matches) { unsigned int i; struct cmd_element *cmd_element; enum match_type best_match; enum match_type element_match; enum matcher_rv matcher_rv; best_match = no_match; *matches = vector_init(VECTOR_MIN_SIZE); for (i = 0; i < vector_active (commands); i++) if ((cmd_element = vector_slot (commands, i)) != NULL) { vector_set_index(*matches, i, NULL); matcher_rv = cmd_element_match(cmd_element, filter, vline, index, &element_match, (vector*)&vector_slot(*matches, i), NULL, NULL); if (MATCHER_ERROR(matcher_rv)) { vector_slot(commands, i) = NULL; if (matcher_rv == MATCHER_AMBIGUOUS) return CMD_ERR_AMBIGUOUS; if (matcher_rv == MATCHER_EXCEED_ARGC_MAX) return CMD_ERR_EXEED_ARGC_MAX; } else if (element_match > best_match) { best_match = element_match; } } *match_type = best_match; return CMD_SUCCESS; } /** * Check whether a given commandline is complete if used for a specific * cmd_element. * * @param cmd_element A cmd_element against which the commandline should be * checked. * @param vline The tokenized commandline. * @return 1 if the given commandline is complete, 0 otherwise. */ static int cmd_is_complete(struct cmd_element *cmd_element, vector vline) { enum matcher_rv rv; rv = cmd_element_match(cmd_element, FILTER_RELAXED, vline, -1, NULL, NULL, NULL, NULL); return (rv == MATCHER_COMPLETE); } /** * Parse a given commandline and construct a list of arguments for the * given command_element. * * @param cmd_element The cmd_element for which we want to construct arguments. * @param vline The tokenized commandline. * @param argc Where to store the argument count. * @param argv Where to store the argument list. Should be at least * CMD_ARGC_MAX elements long. * @return CMD_SUCCESS if everything went alright, an error otherwise. */ static int cmd_parse(struct cmd_element *cmd_element, vector vline, int *argc, const char **argv) { enum matcher_rv rv = cmd_element_match(cmd_element, FILTER_RELAXED, vline, -1, NULL, NULL, argc, argv); switch (rv) { case MATCHER_COMPLETE: return CMD_SUCCESS; case MATCHER_NO_MATCH: return CMD_ERR_NO_MATCH; case MATCHER_AMBIGUOUS: return CMD_ERR_AMBIGUOUS; case MATCHER_EXCEED_ARGC_MAX: return CMD_ERR_EXEED_ARGC_MAX; default: return CMD_ERR_INCOMPLETE; } } /* Check ambiguous match */ static int is_cmd_ambiguous (vector cmd_vector, const char *command, vector matches, enum match_type type) { unsigned int i; unsigned int j; const char *str = NULL; const char *matched = NULL; vector match_vector; struct cmd_token *cmd_token; if (command == NULL) command = ""; for (i = 0; i < vector_active (matches); i++) if ((match_vector = vector_slot (matches, i)) != NULL) { int match = 0; for (j = 0; j < vector_active (match_vector); j++) if ((cmd_token = vector_slot (match_vector, j)) != NULL) { enum match_type ret; assert(cmd_token->type == TOKEN_TERMINAL); if (cmd_token->type != TOKEN_TERMINAL) continue; str = cmd_token->cmd; switch (type) { case exact_match: if (!TERMINAL_RECORD (cmd_token->terminal) && strcmp (command, str) == 0) match++; break; case partly_match: if (!TERMINAL_RECORD (cmd_token->terminal) && 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; #ifdef HAVE_IPV6 case ipv6_match: if (cmd_token->terminal == TERMINAL_IPV6) 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; #endif /* HAVE_IPV6 */ case ipv4_match: if (cmd_token->terminal == TERMINAL_IPV4) 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 (TERMINAL_RECORD (cmd_token->terminal)) match++; break; case no_match: default: break; } } if (!match) vector_slot (cmd_vector, i) = NULL; } return 0; } /* If src matches dst return dst string, otherwise return NULL */ static const char * cmd_entry_function (const char *src, struct cmd_token *token) { const char *dst = token->cmd; /* Skip variable arguments. */ if (TERMINAL_RECORD (token->terminal)) 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 */ static const char * cmd_entry_function_desc (const char *src, struct cmd_token *token) { const char *dst = token->cmd; switch (token->terminal) { case TERMINAL_VARARG: return dst; case TERMINAL_RANGE: if (cmd_range_match (dst, src)) return dst; else return NULL; case TERMINAL_IPV6: if (cmd_ipv6_match (src)) return dst; else return NULL; case TERMINAL_IPV6_PREFIX: if (cmd_ipv6_prefix_match (src)) return dst; else return NULL; case TERMINAL_IPV4: if (cmd_ipv4_match (src)) return dst; else return NULL; case TERMINAL_IPV4_PREFIX: if (cmd_ipv4_prefix_match (src)) return dst; else return NULL; /* Optional or variable commands always match on '?' */ case TERMINAL_OPTION: case TERMINAL_VARIABLE: return dst; case TERMINAL_LITERAL: /* 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; default: assert(0); return NULL; } } /** * Check whether a string is already present in a vector of strings. * @param v A vector of char*. * @param str A char*. * @return 0 if str is already present in the vector, 1 otherwise. */ static int cmd_unique_string (vector v, const char *str) { unsigned int i; char *match; for (i = 0; i < vector_active (v); i++) if ((match = vector_slot (v, i)) != NULL) if (strcmp (match, str) == 0) return 0; return 1; } /** * Check whether a struct cmd_token matching a given string is already * present in a vector of struct cmd_token. * @param v A vector of struct cmd_token*. * @param str A char* which should be searched for. * @return 0 if there is a struct cmd_token* with its cmd matching str, * 1 otherwise. */ static int desc_unique_string (vector v, const char *str) { unsigned int i; struct cmd_token *token; for (i = 0; i < vector_active (v); i++) if ((token = vector_slot (v, i)) != NULL) if (strcmp (token->cmd, str) == 0) return 0; return 1; } static int cmd_try_do_shortcut (enum node_type node, char* first_word) { if ( first_word != NULL && node != AUTH_NODE && node != VIEW_NODE && node != AUTH_ENABLE_NODE && node != ENABLE_NODE && node != RESTRICTED_NODE && 0 == strcmp( "do", first_word ) ) return 1; return 0; } static void cmd_matches_free(vector *matches) { unsigned int i; vector cmd_matches; for (i = 0; i < vector_active(*matches); i++) if ((cmd_matches = vector_slot(*matches, i)) != NULL) vector_free(cmd_matches); vector_free(*matches); *matches = NULL; } static int cmd_describe_cmp(const void *a, const void *b) { const struct cmd_token *first = *(struct cmd_token * const *)a; const struct cmd_token *second = *(struct cmd_token * const *)b; return strcmp(first->cmd, second->cmd); } static void cmd_describe_sort(vector matchvec) { qsort(matchvec->index, vector_active(matchvec), sizeof(void*), cmd_describe_cmp); } /* '?' describe command support. */ static vector cmd_describe_command_real (vector vline, struct vty *vty, int *status) { unsigned int i; vector cmd_vector; #define INIT_MATCHVEC_SIZE 10 vector matchvec; struct cmd_element *cmd_element; unsigned int index; int ret; enum match_type match; char *command; vector matches = NULL; vector match_vector; uint32_t command_found = 0; const char *last_word; /* Set index. */ if (vector_active (vline) == 0) { *status = CMD_ERR_NO_MATCH; return NULL; } index = vector_active (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 and build a list how they could possibly continue. */ for (i = 0; i <= index; i++) { command = vector_slot (vline, i); if (matches) cmd_matches_free(&matches); ret = cmd_vector_filter(cmd_vector, FILTER_RELAXED, vline, i, &match, &matches); if (ret != CMD_SUCCESS) { vector_free (cmd_vector); vector_free (matchvec); cmd_matches_free(&matches); *status = ret; return NULL; } /* The last match may well be ambigious, so break here */ if (i == index) break; if (match == vararg_match) { /* We found a vararg match - so we can throw out the current matches here * and don't need to continue checking the command input */ unsigned int j, k; for (j = 0; j < vector_active (matches); j++) if ((match_vector = vector_slot (matches, j)) != NULL) for (k = 0; k < vector_active (match_vector); k++) { struct cmd_token *token = vector_slot (match_vector, k); vector_set (matchvec, token); } *status = CMD_SUCCESS; vector_set(matchvec, &token_cr); vector_free (cmd_vector); cmd_matches_free(&matches); cmd_describe_sort(matchvec); return matchvec; } ret = is_cmd_ambiguous(cmd_vector, command, matches, match); if (ret == 1) { vector_free (cmd_vector); vector_free (matchvec); cmd_matches_free(&matches); *status = CMD_ERR_AMBIGUOUS; return NULL; } else if (ret == 2) { vector_free (cmd_vector); vector_free (matchvec); cmd_matches_free(&matches); *status = CMD_ERR_NO_MATCH; return NULL; } } /* Make description vector. */ for (i = 0; i < vector_active (matches); i++) { if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) { unsigned int j; vector vline_trimmed; command_found++; last_word = vector_slot(vline, vector_active(vline) - 1); if (last_word == NULL || !strlen(last_word)) { vline_trimmed = vector_copy(vline); vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1); if (cmd_is_complete(cmd_element, vline_trimmed) && desc_unique_string(matchvec, command_cr)) { if (match != vararg_match) vector_set(matchvec, &token_cr); } vector_free(vline_trimmed); } match_vector = vector_slot (matches, i); if (match_vector) { for (j = 0; j < vector_active(match_vector); j++) { struct cmd_token *token = vector_slot(match_vector, j); const char *string; string = cmd_entry_function_desc(command, token); if (string && desc_unique_string(matchvec, string)) vector_set(matchvec, token); } } } } /* * We can get into this situation when the command is complete * but the last part of the command is an optional piece of * the cli. */ last_word = vector_slot(vline, vector_active(vline) - 1); if (command_found == 0 && (last_word == NULL || !strlen(last_word))) vector_set(matchvec, &token_cr); vector_free (cmd_vector); cmd_matches_free(&matches); if (vector_slot (matchvec, 0) == NULL) { vector_free (matchvec); *status = CMD_ERR_NO_MATCH; return NULL; } *status = CMD_SUCCESS; cmd_describe_sort(matchvec); return matchvec; } vector cmd_describe_command (vector vline, struct vty *vty, int *status) { vector ret; if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) ) { enum node_type onode; vector shifted_vline; unsigned int index; onode = vty->node; vty->node = ENABLE_NODE; /* We can try it on enable node, cos' the vty is authenticated */ shifted_vline = vector_init (vector_count(vline)); /* use memcpy? */ for (index = 1; index < vector_active (vline); index++) { vector_set_index (shifted_vline, index-1, vector_lookup(vline, index)); } ret = cmd_describe_command_real (shifted_vline, vty, status); vector_free(shifted_vline); vty->node = onode; return ret; } return cmd_describe_command_real (vline, vty, status); } /* Check LCD of matched command. */ static 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; } static int cmd_complete_cmp(const void *a, const void *b) { const char *first = *(char * const *)a; const char *second = *(char * const *)b; if (!first) { if (!second) return 0; return 1; } if (!second) return -1; return strcmp(first, second); } static void cmd_complete_sort(vector matchvec) { qsort(matchvec->index, vector_active(matchvec), sizeof(void*), cmd_complete_cmp); } /* Command line completion support. */ static char ** cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib) { unsigned int i; vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); #define INIT_MATCHVEC_SIZE 10 vector matchvec; unsigned int index; char **match_str; struct cmd_token *token; char *command; int lcd; vector matches = NULL; vector match_vector; if (vector_active (vline) == 0) { vector_free (cmd_vector); *status = CMD_ERR_NO_MATCH; return NULL; } else index = vector_active (vline) - 1; /* First, filter by command string */ for (i = 0; i <= index; i++) { command = vector_slot (vline, i); enum match_type match; int ret; if (matches) cmd_matches_free(&matches); /* First try completion match, if there is exactly match return 1 */ ret = cmd_vector_filter(cmd_vector, FILTER_RELAXED, vline, i, &match, &matches); if (ret != CMD_SUCCESS) { vector_free(cmd_vector); cmd_matches_free(&matches); *status = ret; return NULL; } /* Break here - the completion mustn't be checked to be non-ambiguous */ if (i == index) break; /* If there is exact match then filter ambiguous match else check ambiguousness. */ ret = is_cmd_ambiguous (cmd_vector, command, matches, match); if (ret == 1) { vector_free (cmd_vector); cmd_matches_free(&matches); *status = CMD_ERR_AMBIGUOUS; return NULL; } } /* Prepare match vector. */ matchvec = vector_init (INIT_MATCHVEC_SIZE); /* Build the possible list of continuations into a list of completions */ for (i = 0; i < vector_active (matches); i++) if ((match_vector = vector_slot (matches, i))) { const char *string; unsigned int j; for (j = 0; j < vector_active (match_vector); j++) if ((token = vector_slot (match_vector, j))) { string = cmd_entry_function (vector_slot (vline, index), token); if (string && cmd_unique_string (matchvec, string)) vector_set (matchvec, (islib != 0 ? XSTRDUP (MTYPE_TMP, string) : strdup (string) /* rl freed */)); } } /* We don't need cmd_vector any more. */ vector_free (cmd_vector); cmd_matches_free(&matches); /* 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 = (islib != 0 ? XMALLOC (MTYPE_TMP, lcd + 1) : malloc(lcd + 1)); memcpy (lcdstr, matchvec->index[0], lcd); lcdstr[lcd] = '\0'; /* Free matchvec. */ for (i = 0; i < vector_active (matchvec); i++) { if (vector_slot (matchvec, i)) { if (islib != 0) XFREE (MTYPE_TMP, vector_slot (matchvec, i)); else free (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; cmd_complete_sort(matchvec); vector_only_wrapper_free (matchvec); *status = CMD_COMPLETE_LIST_MATCH; return match_str; } char ** cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib) { char **ret; if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) ) { enum node_type onode; vector shifted_vline; unsigned int index; onode = vty->node; vty->node = ENABLE_NODE; /* We can try it on enable node, cos' the vty is authenticated */ shifted_vline = vector_init (vector_count(vline)); /* use memcpy? */ for (index = 1; index < vector_active (vline); index++) { vector_set_index (shifted_vline, index-1, vector_lookup(vline, index)); } ret = cmd_complete_command_real (shifted_vline, vty, status, islib); vector_free(shifted_vline); vty->node = onode; return ret; } return cmd_complete_command_real (vline, vty, status, islib); } char ** cmd_complete_command (vector vline, struct vty *vty, int *status) { return cmd_complete_command_lib (vline, vty, status, 0); } /* return parent node */ /* MUST eventually converge on CONFIG_NODE */ enum node_type node_parent ( enum node_type node ) { enum node_type ret; assert (node > CONFIG_NODE); switch (node) { case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: case BGP_ENCAP_NODE: case BGP_ENCAPV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: ret = BGP_NODE; break; case KEYCHAIN_KEY_NODE: ret = KEYCHAIN_NODE; break; case LINK_PARAMS_NODE: ret = INTERFACE_NODE; break; default: ret = CONFIG_NODE; break; } return ret; } /* Execute command by argument vline vector. */ static int cmd_execute_command_real (vector vline, enum filter_type filter, struct vty *vty, struct cmd_element **cmd) { unsigned int i; unsigned int index; vector cmd_vector; struct cmd_element *cmd_element; struct cmd_element *matched_element; unsigned int matched_count, incomplete_count; int argc; const char *argv[CMD_ARGC_MAX]; enum match_type match = 0; char *command; int ret; vector matches; /* Make copy of command elements. */ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); for (index = 0; index < vector_active (vline); index++) { command = vector_slot (vline, index); ret = cmd_vector_filter(cmd_vector, filter, vline, index, &match, &matches); if (ret != CMD_SUCCESS) { cmd_matches_free(&matches); return ret; } if (match == vararg_match) { cmd_matches_free(&matches); break; } ret = is_cmd_ambiguous (cmd_vector, command, matches, match); cmd_matches_free(&matches); 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_active (cmd_vector); i++) if ((cmd_element = vector_slot (cmd_vector, i))) { if (cmd_is_complete(cmd_element, vline)) { 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; ret = cmd_parse(matched_element, vline, &argc, argv); if (ret != CMD_SUCCESS) return ret; /* 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 a given command, handling things like "do ..." and checking * whether the given command might apply at a parent node if doesn't * apply for the current node. * * @param vline Command line input, vector of char* where each element is * one input token. * @param vty The vty context in which the command should be executed. * @param cmd Pointer where the struct cmd_element of the matched command * will be stored, if any. May be set to NULL if this info is * not needed. * @param vtysh If set != 0, don't lookup the command at parent nodes. * @return The status of the command that has been executed or an error code * as to why no command could be executed. */ int cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd, int vtysh) { int ret, saved_ret, tried = 0; enum node_type onode, try_node; onode = try_node = vty->node; if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) ) { vector shifted_vline; unsigned int index; vty->node = ENABLE_NODE; /* We can try it on enable node, cos' the vty is authenticated */ shifted_vline = vector_init (vector_count(vline)); /* use memcpy? */ for (index = 1; index < vector_active (vline); index++) { vector_set_index (shifted_vline, index-1, vector_lookup(vline, index)); } ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd); vector_free(shifted_vline); vty->node = onode; return ret; } saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd); if (vtysh) return saved_ret; /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */ while ( ret != CMD_SUCCESS && ret != CMD_WARNING && vty->node > CONFIG_NODE ) { try_node = node_parent(try_node); vty->node = try_node; ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd); tried = 1; if (ret == CMD_SUCCESS || ret == CMD_WARNING) { /* succesfull command, leave the node as is */ return ret; } } /* no command succeeded, reset the vty to the original node and return the error for this node */ if ( tried ) vty->node = onode; return saved_ret; } /** * Execute a given command, matching it strictly against the current node. * This mode is used when reading config files. * * @param vline Command line input, vector of char* where each element is * one input token. * @param vty The vty context in which the command should be executed. * @param cmd Pointer where the struct cmd_element* of the matched command * will be stored, if any. May be set to NULL if this info is * not needed. * @return The status of the command that has been executed or an error code * as to why no command could be executed. */ int cmd_execute_command_strict (vector vline, struct vty *vty, struct cmd_element **cmd) { return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd); } /** * Parse one line of config, walking up the parse tree attempting to find a match * * @param vty The vty context in which the command should be executed. * @param cmd Pointer where the struct cmd_element* of the match command * will be stored, if any. May be set to NULL if this info is * not needed. * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON * or not. * @return The status of the command that has been executed or an error code * as to why no command could be executed. */ int command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon) { vector vline; int saved_node; int ret; vline = cmd_make_strvec (vty->buf); /* In case of comment line */ if (vline == NULL) return CMD_SUCCESS; /* Execute configuration command : this is strict match */ ret = cmd_execute_command_strict (vline, vty, cmd); saved_node = vty->node; while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) && ret != CMD_SUCCESS && ret != CMD_WARNING && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE) { vty->node = node_parent(vty->node); ret = cmd_execute_command_strict (vline, vty, cmd); } // If climbing the tree did not work then ignore the command and // stay at the same node if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) && ret != CMD_SUCCESS && ret != CMD_WARNING && ret != CMD_ERR_NOTHING_TODO) { vty->node = saved_node; } cmd_free_strvec (vline); return ret; } /* Configration make from file. */ int config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num) { int ret; *line_num = 0; while (fgets (vty->buf, vty->max, fp)) { ++(*line_num); ret = command_config_read_one_line (vty, NULL, 0); if (ret != CMD_SUCCESS && ret != CMD_WARNING && ret != CMD_ERR_NOTHING_TODO) 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: case RESTRICTED_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 BABEL_NODE: case OSPF_NODE: case OSPF6_NODE: case ISIS_NODE: case KEYCHAIN_NODE: case MASC_NODE: case RMAP_NODE: case PIM_NODE: case VTY_NODE: vty->node = CONFIG_NODE; break; case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: case BGP_ENCAP_NODE: case BGP_ENCAPV6_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: vty->node = BGP_NODE; break; case KEYCHAIN_KEY_NODE: vty->node = KEYCHAIN_NODE; break; case LINK_PARAMS_NODE: vty->node = INTERFACE_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: case RESTRICTED_NODE: /* Nothing to do. */ break; case CONFIG_NODE: case INTERFACE_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: case BABEL_NODE: case BGP_NODE: case BGP_ENCAP_NODE: case BGP_ENCAPV6_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: case ISIS_NODE: case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: case PIM_NODE: case VTY_NODE: case LINK_PARAMS_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, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"", VTY_NEWLINE); vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE); vty_out (vty, "configured with:%s %s%s", VTY_NEWLINE, QUAGGA_CONFIG_ARGS, 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, "Quagga 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") { unsigned int i; struct cmd_node *cnode = vector_slot (cmdvec, vty->node); struct cmd_element *cmd; for (i = 0; i < vector_active (cnode->cmd_vector); i++) if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL && !(cmd->attr == CMD_ATTR_DEPRECATED || cmd->attr == CMD_ATTR_HIDDEN)) 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") { unsigned int i; int fd, dupfd = -1; struct cmd_node *node; char *config_file; char *config_file_tmp = NULL; char *config_file_sav = NULL; int ret = CMD_WARNING; 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 = XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1); strcpy (config_file_sav, config_file); strcat (config_file_sav, CONF_BACKUP_EXT); config_file_tmp = XMALLOC (MTYPE_TMP, 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); goto finished; } /* Make vty for configuration file. */ file_vty = vty_new (); file_vty->wfd = 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_active (cmdvec); i++) if ((node = vector_slot (cmdvec, i)) && node->func) { if ((*node->func) (file_vty)) vty_out (file_vty, "!\n"); } if ((dupfd = dup (file_vty->wfd)) < 0) { vty_out (vty, "Couldn't dup fd (for fdatasync) for %s, %s (%d).%s", config_file, safe_strerror(errno), errno, VTY_NEWLINE); } vty_close (file_vty); if (fdatasync (dupfd) < 0) { vty_out (vty, "Couldn't fdatasync %s, %s (%d)!%s", config_file, safe_strerror(errno), errno, VTY_NEWLINE); } 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); goto finished; } if (link (config_file, config_file_sav) != 0) { vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav, VTY_NEWLINE); goto finished; } if (rename (config_file_tmp, config_file) != 0) { vty_out (vty, "Can't move configuration file %s into place.%s", config_file, VTY_NEWLINE); goto finished; } if (chmod (config_file, CONFIGFILE_MASK) != 0) { vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s", config_file, safe_strerror(errno), errno, VTY_NEWLINE); goto finished; } vty_out (vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE); ret = CMD_SUCCESS; finished: if (dupfd >= 0) close (dupfd); unlink (config_file_tmp); XFREE (MTYPE_TMP, config_file_tmp); XFREE (MTYPE_TMP, config_file_sav); return ret; } 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") { unsigned int i; struct cmd_node *node; if (vty->type == VTY_SHELL_SERV) { for (i = 0; i < vector_active (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_active (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 (MTYPE_HOST, host.name); host.name = XSTRDUP (MTYPE_HOST, 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 (MTYPE_HOST, 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 (MTYPE_HOST, host.password); host.password = NULL; if (host.password_encrypt) XFREE (MTYPE_HOST, host.password_encrypt); host.password_encrypt = XSTRDUP (MTYPE_HOST, 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 (MTYPE_HOST, host.password); host.password = NULL; if (host.encrypt) { if (host.password_encrypt) XFREE (MTYPE_HOST, host.password_encrypt); host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0])); } else host.password = XSTRDUP (MTYPE_HOST, 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 (MTYPE_HOST, host.enable); host.enable = NULL; if (host.enable_encrypt) XFREE (MTYPE_HOST, host.enable_encrypt); host.enable_encrypt = XSTRDUP (MTYPE_HOST, 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 (MTYPE_HOST, host.enable); host.enable = NULL; /* Plain password input. */ if (host.encrypt) { if (host.enable_encrypt) XFREE (MTYPE_HOST, host.enable_encrypt); host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0])); } else host.enable = XSTRDUP (MTYPE_HOST, 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 (MTYPE_HOST, host.enable); host.enable = NULL; if (host.enable_encrypt) XFREE (MTYPE_HOST, 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 (MTYPE_HOST, host.password_encrypt); host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password)); } if (host.enable) { if (host.enable_encrypt) XFREE (MTYPE_HOST, host.enable_encrypt); host.enable_encrypt = XSTRDUP (MTYPE_HOST, 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_encrypt) XFREE (MTYPE_HOST, host.password_encrypt); host.password_encrypt = NULL; if (host.enable_encrypt) XFREE (MTYPE_HOST, 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_HIDDEN (do_echo, echo_cmd, "echo .MESSAGE", "Echo a message back to the vty\n" "The message to echo\n") { char *message; vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE); if (message) XFREE(MTYPE_TMP, message); return CMD_SUCCESS; } DEFUN (config_logmsg, config_logmsg_cmd, "logmsg "LOG_LEVELS" .MESSAGE", "Send a message to enabled logging destinations\n" LOG_LEVEL_DESC "The message to send\n") { int level; char *message; if ((level = level_match(argv[0])) == ZLOG_DISABLED) return CMD_ERR_NO_MATCH; zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : "")); if (message) XFREE(MTYPE_TMP, message); return CMD_SUCCESS; } DEFUN (show_logging, show_logging_cmd, "show logging", SHOW_STR "Show current logging configuration\n") { struct zlog *zl = zlog_default; vty_out (vty, "Syslog logging: "); if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED) vty_out (vty, "disabled"); else vty_out (vty, "level %s, facility %s, ident %s", zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]], facility_name(zl->facility), zl->ident); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "Stdout logging: "); if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED) vty_out (vty, "disabled"); else vty_out (vty, "level %s", zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "Monitor logging: "); if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED) vty_out (vty, "disabled"); else vty_out (vty, "level %s", zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "File logging: "); if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp) vty_out (vty, "disabled"); else vty_out (vty, "level %s, filename %s", zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]], zl->filename); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "Protocol name: %s%s", zlog_proto_names[zl->protocol], VTY_NEWLINE); vty_out (vty, "Record priority: %s%s", (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE); vty_out (vty, "Timestamp precision: %d%s", zl->timestamp_precision, VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (config_log_stdout, config_log_stdout_cmd, "log stdout", "Logging control\n" "Set stdout logging level\n") { zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl); return CMD_SUCCESS; } DEFUN (config_log_stdout_level, config_log_stdout_level_cmd, "log stdout "LOG_LEVELS, "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC) { int level; if ((level = level_match(argv[0])) == ZLOG_DISABLED) return CMD_ERR_NO_MATCH; zlog_set_level (NULL, ZLOG_DEST_STDOUT, level); return CMD_SUCCESS; } DEFUN (no_config_log_stdout, no_config_log_stdout_cmd, "no log stdout [LEVEL]", NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n") { zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); return CMD_SUCCESS; } DEFUN (config_log_monitor, config_log_monitor_cmd, "log monitor", "Logging control\n" "Set terminal line (monitor) logging level\n") { zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl); return CMD_SUCCESS; } DEFUN (config_log_monitor_level, config_log_monitor_level_cmd, "log monitor "LOG_LEVELS, "Logging control\n" "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC) { int level; if ((level = level_match(argv[0])) == ZLOG_DISABLED) return CMD_ERR_NO_MATCH; zlog_set_level (NULL, ZLOG_DEST_MONITOR, level); return CMD_SUCCESS; } DEFUN (no_config_log_monitor, no_config_log_monitor_cmd, "no log monitor [LEVEL]", NO_STR "Logging control\n" "Disable terminal line (monitor) logging\n" "Logging level\n") { zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); return CMD_SUCCESS; } static int set_log_file(struct vty *vty, const char *fname, int loglevel) { int ret; char *p = NULL; const char *fullpath; /* Path detection. */ if (! IS_DIRECTORY_SEP (*fname)) { char cwd[MAXPATHLEN+1]; cwd[MAXPATHLEN] = '\0'; if (getcwd (cwd, MAXPATHLEN) == NULL) { zlog_err ("config_log_file: Unable to alloc mem!"); return CMD_WARNING; } if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2)) == NULL) { zlog_err ("config_log_file: Unable to alloc mem!"); return CMD_WARNING; } sprintf (p, "%s/%s", cwd, fname); fullpath = p; } else fullpath = fname; ret = zlog_set_file (NULL, fullpath, loglevel); if (p) XFREE (MTYPE_TMP, p); if (!ret) { vty_out (vty, "can't open logfile %s\n", fname); return CMD_WARNING; } if (host.logfile) XFREE (MTYPE_HOST, host.logfile); host.logfile = XSTRDUP (MTYPE_HOST, fname); return CMD_SUCCESS; } DEFUN (config_log_file, config_log_file_cmd, "log file FILENAME", "Logging control\n" "Logging to file\n" "Logging filename\n") { return set_log_file(vty, argv[0], zlog_default->default_lvl); } DEFUN (config_log_file_level, config_log_file_level_cmd, "log file FILENAME "LOG_LEVELS, "Logging control\n" "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC) { int level; if ((level = level_match(argv[1])) == ZLOG_DISABLED) return CMD_ERR_NO_MATCH; return set_log_file(vty, argv[0], level); } 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_HOST, host.logfile); host.logfile = NULL; return CMD_SUCCESS; } ALIAS (no_config_log_file, no_config_log_file_level_cmd, "no log file FILENAME LEVEL", NO_STR "Logging control\n" "Cancel logging to file\n" "Logging file name\n" "Logging level\n") DEFUN (config_log_syslog, config_log_syslog_cmd, "log syslog", "Logging control\n" "Set syslog logging level\n") { zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); return CMD_SUCCESS; } DEFUN (config_log_syslog_level, config_log_syslog_level_cmd, "log syslog "LOG_LEVELS, "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC) { int level; if ((level = level_match(argv[0])) == ZLOG_DISABLED) return CMD_ERR_NO_MATCH; zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level); return CMD_SUCCESS; } DEFUN_DEPRECATED (config_log_syslog_facility, config_log_syslog_facility_cmd, "log syslog facility "LOG_FACILITIES, "Logging control\n" "Logging goes to syslog\n" "(Deprecated) Facility parameter for syslog messages\n" LOG_FACILITY_DESC) { int facility; if ((facility = facility_match(argv[0])) < 0) return CMD_ERR_NO_MATCH; zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); zlog_default->facility = facility; return CMD_SUCCESS; } DEFUN (no_config_log_syslog, no_config_log_syslog_cmd, "no log syslog [LEVEL]", NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n") { zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); return CMD_SUCCESS; } ALIAS (no_config_log_syslog, no_config_log_syslog_facility_cmd, "no log syslog facility "LOG_FACILITIES, NO_STR "Logging control\n" "Logging goes to syslog\n" "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) DEFUN (config_log_facility, config_log_facility_cmd, "log facility "LOG_FACILITIES, "Logging control\n" "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) { int facility; if ((facility = facility_match(argv[0])) < 0) return CMD_ERR_NO_MATCH; zlog_default->facility = facility; return CMD_SUCCESS; } DEFUN (no_config_log_facility, no_config_log_facility_cmd, "no log facility [FACILITY]", NO_STR "Logging control\n" "Reset syslog facility to default (daemon)\n" "Syslog facility\n") { zlog_default->facility = LOG_DAEMON; return CMD_SUCCESS; } DEFUN_DEPRECATED (config_log_trap, config_log_trap_cmd, "log trap "LOG_LEVELS, "Logging control\n" "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC) { int new_level ; int i; if ((new_level = level_match(argv[0])) == ZLOG_DISABLED) return CMD_ERR_NO_MATCH; zlog_default->default_lvl = new_level; for (i = 0; i < ZLOG_NUM_DESTS; i++) if (zlog_default->maxlvl[i] != ZLOG_DISABLED) zlog_default->maxlvl[i] = new_level; return CMD_SUCCESS; } DEFUN_DEPRECATED (no_config_log_trap, no_config_log_trap_cmd, "no log trap [LEVEL]", NO_STR "Logging control\n" "Permit all logging information\n" "Logging level\n") { zlog_default->default_lvl = 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 (config_log_timestamp_precision, config_log_timestamp_precision_cmd, "log timestamp precision <0-6>", "Logging control\n" "Timestamp configuration\n" "Set the timestamp precision\n" "Number of subsecond digits\n") { if (argc != 1) { vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER_RANGE("Timestamp Precision", zlog_default->timestamp_precision, argv[0], 0, 6); return CMD_SUCCESS; } DEFUN (no_config_log_timestamp_precision, no_config_log_timestamp_precision_cmd, "no log timestamp precision", NO_STR "Logging control\n" "Timestamp configuration\n" "Reset the timestamp precision to the default value of 0\n") { zlog_default->timestamp_precision = 0 ; return CMD_SUCCESS; } DEFUN (banner_motd_file, banner_motd_file_cmd, "banner motd file [FILE]", "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n") { if (host.motdfile) XFREE (MTYPE_HOST, host.motdfile); host.motdfile = XSTRDUP (MTYPE_HOST, argv[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; if (host.motdfile) XFREE (MTYPE_HOST, host.motdfile); host.motdfile = NULL; return CMD_SUCCESS; } DEFUN (show_commandtree, show_commandtree_cmd, "show commandtree", NO_STR "Show command tree\n") { /* TBD */ vector cmd_vector; unsigned int i; vty_out (vty, "Current node id: %d%s", vty->node, VTY_NEWLINE); /* vector of all commands installed at this node */ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); /* loop over all commands at this node */ for (i = 0; i < vector_active(cmd_vector); ++i) { struct cmd_element *cmd_element; /* A cmd_element (seems to be) is an individual command */ if ((cmd_element = vector_slot (cmd_vector, i)) == NULL) continue; vty_out (vty, " %s%s", cmd_element->string, VTY_NEWLINE); } vector_free (cmd_vector); return CMD_SUCCESS; } /* Set config filename. Called from vty.c */ void host_config_set (char *filename) { if (host.config) XFREE (MTYPE_HOST, host.config); host.config = XSTRDUP (MTYPE_HOST, filename); } const char * host_config_get (void) { return host.config; } static void install_default_basic (enum node_type node) { install_element (node, &config_exit_cmd); install_element (node, &config_quit_cmd); install_element (node, &config_help_cmd); install_element (node, &config_list_cmd); } /* Install common/default commands for a privileged node */ void install_default (enum node_type node) { /* VIEW_NODE is inited below, via install_default_basic, and install_element's of commands to VIEW_NODE automatically are also installed to ENABLE_NODE. For all other nodes, we must ensure install_default_basic is also called/ */ if (node != VIEW_NODE && node != ENABLE_NODE) install_default_basic (node); install_element (node, &config_end_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) { command_cr = XSTRDUP(MTYPE_CMD_TOKENS, ""); token_cr.type = TOKEN_TERMINAL; token_cr.terminal = TERMINAL_LITERAL; token_cr.cmd = command_cr; token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, ""); /* 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; host.motdfile = NULL; /* 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 (&restricted_node, NULL); install_node (&config_node, config_write_host); /* Each node's basic commands. */ install_element (VIEW_NODE, &show_version_cmd); if (terminal) { install_default_basic (VIEW_NODE); install_element (VIEW_NODE, &config_enable_cmd); install_element (VIEW_NODE, &config_terminal_length_cmd); install_element (VIEW_NODE, &config_terminal_no_length_cmd); install_element (VIEW_NODE, &show_logging_cmd); install_element (VIEW_NODE, &show_commandtree_cmd); install_element (VIEW_NODE, &echo_cmd); install_element (RESTRICTED_NODE, &config_enable_cmd); install_element (RESTRICTED_NODE, &config_terminal_length_cmd); install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd); install_element (RESTRICTED_NODE, &show_commandtree_cmd); install_element (RESTRICTED_NODE, &echo_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); if (terminal) { install_element (ENABLE_NODE, &config_logmsg_cmd); install_default (CONFIG_NODE); } install_element (CONFIG_NODE, &hostname_cmd); install_element (CONFIG_NODE, &no_hostname_cmd); if (terminal) { 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); install_element (CONFIG_NODE, &config_log_stdout_cmd); install_element (CONFIG_NODE, &config_log_stdout_level_cmd); install_element (CONFIG_NODE, &no_config_log_stdout_cmd); install_element (CONFIG_NODE, &config_log_monitor_cmd); install_element (CONFIG_NODE, &config_log_monitor_level_cmd); install_element (CONFIG_NODE, &no_config_log_monitor_cmd); install_element (CONFIG_NODE, &config_log_file_cmd); install_element (CONFIG_NODE, &config_log_file_level_cmd); install_element (CONFIG_NODE, &no_config_log_file_cmd); install_element (CONFIG_NODE, &no_config_log_file_level_cmd); install_element (CONFIG_NODE, &config_log_syslog_cmd); install_element (CONFIG_NODE, &config_log_syslog_level_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_facility_cmd); install_element (CONFIG_NODE, &no_config_log_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, &config_log_timestamp_precision_cmd); install_element (CONFIG_NODE, &no_config_log_timestamp_precision_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, &banner_motd_file_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); install_element (VIEW_NODE, &show_thread_cpu_cmd); install_element (RESTRICTED_NODE, &show_thread_cpu_cmd); install_element (ENABLE_NODE, &clear_thread_cpu_cmd); install_element (VIEW_NODE, &show_work_queues_cmd); } install_element (CONFIG_NODE, &show_commandtree_cmd); srandom(time(NULL)); } static void cmd_terminate_token(struct cmd_token *token) { unsigned int i, j; vector keyword_vect; if (token->multiple) { for (i = 0; i < vector_active(token->multiple); i++) cmd_terminate_token(vector_slot(token->multiple, i)); vector_free(token->multiple); token->multiple = NULL; } if (token->keyword) { for (i = 0; i < vector_active(token->keyword); i++) { keyword_vect = vector_slot(token->keyword, i); for (j = 0; j < vector_active(keyword_vect); j++) cmd_terminate_token(vector_slot(keyword_vect, j)); vector_free(keyword_vect); } vector_free(token->keyword); token->keyword = NULL; } XFREE(MTYPE_CMD_TOKENS, token->cmd); XFREE(MTYPE_CMD_TOKENS, token->desc); XFREE(MTYPE_CMD_TOKENS, token); } static void cmd_terminate_element(struct cmd_element *cmd) { unsigned int i; if (cmd->tokens == NULL) return; for (i = 0; i < vector_active(cmd->tokens); i++) cmd_terminate_token(vector_slot(cmd->tokens, i)); vector_free(cmd->tokens); cmd->tokens = NULL; } void cmd_terminate () { unsigned int i, j; struct cmd_node *cmd_node; struct cmd_element *cmd_element; vector cmd_node_v; if (cmdvec) { for (i = 0; i < vector_active (cmdvec); i++) if ((cmd_node = vector_slot (cmdvec, i)) != NULL) { cmd_node_v = cmd_node->cmd_vector; for (j = 0; j < vector_active (cmd_node_v); j++) if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL) cmd_terminate_element(cmd_element); vector_free (cmd_node_v); hash_clean (cmd_node->cmd_hash, NULL); hash_free (cmd_node->cmd_hash); cmd_node->cmd_hash = NULL; } vector_free (cmdvec); cmdvec = NULL; } if (command_cr) XFREE(MTYPE_CMD_TOKENS, command_cr); if (token_cr.desc) XFREE(MTYPE_CMD_TOKENS, token_cr.desc); if (host.name) XFREE (MTYPE_HOST, host.name); if (host.password) XFREE (MTYPE_HOST, host.password); if (host.password_encrypt) XFREE (MTYPE_HOST, host.password_encrypt); if (host.enable) XFREE (MTYPE_HOST, host.enable); if (host.enable_encrypt) XFREE (MTYPE_HOST, host.enable_encrypt); if (host.logfile) XFREE (MTYPE_HOST, host.logfile); if (host.motdfile) XFREE (MTYPE_HOST, host.motdfile); if (host.config) XFREE (MTYPE_HOST, host.config); } quagga-1.2.4/lib/command.h000066400000000000000000000534051325323223500153270ustar00rootroot00000000000000/* * 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" #include "lib/route_types.h" #include "hash.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; /* config file name of this host */ char *config; /* Flags for services */ int advanced; int encrypt; /* Banner configuration. */ const char *motd; char *motdfile; }; /* There are some command levels which called from command node. */ enum node_type { AUTH_NODE, /* Authentication mode of vty interface. */ RESTRICTED_NODE, /* Restricted view mode */ 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. */ VRF_NODE, /* VRF node. */ SERVICE_NODE, /* Service node. */ 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. */ BABEL_NODE, /* Babel protocol mode node. */ BGP_NODE, /* BGP protocol mode which includes BGP4+ */ BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */ BGP_VPNV6_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 */ BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */ BGP_ENCAP_NODE, /* BGP ENCAP SAFI */ BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */ OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ ISIS_NODE, /* ISIS protocol mode */ PIM_NODE, /* PIM protocol 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. */ PROTOCOL_NODE, /* protocol filtering node */ VTY_NODE, /* Vty node. */ LINK_PARAMS_NODE, /* Link-parameters node */ ZEBRA_IF_DEFAULTS_NODE, /* If defaults dummy 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. */ const 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; /* Hashed index of command node list, for de-dupping primarily */ struct hash *cmd_hash; }; enum { CMD_ATTR_DEPRECATED = 1, CMD_ATTR_HIDDEN, }; /* Structure of command element. */ struct cmd_element { const char *string; /* Command specification by string. */ int (*func) (struct cmd_element *, struct vty *, int, const char *[]); const char *doc; /* Documentation of this command. */ int daemon; /* Daemon to which this command belong. */ vector tokens; /* Vector of cmd_tokens */ u_char attr; /* Command attributes */ }; enum cmd_token_type { TOKEN_TERMINAL = 0, TOKEN_MULTIPLE, TOKEN_KEYWORD, }; enum cmd_terminal_type { _TERMINAL_BUG = 0, TERMINAL_LITERAL, TERMINAL_OPTION, TERMINAL_VARIABLE, TERMINAL_VARARG, TERMINAL_RANGE, TERMINAL_IPV4, TERMINAL_IPV4_PREFIX, TERMINAL_IPV6, TERMINAL_IPV6_PREFIX, }; /* argument to be recorded on argv[] if it's not a literal */ #define TERMINAL_RECORD(t) ((t) >= TERMINAL_OPTION) /* Command description structure. */ struct cmd_token { enum cmd_token_type type; enum cmd_terminal_type terminal; /* Used for type == MULTIPLE */ vector multiple; /* vector of cmd_token, type == FINAL */ /* Used for type == KEYWORD */ vector keyword; /* vector of vector of cmd_tokens */ /* Used for type == TERMINAL */ char *cmd; /* Command string. */ char *desc; /* 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 /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ struct cmd_element cmdname = \ { \ .string = cmdstr, \ .func = funcname, \ .doc = helpstr, \ .attr = attrs, \ .daemon = dnum, \ }; #define DEFUN_CMD_FUNC_DECL(funcname) \ static int funcname (struct cmd_element *, struct vty *, int, const char *[]); #define DEFUN_CMD_FUNC_TEXT(funcname) \ static int funcname \ (struct cmd_element *self __attribute__ ((unused)), \ struct vty *vty __attribute__ ((unused)), \ int argc __attribute__ ((unused)), \ const char *argv[] __attribute__ ((unused)) ) /* DEFUN for vty command interafce. Little bit hacky ;-). * * DEFUN(funcname, cmdname, cmdstr, helpstr) * * funcname * ======== * * Name of the function that will be defined. * * cmdname * ======= * * Name of the struct that will be defined for the command. * * cmdstr * ====== * * The cmdstr defines the command syntax. It is used by the vty subsystem * and vtysh to perform matching and completion in the cli. So you have to take * care to construct it adhering to the following grammar. The names used * for the production rules losely represent the names used in lib/command.c * * cmdstr = cmd_token , { " " , cmd_token } ; * * cmd_token = cmd_terminal * | cmd_multiple * | cmd_keyword ; * * cmd_terminal_fixed = fixed_string * | variable * | range * | ipv4 * | ipv4_prefix * | ipv6 * | ipv6_prefix ; * * cmd_terminal = cmd_terminal_fixed * | option * | vararg ; * * multiple_part = cmd_terminal_fixed ; * cmd_multiple = "(" , multiple_part , ( "|" | { "|" , multiple_part } ) , ")" ; * * keyword_part = fixed_string , { " " , ( cmd_terminal_fixed | cmd_multiple ) } ; * cmd_keyword = "{" , keyword_part , { "|" , keyword_part } , "}" ; * * lowercase = "a" | ... | "z" ; * uppercase = "A" | ... | "Z" ; * digit = "0" | ... | "9" ; * number = digit , { digit } ; * * fixed_string = (lowercase | digit) , { lowercase | digit | uppercase | "-" | "_" } ; * variable = uppercase , { uppercase | "_" } ; * range = "<" , number , "-" , number , ">" ; * ipv4 = "A.B.C.D" ; * ipv4_prefix = "A.B.C.D/M" ; * ipv6 = "X:X::X:X" ; * ipv6_prefix = "X:X::X:X/M" ; * option = "[" , variable , "]" ; * vararg = "." , variable ; * * To put that all in a textual description: A cmdstr is a sequence of tokens, * separated by spaces. * * Terminal Tokens: * * A very simple cmdstring would be something like: "show ip bgp". It consists * of three Terminal Tokens, each containing a fixed string. When this command * is called, no arguments will be passed down to the function implementing it, * as it only consists of fixed strings. * * Apart from fixed strings, Terminal Tokens can also contain variables: * An example would be "show ip bgp A.B.C.D". This command expects an IPv4 * as argument. As this is a variable, the IP address entered by the user will * be passed down as an argument. Apart from two exceptions, the other options * for Terminal Tokens behave exactly as we just discussed and only make a * difference for the CLI. The two exceptions will be discussed in the next * paragraphs. * * A Terminal Token can contain a so called option match. This is a simple * string variable that the user may omit. An example would be: * "show interface [IFNAME]". If the user calls this without an interface as * argument, no arguments will be passed down to the function implementing * this command. Otherwise, the interface name will be provided to the function * as a regular argument. * Also, a Terminal Token can contain a so called vararg. This is used e.g. in * "show ip bgp regexp .LINE". The last token is a vararg match and will * consume all the arguments the user inputs on the command line and append * those to the list of arguments passed down to the function implementing this * command. (Therefore, it doesn't make much sense to have any tokens after a * vararg because the vararg will already consume all the words the user entered * in the CLI) * * Multiple Tokens: * * The Multiple Token type can be used if there are multiple possibilities what * arguments may be used for a command, but it should map to the same function * nonetheless. An example would be "ip route A.B.C.D/M (reject|blackhole)" * In that case both "reject" and "blackhole" would be acceptable as last * arguments. The words matched by Multiple Tokens are always added to the * argument list, even if they are matched by fixed strings. Such a Multiple * Token can contain almost any type of token that would also be acceptable * for a Terminal Token, the exception are optional variables and varag. * * There is one special case that is used in some places of Quagga that should be * pointed out here shortly. An example would be "password (8|) WORD". This * construct is used to have fixed strings communicated as arguments. (The "8" * will be passed down as an argument in this case) It does not mean that * the "8" is optional. Another historic and possibly surprising property of * this construct is that it consumes two parts of helpstr. (Help * strings will be explained later) * * Keyword Tokens: * * There are commands that take a lot of different and possibly optional arguments. * An example from ospf would be the "default-information originate" command. This * command takes a lot of optional arguments that may be provided in any order. * To accomodate such commands, the Keyword Token has been implemented. * Using the keyword token, the "default-information originate" command and all * its possible options can be represented using this single cmdstr: * "default-information originate \ * {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}" * * Keywords always start with a fixed string and may be followed by arguments. * Except optional variables and vararg, everything is permitted here. * * For the special case of a keyword without arguments, either NULL or the * keyword itself will be pushed as an argument, depending on whether the * keyword is present. * For the other keywords, arguments will be only pushed for * variables/Multiple Tokens. If the keyword is not present, the arguments that * would have been pushed will be substituted by NULL. * * A few examples: * "default information originate metric-type 1 metric 1000" * would yield the following arguments: * { NULL, "1000", "1", NULL } * * "default information originate always route-map RMAP-DEFAULT" * would yield the following arguments: * { "always", NULL, NULL, "RMAP-DEFAULT" } * * helpstr * ======= * * The helpstr is used to show a short explantion for the commands that * are available when the user presses '?' on the CLI. It is the concatenation * of the helpstrings for all the tokens that make up the command. * * There should be one helpstring for each token in the cmdstr except those * containing other tokens, like Multiple or Keyword Tokens. For those, there * will only be the helpstrings of the contained tokens. * * The individual helpstrings are expected to be in the same order as their * respective Tokens appear in the cmdstr. They should each be terminated with * a linefeed. The last helpstring should be terminated with a linefeed as well. * * Care should also be taken to avoid having similar tokens with different * helpstrings. Imagine e.g. the commands "show ip ospf" and "show ip bgp". * they both contain a helpstring for "show", but only one will be displayed * when the user enters "sh?". If those two helpstrings differ, it is not * defined which one will be shown and the behavior is therefore unpredictable. */ #define DEFUN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_FUNC_DECL(funcname) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) #define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \ DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \ /* 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) \ DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) \ /* DEFUN + DEFSH */ #define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_FUNC_DECL(funcname) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) \ DEFUN_CMD_FUNC_TEXT(funcname) /* DEFUN + DEFSH with attributes */ #define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUNSH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) #define DEFUNSH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUNSH_ATTR (daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) /* ALIAS macro which define existing command's alias. */ #define ALIAS(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) #define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) #define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, 0) #define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, 0) #define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) #define ALIAS_SH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, daemon) #define ALIAS_SH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED, daemon) #endif /* VTYSH_EXTRACT_PL */ /* * Sometimes #defines create maximum values that * need to have strings created from them that * allow the parser to match against them. * These macros allow that. */ #define CMD_CREATE_STR(s) CMD_CREATE_STR_HELPER(s) #define CMD_CREATE_STR_HELPER(s) #s #define CMD_RANGE_STR(a,s) "<" CMD_CREATE_STR(a) "-" CMD_CREATE_STR(s) ">" /* 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 REDIST_STR "Redistribute information from another routing protocol\n" #define CLEAR_STR "Reset functions\n" #define RIP_STR "RIP information\n" #define BGP_STR "BGP information\n" #define BGP_SOFT_STR "Soft reconfig inbound and outbound updates\n" #define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n" #define BGP_SOFT_OUT_STR "Resend all outbound updates\n" #define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\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 information\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 ISIS_STR "IS-IS information\n" #define AREA_TAG_STR "[area tag]\n" #define MPLS_TE_STR "MPLS-TE specific commands\n" #define LINK_PARAMS_STR "Configure interface link parameters\n" #define OSPF_RI_STR "OSPF Router Information specific commands\n" #define PCE_STR "PCE Router Information specific commands\n" #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. */ extern void install_node (struct cmd_node *, int (*) (struct vty *)); extern void install_default (enum node_type); extern void install_element (enum node_type, struct cmd_element *); /* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated string with a space between each element (allocated using XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */ extern char *argv_concat (const char **argv, int argc, int shift); extern vector cmd_make_strvec (const char *); extern void cmd_free_strvec (vector); extern vector cmd_describe_command (vector, struct vty *, int *status); extern char **cmd_complete_command (vector, struct vty *, int *status); extern char **cmd_complete_command_lib (vector, struct vty *, int *status, int islib); extern const char *cmd_prompt (enum node_type); extern int command_config_read_one_line (struct vty *vty, struct cmd_element **, int use_config_node); extern int config_from_file (struct vty *, FILE *, unsigned int *line_num); extern enum node_type node_parent (enum node_type); extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int); extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **); extern void cmd_init (int); extern void cmd_terminate (void); /* 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; extern const char *host_config_get (void); extern void host_config_set (char *); extern void print_version (const char *); /* struct host global, ick */ extern struct host host; /* "" global */ extern char *command_cr; #endif /* _ZEBRA_COMMAND_H */ quagga-1.2.4/lib/daemon.c000066400000000000000000000033331325323223500151420ustar00rootroot00000000000000/* * 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 #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) { zlog_err ("fork failed: %s", safe_strerror(errno)); 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) { zlog_err ("setsid failed: %s", safe_strerror(errno)); 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 */ quagga-1.2.4/lib/distribute.c000066400000000000000000000707011325323223500160600ustar00rootroot00000000000000/* 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 *); static struct distribute * distribute_new (void) { return XCALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute)); } /* Free distribute object. */ static void distribute_free (struct distribute *dist) { int i = 0; if (dist->ifname) XFREE (MTYPE_DISTRIBUTE_IFNAME, dist->ifname); for (i=0; i < DISTRIBUTE_MAX; i++) if (dist->list[i]) free(dist->list[i]); for (i=0; i < DISTRIBUTE_MAX; i++) if (dist->prefix[i]) free(dist->prefix[i]); XFREE (MTYPE_DISTRIBUTE, dist); } static void distribute_free_if_empty(struct distribute *dist) { int i; for (i=0; i < DISTRIBUTE_MAX; i++) if (dist->list[i] != NULL || dist->prefix[i] != NULL) return; hash_release (disthash, dist); distribute_free (dist); } /* Lookup interface's distribute list. */ struct distribute * distribute_lookup (const char *ifname) { struct distribute key; struct distribute *dist; /* temporary reference */ key.ifname = (char *)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; } static void * distribute_hash_alloc (struct distribute *arg) { struct distribute *dist; dist = distribute_new (); if (arg->ifname) dist->ifname = XSTRDUP (MTYPE_DISTRIBUTE_IFNAME, arg->ifname); else dist->ifname = NULL; return dist; } /* Make new distribute list and push into hash. */ static struct distribute * distribute_get (const char *ifname) { struct distribute key; /* temporary reference */ key.ifname = (char *)ifname; return hash_get (disthash, &key, (void * (*) (void *))distribute_hash_alloc); } static unsigned int distribute_hash_make (void *arg) { const struct distribute *dist = arg; return dist->ifname ? string_hash_make (dist->ifname) : 0; } /* If two distribute-list have same value then return 1 else return 0. This function is used by hash package. */ static int distribute_cmp (const struct distribute *dist1, const 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. */ static struct distribute * distribute_list_set (const char *ifname, enum distribute_type type, const char *alist_name) { struct distribute *dist; dist = distribute_get (ifname); if (dist->list[type]) free (dist->list[type]); dist->list[type] = 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. */ static int distribute_list_unset (const char *ifname, enum distribute_type type, const char *alist_name) { struct distribute *dist; dist = distribute_lookup (ifname); if (!dist) return 0; if (!dist->list[type]) return 0; if (strcmp (dist->list[type], alist_name) != 0) return 0; free (dist->list[type]); dist->list[type] = NULL; /* Apply this distribute-list to the interface. */ (*distribute_delete_hook) (dist); /* If all dist are NULL, then free distribute list. */ distribute_free_if_empty(dist); return 1; } /* Set access-list name to the distribute list. */ static struct distribute * distribute_list_prefix_set (const char *ifname, enum distribute_type type, const char *plist_name) { struct distribute *dist; dist = distribute_get (ifname); if (dist->prefix[type]) free (dist->prefix[type]); dist->prefix[type] = 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. */ static int distribute_list_prefix_unset (const char *ifname, enum distribute_type type, const char *plist_name) { struct distribute *dist; dist = distribute_lookup (ifname); if (!dist) return 0; if (!dist->prefix[type]) return 0; if (strcmp (dist->prefix[type], plist_name) != 0) return 0; free (dist->prefix[type]); dist->prefix[type] = NULL; /* Apply this distribute-list to the interface. */ (*distribute_delete_hook) (dist); /* If all dist are NULL, then free distribute list. */ distribute_free_if_empty(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; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V4_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_set (NULL, type, argv[0]); return CMD_SUCCESS; } DEFUN (ipv6_distribute_list_all, ipv6_distribute_list_all_cmd, "ipv6 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; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_V6_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V6_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_set (NULL, type, argv[0]); return CMD_SUCCESS; } ALIAS (ipv6_distribute_list_all, ipv6_as_v4_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_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V4_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; } DEFUN (no_ipv6_distribute_list_all, no_ipv6_distribute_list_all_cmd, "no ipv6 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_V6_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V6_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_ipv6_distribute_list_all, no_ipv6_as_v4_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; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V4_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_set (argv[2], type, argv[0]); return CMD_SUCCESS; } DEFUN (ipv6_distribute_list, ipv6_distribute_list_cmd, "ipv6 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; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_V6_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V6_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_set (argv[2], type, argv[0]); return CMD_SUCCESS; } ALIAS (ipv6_distribute_list, ipv6_as_v4_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_distribute_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_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V4_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; } DEFUN (no_ipv6_distribute_list, no_ipv6_distribute_list_cmd, "no ipv6 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_V6_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V6_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_ipv6_distribute_list, no_ipv6_as_v4_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 (distribute_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; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V4_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_prefix_set (NULL, type, argv[0]); return CMD_SUCCESS; } DEFUN (ipv6_distribute_list_prefix_all, ipv6_distribute_list_prefix_all_cmd, "ipv6 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; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_V6_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V6_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_prefix_set (NULL, type, argv[0]); return CMD_SUCCESS; } ALIAS (ipv6_distribute_list_prefix_all, ipv6_as_v4_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_distribute_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_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V4_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; } DEFUN (no_ipv6_distribute_list_prefix_all, no_ipv6_distribute_list_prefix_all_cmd, "no ipv6 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_V6_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V6_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_ipv6_distribute_list_prefix_all, no_ipv6_as_v4_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 (distribute_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; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V4_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_prefix_set (argv[2], type, argv[0]); return CMD_SUCCESS; } DEFUN (ipv6_distribute_list_prefix, ipv6_distribute_list_prefix_cmd, "ipv6 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; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_V6_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V6_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_prefix_set (argv[2], type, argv[0]); return CMD_SUCCESS; } ALIAS (ipv6_distribute_list_prefix, ipv6_as_v4_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_distribute_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_V4_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V4_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; } DEFUN (no_ipv6_distribute_list_prefix, no_ipv6_distribute_list_prefix_cmd, "no ipv6 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_V6_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_V6_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_ipv6_distribute_list_prefix, no_ipv6_as_v4_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") static int distribute_print (struct vty *vty, char *tab[], int is_prefix, enum distribute_type type, int has_print) { if (tab[type]) { vty_out (vty, "%s %s%s", has_print ? "," : "", is_prefix ? "(prefix-list) " : "", tab[type]); return 1; } return has_print; } int config_show_distribute (struct vty *vty) { unsigned int i; int has_print = 0; struct hash_backet *mp; struct distribute *dist; /* Output filter configuration. */ dist = distribute_lookup (NULL); vty_out(vty, " Outgoing update filter list for all interface is"); has_print = 0; if (dist) { has_print = distribute_print(vty, dist->list, 0, DISTRIBUTE_V4_OUT, has_print); has_print = distribute_print(vty, dist->prefix, 1, DISTRIBUTE_V4_OUT, has_print); has_print = distribute_print(vty, dist->list, 0, DISTRIBUTE_V6_OUT, has_print); has_print = distribute_print(vty, dist->prefix, 1, DISTRIBUTE_V6_OUT, has_print); } if (has_print) vty_out (vty, "%s", VTY_NEWLINE); else vty_out (vty, " 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) { vty_out (vty, " %s filtered by", dist->ifname); has_print = 0; has_print = distribute_print(vty, dist->list, 0, DISTRIBUTE_V4_OUT, has_print); has_print = distribute_print(vty, dist->prefix, 1, DISTRIBUTE_V4_OUT, has_print); has_print = distribute_print(vty, dist->list, 0, DISTRIBUTE_V6_OUT, has_print); has_print = distribute_print(vty, dist->prefix, 1, DISTRIBUTE_V6_OUT, has_print); if (has_print) vty_out (vty, "%s", VTY_NEWLINE); else vty_out(vty, " nothing%s", VTY_NEWLINE); } } /* Input filter configuration. */ dist = distribute_lookup (NULL); vty_out(vty, " Incoming update filter list for all interface is"); has_print = 0; if (dist) { has_print = distribute_print(vty, dist->list, 0, DISTRIBUTE_V4_IN, has_print); has_print = distribute_print(vty, dist->prefix, 1, DISTRIBUTE_V4_IN, has_print); has_print = distribute_print(vty, dist->list, 0, DISTRIBUTE_V6_IN, has_print); has_print = distribute_print(vty, dist->prefix, 1, DISTRIBUTE_V6_IN, has_print); } if (has_print) vty_out (vty, "%s", VTY_NEWLINE); else vty_out (vty, " 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) { vty_out (vty, " %s filtered by", dist->ifname); has_print = 0; has_print = distribute_print(vty, dist->list, 0, DISTRIBUTE_V4_IN, has_print); has_print = distribute_print(vty, dist->prefix, 1, DISTRIBUTE_V4_IN, has_print); has_print = distribute_print(vty, dist->list, 0, DISTRIBUTE_V6_IN, has_print); has_print = distribute_print(vty, dist->prefix, 1, DISTRIBUTE_V6_IN, has_print); if (has_print) vty_out (vty, "%s", VTY_NEWLINE); else vty_out(vty, " nothing%s", VTY_NEWLINE); } } return 0; } /* Configuration write function. */ int config_write_distribute (struct vty *vty) { unsigned int i; int j; int output, v6; 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; for (j=0; j < DISTRIBUTE_MAX; j++) if (dist->list[j]) { output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT; v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT; vty_out (vty, " %sdistribute-list %s %s %s%s", v6 ? "ipv6 " : "", dist->list[j], output ? "out" : "in", dist->ifname ? dist->ifname : "", VTY_NEWLINE); write++; } for (j=0; j < DISTRIBUTE_MAX; j++) if (dist->prefix[j]) { output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT; v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT; vty_out (vty, " %sdistribute-list prefix %s %s %s%s", v6 ? "ipv6 " : "", dist->prefix[j], output ? "out" : "in", 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, (int (*) (const void *, const void *)) distribute_cmp); /* install v4 */ if (node == RIP_NODE || node == BABEL_NODE) { install_element (node, &distribute_list_all_cmd); install_element (node, &no_distribute_list_all_cmd); install_element (node, &distribute_list_cmd); install_element (node, &no_distribute_list_cmd); install_element (node, &distribute_list_prefix_all_cmd); install_element (node, &no_distribute_list_prefix_all_cmd); install_element (node, &distribute_list_prefix_cmd); install_element (node, &no_distribute_list_prefix_cmd); } /* install v6 */ if (node == RIPNG_NODE || node == BABEL_NODE) { install_element (node, &ipv6_distribute_list_all_cmd); install_element (node, &no_ipv6_distribute_list_all_cmd); install_element (node, &ipv6_distribute_list_cmd); install_element (node, &no_ipv6_distribute_list_cmd); install_element (node, &ipv6_distribute_list_prefix_all_cmd); install_element (node, &no_ipv6_distribute_list_prefix_all_cmd); install_element (node, &ipv6_distribute_list_prefix_cmd); install_element (node, &no_ipv6_distribute_list_prefix_cmd); } /* install v4 syntax command for v6 only protocols. */ if (node == RIPNG_NODE) { install_element (node, &ipv6_as_v4_distribute_list_all_cmd); install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd); install_element (node, &ipv6_as_v4_distribute_list_cmd); install_element (node, &no_ipv6_as_v4_distribute_list_cmd); install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd); install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd); install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd); install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd); } } quagga-1.2.4/lib/distribute.h000066400000000000000000000036371325323223500160710ustar00rootroot00000000000000/* 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 #include #include "if.h" #include "filter.h" /* Disctirubte list types. */ enum distribute_type { DISTRIBUTE_V4_IN, DISTRIBUTE_V6_IN, DISTRIBUTE_V4_OUT, DISTRIBUTE_V6_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. */ extern void distribute_list_init (int); extern void distribute_list_reset (void); extern void distribute_list_add_hook (void (*) (struct distribute *)); extern void distribute_list_delete_hook (void (*) (struct distribute *)); extern struct distribute *distribute_lookup (const char *); extern int config_write_distribute (struct vty *); extern int config_show_distribute (struct vty *); extern enum filter_type distribute_apply_in (struct interface *, struct prefix *); extern enum filter_type distribute_apply_out (struct interface *, struct prefix *); #endif /* _ZEBRA_DISTRIBUTE_H */ quagga-1.2.4/lib/event_counter.c000066400000000000000000000053601325323223500165610ustar00rootroot00000000000000/* * Copyright (C) 2016 Christian Franke * * This file is part of Quagga. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Alternatively, you can use, redistribute and/or modify it under the * following terms: * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "event_counter.h" void event_counter_inc (struct event_counter *counter) { counter->count++; counter->last = time (NULL); } const char * event_counter_format (const struct event_counter *counter) { struct tm last_change_store; struct tm *last_change; char timebuf[sizeof ("Thu, 01 Jan 1970 00:00:00 +0000")]; static char rv[20 + sizeof (" last: ") + sizeof (timebuf)]; last_change = localtime_r (&counter->last, &last_change_store); if (!last_change || strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %T %z", last_change) == 0) { strncpy (timebuf, "???", sizeof (timebuf)); } snprintf (rv, sizeof (rv), "%5llu last: %s", counter->count, counter->last ? timebuf : "(never)"); return rv; } quagga-1.2.4/lib/event_counter.h000066400000000000000000000043311325323223500165630ustar00rootroot00000000000000/* * Copyright (C) 2016 Christian Franke * * This file is part of Quagga. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Alternatively, you can use, redistribute and/or modify it under the * following terms: * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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_EVENT_COUNTER_H #define _ZEBRA_EVENT_COUNTER_H struct event_counter { unsigned long long count; time_t last; }; void event_counter_inc (struct event_counter *counter); const char *event_counter_format (const struct event_counter *counter); #endif quagga-1.2.4/lib/fifo.h000066400000000000000000000043431325323223500146310ustar00rootroot00000000000000/* FIFO common header. Copyright (C) 2015 Kunihiro Ishiguro This file is part of Quagga. Quagga is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Quagga is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU 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 __LIB_FIFO_H__ #define __LIB_FIFO_H__ /* FIFO -- first in first out structure and macros. */ struct fifo { struct fifo *next; struct fifo *prev; u_int32_t count; }; #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 /* __LIB_FIFO_H__ */ quagga-1.2.4/lib/filter.c000066400000000000000000001555311325323223500151740ustar00rootroot00000000000000/* 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" #include "log.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) (const char *); /* Hook function which is executed when access_list is deleted. */ void (*delete_hook) (const char *); }; /* 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 */ static 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. */ static struct filter * filter_new (void) { return (struct filter *) XCALLOC (MTYPE_ACCESS_FILTER, sizeof (struct filter)); } static void filter_free (struct filter *filter) { XFREE (MTYPE_ACCESS_FILTER, filter); } /* Return string of filter_type. */ static const 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. */ static struct access_list * access_list_new (void) { return (struct access_list *) XCALLOC (MTYPE_ACCESS_LIST, sizeof (struct access_list)); } /* Free allocated access_list. */ static void access_list_free (struct access_list *access) { XFREE (MTYPE_ACCESS_LIST, access); } /* Delete access_list from access_master and free it. */ static 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. */ static struct access_list * access_list_insert (afi_t afi, const char *name) { unsigned 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 (point->name && 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, const 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 (access->name && strcmp (access->name, name) == 0) return access; for (access = master->str.head; access; access = access->next) if (access->name && 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. */ static struct access_list * access_list_get (afi_t afi, const 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) (const char *)) { 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) (const char *)) { 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. */ static 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->name); } /* 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. */ static void access_list_filter_delete (struct access_list *access, struct filter *filter) { struct access_master *master; /* transfer ownership of access->name to a local, to retain the name * to pass to a delete hook, while the access-list is deleted * * It is important that access-lists that are deleted, or are in process * of being deleted, are not visible via access_list_lookup. This is * because some (all?) users process the delete_hook callback the same * as an add - they simply refresh all their access_list name references * by looking up the name. * * If an access list can be looked up while being deleted, such users will * not remove an access-list, and will keep dangling references to * freed access lists. */ char *name = access->name; access->name = NULL; 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) (name); XFREE (MTYPE_ACCESS_LIST_STR, name); } /* 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 */ static 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; } static 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; } static int vty_access_list_remark_unset (struct vty *vty, afi_t afi, const 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; } static int filter_set_cisco (struct vty *vty, const char *name_str, const char *type_str, const char *addr_str, const char *addr_mask_str, const char *mask_str, const 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); } static int filter_set_zebra (struct vty *vty, const char *name_str, const char *type_str, afi_t afi, const 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; char *name; /* 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; /* transfer ownership of access->name to a local, to retain * a while longer, past access_list being freed */ name = access->name; access->name = NULL; /* Delete all filter from access-list. */ access_list_delete (access); /* Run hook function. */ if (master->delete_hook) (*master->delete_hook) (name); XFREE (MTYPE_ACCESS_LIST_STR, name); 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; access = access_list_get (AFI_IP, argv[0]); if (access->remark) { XFREE (MTYPE_TMP, access->remark); access->remark = NULL; } access->remark = argv_concat(argv, argc, 1); 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; char *name; /* 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; name = access->name; access->name = NULL; /* Delete all filter from access-list. */ access_list_delete (access); /* Run hook function. */ if (master->delete_hook) (*master->delete_hook) (name); XFREE (MTYPE_ACCESS_LIST_STR, name); 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; access = access_list_get (AFI_IP6, argv[0]); if (access->remark) { XFREE (MTYPE_TMP, access->remark); access->remark = NULL; } access->remark = argv_concat(argv, argc, 1); 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. */ static int filter_show (struct vty *vty, const 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; /* Print the name of the protocol */ if (zlog_default) vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol], VTY_NEWLINE); for (access = master->num.head; access; access = access->next) { if (!access->name || (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 (!access->name || (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); } static 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. */ static struct cmd_node access_node = { ACCESS_NODE, "", /* Access list has no interface. */ 1 }; static int config_write_access_ipv4 (struct vty *vty) { return config_write_access (vty, AFI_IP); } static void access_list_reset_ipv4 (void) { 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. */ static void access_list_init_ipv4 (void) { 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 static struct cmd_node access_ipv6_node = { ACCESS_IPV6_NODE, "", 1 }; static int config_write_access_ipv6 (struct vty *vty) { return config_write_access (vty, AFI_IP6); } static void access_list_reset_ipv6 (void) { 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); } static void access_list_init_ipv6 (void) { 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 */ } quagga-1.2.4/lib/filter.h000066400000000000000000000035341325323223500151740ustar00rootroot00000000000000/* * 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 direction. */ #define FILTER_IN 0 #define FILTER_OUT 1 #define FILTER_MAX 2 /* 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. */ extern void access_list_init (void); extern void access_list_reset (void); extern void access_list_add_hook (void (*func) (const char *)); extern void access_list_delete_hook (void (*func) (const char *)); extern struct access_list *access_list_lookup (afi_t, const char *); extern enum filter_type access_list_apply (struct access_list *, void *); #endif /* _ZEBRA_FILTER_H */ quagga-1.2.4/lib/getopt.c000066400000000000000000000730321325323223500152040ustar00rootroot00000000000000/* 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 #include #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; } } #ifdef REALLY_NEED_PLAIN_GETOPT 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 /* REALLY_NEED_PLAIN_GETOPT */ #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 */ quagga-1.2.4/lib/getopt.h000066400000000000000000000122151325323223500152050ustar00rootroot00000000000000/* 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 /* * The operating system may or may not provide getopt_long(), and if * so it may or may not be a version we are willing to use. Our * strategy is to declare getopt here, and then provide code unless * the supplied version is adequate. The difficult case is when a * declaration for getopt is provided, as our declaration must match. * * XXX Arguably this version should be named differently, and the * local names defined to refer to the system version when we choose * to use the system version. */ #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__ #if REALLY_NEED_PLAIN_GETOPT /* * getopt is defined in POSIX.2. Assume that if the system defines * getopt that it complies with POSIX.2. If not, an autoconf test * should be written to define NONPOSIX_GETOPT_DEFINITION. */ #ifndef NONPOSIX_GETOPT_DEFINITION extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* NONPOSIX_GETOPT_DEFINITION */ extern int getopt (void); #endif /* NONPOSIX_GETOPT_DEFINITION */ #endif 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__ */ #ifdef REALLY_NEED_PLAIN_GETOPT extern int getopt (); #endif /* REALLY_NEED_PLAIN_GETOPT */ extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* __STDC__ */ #ifdef __cplusplus } #endif #endif /* getopt.h */ quagga-1.2.4/lib/getopt1.c000066400000000000000000000106521325323223500152640ustar00rootroot00000000000000/* 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. */ #include #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 */ quagga-1.2.4/lib/gitversion.pl000066400000000000000000000023301325323223500162550ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; my $dir = shift; chdir $dir || die "$dir: $!\n"; my $gitdesc = `git describe --always --dirty || echo -- \"0-gUNKNOWN\"`; chomp $gitdesc; my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN"; printf STDERR "git suffix: %s\n", $gitsuffix; printf "#define GIT_SUFFIX \"%s\"\n", $gitsuffix; my $gitcommit = `git log -1 --format=\"%H\" || echo DEADBEEF`; chomp $gitcommit; open(BRANCHES, "git branch -a -v --abbrev=40|") || die "git branch: $!\n"; my @names = (); while () { chomp $_; if (/\s+(.*?)\s+$gitcommit/) { my $branch = $1; if ($branch =~ /^remotes\/(.*?)(\/.*)$/) { my $path = $2; my $url = `git config --get "remote.$1.url"`; chomp $url; $url =~ s/^(git:|https?:|git@)\/\/github\.com/github/i; $url =~ s/^(ssh|git):\/\/git\.sv\.gnu\.org\/srv\/git\//savannah:/i; $url =~ s/^(ssh|git):\/\/git\.savannah\.nongnu\.org\//savannah:/i; push @names, $url.$path; } else { push @names, 'local:'.$branch; } } } printf STDERR "git branches: %s\n", join(", ", @names); my $cr = "\\r\\n\\"; printf < #include "hash.h" #include "memory.h" /* Allocate a new hash. */ struct hash * hash_create_size (unsigned int size, unsigned int (*hash_key) (void *), int (*hash_cmp) (const void *, const void *)) { struct hash *hash; assert ((size & (size-1)) == 0); hash = XMALLOC (MTYPE_HASH, sizeof (struct hash)); hash->index = XCALLOC (MTYPE_HASH_INDEX, sizeof (struct hash_backet *) * size); hash->size = size; hash->no_expand = 0; 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) (void *), int (*hash_cmp) (const void *, const void *)) { return hash_create_size (HASH_INITIAL_SIZE, 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; } /* Expand hash if the chain length exceeds the threshold. */ static void hash_expand (struct hash *hash) { unsigned int i, new_size, losers; struct hash_backet *hb, *hbnext, **new_index; new_size = hash->size * 2; new_index = XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_backet *) * new_size); if (new_index == NULL) return; for (i = 0; i < hash->size; i++) for (hb = hash->index[i]; hb; hb = hbnext) { unsigned int h = hb->key & (new_size - 1); hbnext = hb->next; hb->next = new_index[h]; new_index[h] = hb; } /* Switch to new table */ XFREE(MTYPE_HASH_INDEX, hash->index); hash->size = new_size; hash->index = new_index; /* Ideally, new index should have chains half as long as the original. If expansion didn't help, then not worth expanding again, the problem is the hash function. */ losers = 0; for (i = 0; i < hash->size; i++) { unsigned int len = 0; for (hb = hash->index[i]; hb; hb = hb->next) { if (++len > HASH_THRESHOLD/2) ++losers; if (len >= HASH_THRESHOLD) hash->no_expand = 1; } } if (losers > hash->count / 2) hash->no_expand = 1; } /* 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) (void *)) { unsigned int key; unsigned int index; void *newdata; unsigned int len; struct hash_backet *backet; key = (*hash->hash_key) (data); index = key & (hash->size - 1); len = 0; for (backet = hash->index[index]; backet != NULL; backet = backet->next) { if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) return backet->data; ++len; } if (alloc_func) { newdata = (*alloc_func) (data); if (newdata == NULL) return NULL; if (len > HASH_THRESHOLD && !hash->no_expand) { hash_expand (hash); index = key & (hash->size - 1); } 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); } /* Simple Bernstein hash which is simple and fast for common case */ unsigned int string_hash_make (const char *str) { unsigned int hash = 0; while (*str) hash = (hash * 33) ^ (unsigned int) *str++; return hash; } /* 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 - 1); 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) { unsigned int i; struct hash_backet *hb; struct hash_backet *hbnext; for (i = 0; i < hash->size; i++) for (hb = hash->index[i]; hb; hb = hbnext) { /* get pointer to next hash backet here, in case (*func) * decides to delete hb by calling hash_release */ hbnext = hb->next; (*func) (hb, arg); } } /* Clean up hash. */ void hash_clean (struct hash *hash, void (*free_func) (void *)) { unsigned 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); } quagga-1.2.4/lib/hash.h000066400000000000000000000043141325323223500146270ustar00rootroot00000000000000/* 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 HASH_INITIAL_SIZE 256 /* initial number of backets. */ #define HASH_THRESHOLD 10 /* expand when backet. */ 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. Must be power of 2 */ unsigned int size; /* If expansion failed. */ int no_expand; /* Key make function. */ unsigned int (*hash_key) (void *); /* Data compare function. */ int (*hash_cmp) (const void *, const void *); /* Backet alloc. */ unsigned long count; }; extern struct hash *hash_create (unsigned int (*) (void *), int (*) (const void *, const void *)); extern struct hash *hash_create_size (unsigned int, unsigned int (*) (void *), int (*) (const void *, const void *)); extern void *hash_get (struct hash *, void *, void * (*) (void *)); extern void *hash_alloc_intern (void *); extern void *hash_lookup (struct hash *, void *); extern void *hash_release (struct hash *, void *); extern void hash_iterate (struct hash *, void (*) (struct hash_backet *, void *), void *); extern void hash_clean (struct hash *, void (*) (void *)); extern void hash_free (struct hash *); extern unsigned int string_hash_make (const char *); #endif /* _ZEBRA_HASH_H */ quagga-1.2.4/lib/if.c000066400000000000000000000715041325323223500143020ustar00rootroot00000000000000 /* * 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 "vrf.h" #include "if.h" #include "sockunion.h" #include "prefix.h" #include "memory.h" #include "table.h" #include "buffer.h" #include "str.h" #include "log.h" /* List of interfaces in only the default VRF */ 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 = {0,}; /* Compare interface names, returning an integer greater than, equal to, or * less than 0, (following the strcmp convention), according to the * relationship between ifp1 and ifp2. Interface names consist of an * alphabetic prefix and a numeric suffix. The primary sort key is * lexicographic by name, and then numeric by number. No number sorts * before all numbers. Examples: de0 < de1, de100 < fxp0 < xl0, devpty < * devpty0, de0 < del0 */ int if_cmp_func (struct interface *ifp1, struct interface *ifp2) { unsigned int l1, l2; long int x1, x2; char *p1, *p2; int res; p1 = ifp1->name; p2 = ifp2->name; while (*p1 && *p2) { /* look up to any number */ l1 = strcspn(p1, "0123456789"); l2 = strcspn(p2, "0123456789"); /* name lengths are different -> compare names */ if (l1 != l2) return (strcmp(p1, p2)); /* Note that this relies on all numbers being less than all letters, so * that de0 < del0. */ res = strncmp(p1, p2, l1); /* names are different -> compare them */ if (res) return res; /* with identical name part, go to numeric part */ p1 += l1; p2 += l1; if (!*p1) return -1; if (!*p2) return 1; x1 = strtol(p1, &p1, 10); x2 = strtol(p2, &p2, 10); /* let's compare numbers now */ if (x1 < x2) return -1; if (x1 > x2) return 1; /* numbers were equal, lets do it again.. (it happens with name like "eth123.456:789") */ } if (*p1) return 1; if (*p2) return -1; return 0; } /* Create new interface structure. */ struct interface * if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id) { struct interface *ifp; struct list *intf_list = vrf_iflist_get (vrf_id); ifp = XCALLOC (MTYPE_IF, sizeof (struct interface)); ifp->ifindex = IFINDEX_INTERNAL; assert (name); assert (namelen <= INTERFACE_NAMSIZ); /* Need space for '\0' at end. */ strncpy (ifp->name, name, namelen); ifp->name[namelen] = '\0'; ifp->vrf_id = vrf_id; if (if_lookup_by_name_vrf (ifp->name, vrf_id) == NULL) listnode_add_sort (intf_list, ifp); else zlog_err("if_create(%s): corruption detected -- interface with this " "name exists already in VRF %u!", ifp->name, vrf_id); 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; } struct interface * if_create (const char *name, int namelen) { return if_create_vrf (name, namelen, VRF_DEFAULT); } /* Delete interface structure. */ void if_delete_retain (struct interface *ifp) { if (if_master.if_delete_hook) (*if_master.if_delete_hook) (ifp); /* Free connected address list */ list_delete_all_node (ifp->connected); } /* Delete and free interface structure. */ void if_delete (struct interface *ifp) { listnode_delete (vrf_iflist (ifp->vrf_id), ifp); if_delete_retain(ifp); list_free (ifp->connected); if_link_params_free (ifp); 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_vrf (ifindex_t ifindex, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { if (ifp->ifindex == ifindex) return ifp; } return NULL; } struct interface * if_lookup_by_index (ifindex_t ifindex) { return if_lookup_by_index_vrf (ifindex, VRF_DEFAULT); } const char * ifindex2ifname_vrf (ifindex_t ifindex, vrf_id_t vrf_id) { struct interface *ifp; return ((ifp = if_lookup_by_index_vrf (ifindex, vrf_id)) != NULL) ? ifp->name : "unknown"; } const char * ifindex2ifname (ifindex_t ifindex) { return ifindex2ifname_vrf (ifindex, VRF_DEFAULT); } ifindex_t ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id) { struct interface *ifp; return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp->ifindex : IFINDEX_INTERNAL; } ifindex_t ifname2ifindex (const char *name) { return ifname2ifindex_vrf (name, VRF_DEFAULT); } /* Interface existance check by interface name. */ struct interface * if_lookup_by_name_vrf (const char *name, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; if (name) for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { if (strcmp(name, ifp->name) == 0) return ifp; } return NULL; } struct interface * if_lookup_by_name (const char *name) { return if_lookup_by_name_vrf (name, VRF_DEFAULT); } struct interface * if_lookup_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; if (namelen > INTERFACE_NAMSIZ) return NULL; for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { if (!memcmp(name, ifp->name, namelen) && (ifp->name[namelen] == '\0')) return ifp; } return NULL; } struct interface * if_lookup_by_name_len(const char *name, size_t namelen) { return if_lookup_by_name_len_vrf (name, namelen, VRF_DEFAULT); } /* Lookup interface by IPv4 address. */ struct interface * if_lookup_exact_address_vrf (struct in_addr src, vrf_id_t vrf_id) { struct listnode *node; struct listnode *cnode; struct interface *ifp; struct prefix *p; struct connected *c; for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) { p = c->address; if (p && p->family == AF_INET) { if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) return ifp; } } } return NULL; } struct interface * if_lookup_exact_address (struct in_addr src) { return if_lookup_exact_address_vrf (src, VRF_DEFAULT); } /* Lookup interface by IPv4 address. */ struct interface * if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id) { struct listnode *node; struct prefix addr; int bestlen = 0; struct listnode *cnode; struct interface *ifp; struct connected *c; struct interface *match; addr.family = AF_INET; addr.u.prefix4 = src; addr.prefixlen = IPV4_MAX_BITLEN; match = NULL; for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) { if (c->address && (c->address->family == AF_INET) && prefix_match(CONNECTED_PREFIX(c), &addr) && (c->address->prefixlen > bestlen)) { bestlen = c->address->prefixlen; match = ifp; } } } return match; } struct interface * if_lookup_address (struct in_addr src) { return if_lookup_address_vrf (src, VRF_DEFAULT); } /* Lookup interface by prefix */ struct interface * if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id) { struct listnode *node; struct listnode *cnode; struct interface *ifp; struct connected *c; for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) { if (prefix_cmp(c->address, prefix) == 0) { return ifp; } } } return NULL; } struct interface * if_lookup_prefix (struct prefix *prefix) { return if_lookup_prefix_vrf (prefix, VRF_DEFAULT); } /* Get interface by name if given name interface doesn't exist create one. */ struct interface * if_get_by_name_vrf (const char *name, vrf_id_t vrf_id) { struct interface *ifp; return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp : if_create_vrf (name, strlen(name), vrf_id); } struct interface * if_get_by_name (const char *name) { return if_get_by_name_vrf (name, VRF_DEFAULT); } struct interface * if_get_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id) { struct interface *ifp; return ((ifp = if_lookup_by_name_len_vrf (name, namelen, vrf_id)) != NULL) ? \ ifp : if_create_vrf (name, namelen, vrf_id); } struct interface * if_get_by_name_len (const char *name, size_t namelen) { return if_get_by_name_len_vrf (name, namelen, VRF_DEFAULT); } /* Does interface up ? */ int if_is_up (struct interface *ifp) { return ifp->flags & IFF_UP; } /* Is interface running? */ int if_is_running (struct interface *ifp) { return ifp->flags & IFF_RUNNING; } /* Is the interface operative, eg. either UP & RUNNING or UP & !ZEBRA_INTERFACE_LINK_DETECTION */ int if_is_operative (struct interface *ifp) { return ((ifp->flags & IFF_UP) && (ifp->flags & IFF_RUNNING || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))); } /* Is this loopback interface ? */ int if_is_loopback (struct interface *ifp) { /* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M * but Y on platform N? */ return (ifp->flags & (IFF_LOOPBACK|IFF_NOXMIT|IFF_VIRTUAL)); } /* 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 (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"); IFF_OUT_LOG (IFF_NOXMIT, "NOXMIT"); IFF_OUT_LOG (IFF_NORTEXCH, "NORTEXCH"); IFF_OUT_LOG (IFF_VIRTUAL, "VIRTUAL"); IFF_OUT_LOG (IFF_IPV4, "IPv4"); IFF_OUT_LOG (IFF_IPV6, "IPv6"); strlcat (logbuf, ">", BUFSIZ); return logbuf; #undef IFF_OUT_LOG } /* For debugging */ static void if_dump (const struct interface *ifp) { struct listnode *node; struct connected *c __attribute__((unused)); for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c)) zlog_info ("Interface %s vrf %u index %d metric %d mtu %d " #ifdef HAVE_IPV6 "mtu6 %d " #endif /* HAVE_IPV6 */ "%s", ifp->name, ifp->vrf_id, ifp->ifindex, ifp->metric, ifp->mtu, #ifdef HAVE_IPV6 ifp->mtu6, #endif /* HAVE_IPV6 */ if_flag_dump (ifp->flags)); } /* Interface printing for all interface. */ void if_dump_all (void) { struct list *intf_list; struct listnode *node; void *p; vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((intf_list = vrf_iter2iflist (iter)) != NULL) for (ALL_LIST_ELEMENTS_RO (intf_list, node, p)) if_dump (p); } DEFUN (interface_desc, interface_desc_cmd, "description .LINE", "Interface specific description\n" "Characters describing this interface\n") { struct interface *ifp; if (argc == 0) return CMD_SUCCESS; ifp = vty->index; if (ifp->desc) XFREE (MTYPE_TMP, ifp->desc); ifp->desc = argv_concat(argv, argc, 0); 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 (MTYPE_TMP, ifp->desc); ifp->desc = NULL; return CMD_SUCCESS; } #ifdef SUNOS_5 /* Need to handle upgrade from SUNWzebra to Quagga. SUNWzebra created * a seperate struct interface for each logical interface, so config * file may be full of 'interface fooX:Y'. Solaris however does not * expose logical interfaces via PF_ROUTE, so trying to track logical * interfaces can be fruitless, for that reason Quagga only tracks * the primary IP interface. * * We try accomodate SUNWzebra by: * - looking up the interface name, to see whether it exists, if so * its useable * - for protocol daemons, this could only because zebra told us of * the interface * - for zebra, only because it learnt from kernel * - if not: * - search the name to see if it contains a sub-ipif / logical interface * seperator, the ':' char. If it does: * - text up to that char must be the primary name - get that name. * if not: * - no idea, just get the name in its entirety. */ static struct interface * if_sunwzebra_get (const char *name, size_t nlen, vrf_id_t vrf_id) { struct interface *ifp; size_t seppos = 0; if ( (ifp = if_lookup_by_name_len_vrf (name, nlen, vrf_id)) != NULL) return ifp; /* hunt the primary interface name... */ while (seppos < nlen && name[seppos] != ':') seppos++; /* Wont catch seperator as last char, e.g. 'foo0:' but thats invalid */ if (seppos < nlen) return if_get_by_name_len_vrf (name, seppos, vrf_id); else return if_get_by_name_len_vrf (name, nlen, vrf_id); } #endif /* SUNOS_5 */ DEFUN (interface, interface_cmd, "interface IFNAME", "Select an interface to configure\n" "Interface's name\n") { struct interface *ifp; size_t sl; vrf_id_t vrf_id = VRF_DEFAULT; if ((sl = strlen(argv[0])) > INTERFACE_NAMSIZ) { vty_out (vty, "%% Interface name %s is invalid: length exceeds " "%d characters%s", argv[0], INTERFACE_NAMSIZ, VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); #ifdef SUNOS_5 ifp = if_sunwzebra_get (argv[0], sl, vrf_id); #else ifp = if_get_by_name_len_vrf (argv[0], sl, vrf_id); #endif /* SUNOS_5 */ vty->index = ifp; vty->node = INTERFACE_NODE; return CMD_SUCCESS; } ALIAS (interface, interface_vrf_cmd, "interface IFNAME " VRF_CMD_STR, "Select an interface to configure\n" "Interface's name\n" VRF_CMD_HELP_STR) DEFUN_NOSH (no_interface, no_interface_cmd, "no interface IFNAME", NO_STR "Delete a pseudo interface's configuration\n" "Interface's name\n") { // deleting interface struct interface *ifp; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); ifp = if_lookup_by_name_vrf (argv[0], vrf_id); if (ifp == NULL) { vty_out (vty, "%% Interface %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; } if_delete(ifp); return CMD_SUCCESS; } ALIAS (no_interface, no_interface_vrf_cmd, "no interface IFNAME " VRF_CMD_STR, NO_STR "Delete a pseudo interface's configuration\n" "Interface's name\n" VRF_CMD_HELP_STR) /* For debug purpose. */ DEFUN (show_address, show_address_cmd, "show address", SHOW_STR "address\n") { struct listnode *node; struct listnode *node2; struct interface *ifp; struct connected *ifc; struct prefix *p; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc)) { 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; } ALIAS (show_address, show_address_vrf_cmd, "show address " VRF_CMD_STR, SHOW_STR "address\n" VRF_CMD_HELP_STR) DEFUN (show_address_vrf_all, show_address_vrf_all_cmd, "show address " VRF_ALL_CMD_STR, SHOW_STR "address\n" VRF_ALL_CMD_HELP_STR) { struct list *intf_list; struct listnode *node; struct listnode *node2; struct interface *ifp; struct connected *ifc; struct prefix *p; vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { intf_list = vrf_iter2iflist (iter); if (!intf_list || !listcount (intf_list)) continue; vty_out (vty, "%sVRF %u%s%s", VTY_NEWLINE, vrf_iter2id (iter), VTY_NEWLINE, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (intf_list, node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc)) { 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 (void) { return XCALLOC (MTYPE_CONNECTED, sizeof (struct connected)); } /* 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) XFREE (MTYPE_CONNECTED_LABEL, connected->label); XFREE (MTYPE_CONNECTED, connected); } /* Print if_addr structure. */ static void __attribute__ ((unused)) 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 vrf %u %s %s/%d ", str, ifp->name, ifp->vrf_id, 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, "%s", logbuf); } /* If two connected address has same prefix return 1. */ static 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 = listgetdata (node); next = node->next; if (connected_same_prefix (ifc->address, p)) { listnode_delete (ifp->connected, ifc); return ifc; } } return NULL; } /* Find the IPv4 address on our side that will be used when packets are sent to dst. */ struct connected * connected_lookup_address (struct interface *ifp, struct in_addr dst) { struct prefix addr; struct listnode *cnode; struct connected *c; struct connected *match; addr.family = AF_INET; addr.u.prefix4 = dst; addr.prefixlen = IPV4_MAX_BITLEN; match = NULL; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) { if (c->address && (c->address->family == AF_INET) && prefix_match(CONNECTED_PREFIX(c), &addr) && (!match || (c->address->prefixlen > match->address->prefixlen))) match = c; } return match; } struct connected * connected_add_by_prefix (struct interface *ifp, struct prefix *p, struct prefix *destination) { struct connected *ifc; /* Allocate new connected address. */ ifc = connected_new (); ifc->ifp = ifp; /* Fetch interface address */ ifc->address = prefix_new(); memcpy (ifc->address, p, sizeof(struct prefix)); /* Fetch dest address */ if (destination) { ifc->destination = prefix_new(); memcpy (ifc->destination, destination, sizeof(struct prefix)); } /* Add connected address to the interface. */ listnode_add (ifp->connected, ifc); return ifc; } #ifndef HAVE_IF_NAMETOINDEX ifindex_t if_nametoindex (const char *name) { struct interface *ifp; return ((ifp = if_lookup_by_name_len(name, strnlen(name, IFNAMSIZ))) != NULL) ? ifp->ifindex : 0; } #endif #ifndef HAVE_IF_INDEXTONAME char * if_indextoname (ifindex_t ifindex, char *name) { struct interface *ifp; if (!(ifp = if_lookup_by_index(ifindex))) return NULL; strncpy (name, ifp->name, IFNAMSIZ); return ifp->name; } #endif #if 0 /* this route_table of struct connected's is unused * however, it would be good to use a route_table rather than * a list.. */ /* 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; */ static 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; } static 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. */ static struct interface * ifaddr_ipv4_lookup (struct in_addr *addr, ifindex_t ifindex) { struct prefix_ipv4 p; struct route_node *rn; struct interface *ifp; 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 return if_lookup_by_index(ifindex); } #endif /* ifaddr_ipv4_table */ /* Initialize interface list. */ void if_init (vrf_id_t vrf_id, struct list **intf_list) { *intf_list = list_new (); #if 0 ifaddr_ipv4_table = route_table_init (); #endif /* ifaddr_ipv4_table */ (*intf_list)->cmp = (int (*)(void *, void *))if_cmp_func; if (vrf_id == VRF_DEFAULT) iflist = *intf_list; } void if_terminate (vrf_id_t vrf_id, struct list **intf_list) { for (;;) { struct interface *ifp; ifp = listnode_head (*intf_list); if (ifp == NULL) break; if_delete (ifp); } list_delete (*intf_list); *intf_list = NULL; if (vrf_id == VRF_DEFAULT) iflist = NULL; } const char * if_link_type_str (enum zebra_link_type llt) { switch (llt) { #define llts(T,S) case (T): return (S) llts(ZEBRA_LLT_UNKNOWN, "Unknown"); llts(ZEBRA_LLT_ETHER, "Ethernet"); llts(ZEBRA_LLT_EETHER, "Experimental Ethernet"); llts(ZEBRA_LLT_AX25, "AX.25 Level 2"); llts(ZEBRA_LLT_PRONET, "PROnet token ring"); llts(ZEBRA_LLT_IEEE802, "IEEE 802.2 Ethernet/TR/TB"); llts(ZEBRA_LLT_ARCNET, "ARCnet"); llts(ZEBRA_LLT_APPLETLK, "AppleTalk"); llts(ZEBRA_LLT_DLCI, "Frame Relay DLCI"); llts(ZEBRA_LLT_ATM, "ATM"); llts(ZEBRA_LLT_METRICOM, "Metricom STRIP"); llts(ZEBRA_LLT_IEEE1394, "IEEE 1394 IPv4"); llts(ZEBRA_LLT_EUI64, "EUI-64"); llts(ZEBRA_LLT_INFINIBAND, "InfiniBand"); llts(ZEBRA_LLT_SLIP, "SLIP"); llts(ZEBRA_LLT_CSLIP, "Compressed SLIP"); llts(ZEBRA_LLT_SLIP6, "SLIPv6"); llts(ZEBRA_LLT_CSLIP6, "Compressed SLIPv6"); llts(ZEBRA_LLT_ROSE, "ROSE packet radio"); llts(ZEBRA_LLT_X25, "CCITT X.25"); llts(ZEBRA_LLT_PPP, "PPP"); llts(ZEBRA_LLT_CHDLC, "Cisco HDLC"); llts(ZEBRA_LLT_RAWHDLC, "Raw HDLC"); llts(ZEBRA_LLT_LAPB, "LAPB"); llts(ZEBRA_LLT_IPIP, "IPIP Tunnel"); llts(ZEBRA_LLT_IPIP6, "IPIP6 Tunnel"); llts(ZEBRA_LLT_FRAD, "FRAD"); llts(ZEBRA_LLT_SKIP, "SKIP vif"); llts(ZEBRA_LLT_LOOPBACK, "Loopback"); llts(ZEBRA_LLT_LOCALTLK, "Localtalk"); llts(ZEBRA_LLT_FDDI, "FDDI"); llts(ZEBRA_LLT_SIT, "IPv6-in-IPv4 SIT"); llts(ZEBRA_LLT_IPDDP, "IP-in-DDP tunnel"); llts(ZEBRA_LLT_IPGRE, "GRE over IP"); llts(ZEBRA_LLT_PIMREG, "PIMSM registration"); llts(ZEBRA_LLT_HIPPI, "HiPPI"); llts(ZEBRA_LLT_IRDA, "IrDA"); llts(ZEBRA_LLT_FCPP, "Fibre-Channel PtP"); llts(ZEBRA_LLT_FCAL, "Fibre-Channel Arbitrated Loop"); llts(ZEBRA_LLT_FCPL, "Fibre-Channel Public Loop"); llts(ZEBRA_LLT_FCFABRIC, "Fibre-Channel Fabric"); llts(ZEBRA_LLT_IEEE802_TR, "IEEE 802.2 Token Ring"); llts(ZEBRA_LLT_IEEE80211, "IEEE 802.11"); llts(ZEBRA_LLT_IEEE80211_RADIOTAP, "IEEE 802.11 Radiotap"); llts(ZEBRA_LLT_IEEE802154, "IEEE 802.15.4"); llts(ZEBRA_LLT_IEEE802154_PHY, "IEEE 802.15.4 Phy"); default: zlog_warn ("Unknown value %d", llt); return "Unknown type!"; #undef llts } return NULL; } struct if_link_params * if_link_params_get (struct interface *ifp) { int i; if (ifp->link_params != NULL) return ifp->link_params; struct if_link_params *iflp = XCALLOC(MTYPE_IF_LINK_PARAMS, sizeof (struct if_link_params)); if (iflp == NULL) return NULL; /* Set TE metric == standard metric */ iflp->te_metric = ifp->metric; /* Compute default bandwidth based on interface */ int bw = (float)((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH) * TE_KILO_BIT / TE_BYTE); /* Set Max, Reservable and Unreserved Bandwidth */ iflp->max_bw = bw; iflp->max_rsv_bw = bw; for (i = 0; i < MAX_CLASS_TYPE; i++) iflp->unrsv_bw[i] = bw; /* Update Link parameters status */ iflp->lp_status = LP_TE | LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW; /* Finally attach newly created Link Parameters */ ifp->link_params = iflp; return iflp; } void if_link_params_free (struct interface *ifp) { if (ifp->link_params == NULL) return; XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params); ifp->link_params = NULL; } quagga-1.2.4/lib/if.h000066400000000000000000000400601325323223500143000ustar00rootroot00000000000000/* 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 "zebra.h" #include "linklist.h" /* Interface link-layer type, if known. Derived from: * * net/if_arp.h on various platforms - Linux especially. * http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml * * Some of the more obviously defunct technologies left out. */ enum zebra_link_type { ZEBRA_LLT_UNKNOWN = 0, ZEBRA_LLT_ETHER, ZEBRA_LLT_EETHER, ZEBRA_LLT_AX25, ZEBRA_LLT_PRONET, ZEBRA_LLT_IEEE802, ZEBRA_LLT_ARCNET, ZEBRA_LLT_APPLETLK, ZEBRA_LLT_DLCI, ZEBRA_LLT_ATM, ZEBRA_LLT_METRICOM, ZEBRA_LLT_IEEE1394, ZEBRA_LLT_EUI64, ZEBRA_LLT_INFINIBAND, ZEBRA_LLT_SLIP, ZEBRA_LLT_CSLIP, ZEBRA_LLT_SLIP6, ZEBRA_LLT_CSLIP6, ZEBRA_LLT_RSRVD, ZEBRA_LLT_ADAPT, ZEBRA_LLT_ROSE, ZEBRA_LLT_X25, ZEBRA_LLT_PPP, ZEBRA_LLT_CHDLC, ZEBRA_LLT_LAPB, ZEBRA_LLT_RAWHDLC, ZEBRA_LLT_IPIP, ZEBRA_LLT_IPIP6, ZEBRA_LLT_FRAD, ZEBRA_LLT_SKIP, ZEBRA_LLT_LOOPBACK, ZEBRA_LLT_LOCALTLK, ZEBRA_LLT_FDDI, ZEBRA_LLT_SIT, ZEBRA_LLT_IPDDP, ZEBRA_LLT_IPGRE, ZEBRA_LLT_IP6GRE, ZEBRA_LLT_PIMREG, ZEBRA_LLT_HIPPI, ZEBRA_LLT_ECONET, ZEBRA_LLT_IRDA, ZEBRA_LLT_FCPP, ZEBRA_LLT_FCAL, ZEBRA_LLT_FCPL, ZEBRA_LLT_FCFABRIC, ZEBRA_LLT_IEEE802_TR, ZEBRA_LLT_IEEE80211, ZEBRA_LLT_IEEE80211_RADIOTAP, ZEBRA_LLT_IEEE802154, ZEBRA_LLT_IEEE802154_PHY, }; /* 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 typedef signed int ifindex_t; #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 */ /* Here are "non-official" architectural constants. */ #define TE_EXT_MASK 0x0FFFFFFF #define TE_EXT_ANORMAL 0x80000000 #define LOSS_PRECISION 0.000003 #define TE_KILO_BIT 1000 #define TE_BYTE 8 #define DEFAULT_BANDWIDTH 10000 #define MAX_CLASS_TYPE 8 #define MAX_PKT_LOSS 50.331642 /* Link Parameters Status: 0: unset, 1: set, */ #define LP_UNSET 0x0000 #define LP_TE 0x0001 #define LP_MAX_BW 0x0002 #define LP_MAX_RSV_BW 0x0004 #define LP_UNRSV_BW 0x0008 #define LP_ADM_GRP 0x0010 #define LP_RMT_AS 0x0020 #define LP_DELAY 0x0040 #define LP_MM_DELAY 0x0080 #define LP_DELAY_VAR 0x0100 #define LP_PKT_LOSS 0x0200 #define LP_RES_BW 0x0400 #define LP_AVA_BW 0x0800 #define LP_USE_BW 0x1000 #define IS_PARAM_UNSET(lp, st) !(lp->lp_status & st) #define IS_PARAM_SET(lp, st) (lp->lp_status & st) #define IS_LINK_PARAMS_SET(lp) (lp->lp_status != LP_UNSET) #define SET_PARAM(lp, st) (lp->lp_status) |= (st) #define UNSET_PARAM(lp, st) (lp->lp_status) &= ~(st) #define RESET_LINK_PARAM(lp) (lp->lp_status = LP_UNSET) /* Link Parameters for Traffic Engineering */ struct if_link_params { u_int32_t lp_status; /* Status of Link Parameters: */ u_int32_t te_metric; /* Traffic Engineering metric */ float max_bw; /* Maximum Bandwidth */ float max_rsv_bw; /* Maximum Reservable Bandwidth */ float unrsv_bw[MAX_CLASS_TYPE]; /* Unreserved Bandwidth per Class Type (8) */ u_int32_t admin_grp; /* Administrative group */ u_int32_t rmt_as; /* Remote AS number */ struct in_addr rmt_ip; /* Remote IP address */ u_int32_t av_delay; /* Link Average Delay */ u_int32_t min_delay; /* Link Min Delay */ u_int32_t max_delay; /* Link Max Delay */ u_int32_t delay_var; /* Link Delay Variation */ float pkt_loss; /* Link Packet Loss */ float res_bw; /* Residual Bandwidth */ float ava_bw; /* Available Bandwidth */ float use_bw; /* Utilized Bandwidth */ }; #define INTERFACE_LINK_PARAMS_SIZE sizeof(struct if_link_params) #define HAS_LINK_PARAMS(ifp) ((ifp)->link_params != NULL) /* Interface structure */ struct interface { /* Interface name. This should probably never be changed after the interface is created, because the configuration info for this interface is associated with this structure. For that reason, the interface should also never be deleted (to avoid losing configuration info). To delete, just set ifindex to IFINDEX_INTERNAL to indicate that the interface does not exist in the kernel. */ char name[INTERFACE_NAMSIZ + 1]; /* Interface index (should be IFINDEX_INTERNAL for non-kernel or deleted interfaces). */ ifindex_t ifindex; #define IFINDEX_INTERNAL 0 /* Zebra internal interface status */ u_char status; #define ZEBRA_INTERFACE_ACTIVE (1 << 0) #define ZEBRA_INTERFACE_SUB (1 << 1) #define ZEBRA_INTERFACE_LINKDETECTION (1 << 2) /* Interface flags. */ uint64_t flags; /* Interface metric */ int metric; /* Interface MTU. */ unsigned int mtu; /* IPv4 MTU */ unsigned int mtu6; /* IPv6 MTU - probably, but not neccessarily same as mtu */ /* Link-layer information and hardware address */ enum zebra_link_type ll_type; u_char hw_addr[INTERFACE_HWADDR_MAX]; int hw_addr_len; /* interface bandwidth, kbits */ unsigned int bandwidth; /* Link parameters for Traffic Engineering */ struct if_link_params *link_params; /* description of the interface. */ char *desc; /* Distribute list. */ void *distribute_in; void *distribute_out; /* Connected address list. */ struct 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 */ vrf_id_t vrf_id; }; /* 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) #define ZEBRA_IFC_QUEUED (1 << 2) /* The ZEBRA_IFC_REAL flag should be set if and only if this address exists in the kernel and is actually usable. (A case where it exists but is not yet usable would be IPv6 with DAD) The ZEBRA_IFC_CONFIGURED flag should be set if and only if this address was configured by the user from inside quagga. The ZEBRA_IFC_QUEUED flag should be set if and only if the address exists in the kernel. It may and should be set although the address might not be usable yet. (compare with ZEBRA_IFC_REAL) */ /* Flags for connected address. */ u_char flags; #define ZEBRA_IFA_SECONDARY (1 << 0) #define ZEBRA_IFA_PEER (1 << 1) #define ZEBRA_IFA_UNNUMBERED (1 << 2) /* N.B. the ZEBRA_IFA_PEER flag should be set if and only if a peer address has been configured. If this flag is set, the destination field must contain the peer address. Otherwise, if this flag is not set, the destination address will either contain a broadcast address or be NULL. */ /* Address of connected network. */ struct prefix *address; /* Peer or Broadcast address, depending on whether ZEBRA_IFA_PEER is set. Note: destination may be NULL if ZEBRA_IFA_PEER is not set. */ struct prefix *destination; /* Label for Linux 2.2.X and upper. */ char *label; }; /* Does the destination field contain a peer address? */ #define CONNECTED_PEER(C) CHECK_FLAG((C)->flags, ZEBRA_IFA_PEER) /* Prefix to insert into the RIB */ #define CONNECTED_PREFIX(C) \ (CONNECTED_PEER(C) ? (C)->destination : (C)->address) /* Identifying address. We guess that if there's a peer address, but the local address is in the same prefix, then the local address may be unique. */ #define CONNECTED_ID(C) \ ((CONNECTED_PEER(C) && !prefix_match((C)->destination, (C)->address)) ?\ (C)->destination : (C)->address) /* 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 */ #ifndef IFF_NOXMIT #define IFF_NOXMIT 0x0 #endif /* IFF_NOXMIT */ #ifndef IFF_NORTEXCH #define IFF_NORTEXCH 0x0 #endif /* IFF_NORTEXCH */ #ifndef IFF_IPV4 #define IFF_IPV4 0x0 #endif /* IFF_IPV4 */ #ifndef IFF_IPV6 #define IFF_IPV6 0x0 #endif /* IFF_IPV6 */ #ifndef IFF_VIRTUAL #define IFF_VIRTUAL 0x0 #endif /* IFF_VIRTUAL */ /* Prototypes. */ extern int if_cmp_func (struct interface *, struct interface *); extern struct interface *if_create (const char *name, int namelen); extern struct interface *if_lookup_by_index (ifindex_t); extern struct interface *if_lookup_exact_address (struct in_addr); extern struct interface *if_lookup_address (struct in_addr); extern struct interface *if_lookup_prefix (struct prefix *prefix); extern struct interface *if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id); extern struct interface *if_lookup_by_index_vrf (ifindex_t, vrf_id_t vrf_id); extern struct interface *if_lookup_exact_address_vrf (struct in_addr, vrf_id_t vrf_id); extern struct interface *if_lookup_address_vrf (struct in_addr, vrf_id_t vrf_id); extern struct interface *if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id); /* These 2 functions are to be used when the ifname argument is terminated by a '\0' character: */ extern struct interface *if_lookup_by_name (const char *ifname); extern struct interface *if_get_by_name (const char *ifname); extern struct interface *if_lookup_by_name_vrf (const char *ifname, vrf_id_t vrf_id); extern struct interface *if_get_by_name_vrf (const char *ifname, vrf_id_t vrf_id); /* For these 2 functions, the namelen argument should be the precise length of the ifname string (not counting any optional trailing '\0' character). In most cases, strnlen should be used to calculate the namelen value. */ extern struct interface *if_lookup_by_name_len(const char *ifname, size_t namelen); extern struct interface *if_get_by_name_len(const char *ifname,size_t namelen); extern struct interface *if_lookup_by_name_len_vrf(const char *ifname, size_t namelen, vrf_id_t vrf_id); extern struct interface *if_get_by_name_len_vrf(const char *ifname, size_t namelen, vrf_id_t vrf_id); /* Delete the interface, but do not free the structure, and leave it in the interface list. It is often advisable to leave the pseudo interface structure because there may be configuration information attached. */ extern void if_delete_retain (struct interface *); /* Delete and free the interface structure: calls if_delete_retain and then deletes it from the interface list and frees the structure. */ extern void if_delete (struct interface *); extern int if_is_up (struct interface *); extern int if_is_running (struct interface *); extern int if_is_operative (struct interface *); extern int if_is_loopback (struct interface *); extern int if_is_broadcast (struct interface *); extern int if_is_pointopoint (struct interface *); extern int if_is_multicast (struct interface *); extern void if_add_hook (int, int (*)(struct interface *)); extern void if_init (vrf_id_t, struct list **); extern void if_terminate (vrf_id_t, struct list **); extern void if_dump_all (void); extern const char *if_flag_dump(unsigned long); extern const char *if_link_type_str (enum zebra_link_type); /* Please use ifindex2ifname instead of if_indextoname where possible; ifindex2ifname uses internal interface info, whereas if_indextoname must make a system call. */ extern const char *ifindex2ifname (ifindex_t); extern const char *ifindex2ifname_vrf (ifindex_t, vrf_id_t vrf_id); /* Please use ifname2ifindex instead of if_nametoindex where possible; ifname2ifindex uses internal interface info, whereas if_nametoindex must make a system call. */ extern ifindex_t ifname2ifindex(const char *ifname); extern ifindex_t ifname2ifindex_vrf(const char *ifname, vrf_id_t vrf_id); /* Connected address functions. */ extern struct connected *connected_new (void); extern void connected_free (struct connected *); extern void connected_add (struct interface *, struct connected *); extern struct connected *connected_add_by_prefix (struct interface *, struct prefix *, struct prefix *); extern struct connected *connected_delete_by_prefix (struct interface *, struct prefix *); extern struct connected *connected_lookup_address (struct interface *, struct in_addr); #ifndef HAVE_IF_NAMETOINDEX extern ifindex_t if_nametoindex (const char *); #endif #ifndef HAVE_IF_INDEXTONAME extern char *if_indextoname (ifindex_t, char *); #endif /* link parameters */ struct if_link_params *if_link_params_get (struct interface *); void if_link_params_free (struct interface *); /* Exported variables. */ extern struct 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 no_interface_cmd; extern struct cmd_element interface_vrf_cmd; extern struct cmd_element no_interface_vrf_cmd; extern struct cmd_element interface_pseudo_cmd; extern struct cmd_element no_interface_pseudo_cmd; extern struct cmd_element show_address_cmd; extern struct cmd_element show_address_vrf_cmd; extern struct cmd_element show_address_vrf_all_cmd; #endif /* _ZEBRA_IF_H */ quagga-1.2.4/lib/if_rmap.c000066400000000000000000000170411325323223500153150ustar00rootroot00000000000000/* 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 "if_rmap.h" struct hash *ifrmaphash; /* Hook functions. */ static void (*if_rmap_add_hook) (struct if_rmap *) = NULL; static void (*if_rmap_delete_hook) (struct if_rmap *) = NULL; static struct if_rmap * if_rmap_new (void) { struct if_rmap *new; new = XCALLOC (MTYPE_IF_RMAP, sizeof (struct if_rmap)); return new; } static void if_rmap_free (struct if_rmap *if_rmap) { if (if_rmap->ifname) XFREE (MTYPE_IF_RMAP_NAME, if_rmap->ifname); if (if_rmap->routemap[IF_RMAP_IN]) XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); if (if_rmap->routemap[IF_RMAP_OUT]) XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); XFREE (MTYPE_IF_RMAP, if_rmap); } struct if_rmap * if_rmap_lookup (const char *ifname) { struct if_rmap key; struct if_rmap *if_rmap; /* temporary copy */ key.ifname = (char *)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; } static void * if_rmap_hash_alloc (void *arg) { struct if_rmap *ifarg = arg; struct if_rmap *if_rmap; if_rmap = if_rmap_new (); if_rmap->ifname = XSTRDUP (MTYPE_IF_RMAP_NAME, ifarg->ifname); return if_rmap; } static struct if_rmap * if_rmap_get (const char *ifname) { struct if_rmap key; /* temporary copy */ key.ifname = (char *)ifname; return (struct if_rmap *) hash_get (ifrmaphash, &key, if_rmap_hash_alloc); } static unsigned int if_rmap_hash_make (void *data) { const struct if_rmap *if_rmap = data; return string_hash_make (if_rmap->ifname); } static int if_rmap_hash_cmp (const void *arg1, const void* arg2) { const struct if_rmap *if_rmap1 = arg1; const struct if_rmap *if_rmap2 = arg2; return strcmp (if_rmap1->ifname, if_rmap2->ifname) == 0; } static struct if_rmap * if_rmap_set (const char *ifname, enum if_rmap_type type, const 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]) XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); if_rmap->routemap[IF_RMAP_IN] = XSTRDUP (MTYPE_IF_RMAP_NAME, routemap_name); } if (type == IF_RMAP_OUT) { if (if_rmap->routemap[IF_RMAP_OUT]) XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); if_rmap->routemap[IF_RMAP_OUT] = XSTRDUP (MTYPE_IF_RMAP_NAME, routemap_name); } if (if_rmap_add_hook) (*if_rmap_add_hook) (if_rmap); return if_rmap; } static int if_rmap_unset (const char *ifname, enum if_rmap_type type, const 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; XFREE (MTYPE_IF_RMAP_NAME, 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; XFREE (MTYPE_IF_RMAP_NAME, 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 (if_rmap, 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; 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_set (argv[2], type, argv[0]); return CMD_SUCCESS; } ALIAS (if_rmap, if_ipv6_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") DEFUN (no_if_rmap, no_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; } ALIAS (no_if_rmap, no_if_ipv6_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") /* Configuration write function. */ int config_write_if_rmap (struct vty *vty) { unsigned 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 (int node) { ifrmaphash = hash_create (if_rmap_hash_make, if_rmap_hash_cmp); if (node == RIPNG_NODE) { install_element (RIPNG_NODE, &if_ipv6_rmap_cmd); install_element (RIPNG_NODE, &no_if_ipv6_rmap_cmd); } else if (node == RIP_NODE) { install_element (RIP_NODE, &if_rmap_cmd); install_element (RIP_NODE, &no_if_rmap_cmd); } } quagga-1.2.4/lib/if_rmap.h000066400000000000000000000025341325323223500153230ustar00rootroot00000000000000/* 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]; }; extern void if_rmap_init (int); extern void if_rmap_reset (void); extern void if_rmap_hook_add (void (*) (struct if_rmap *)); extern void if_rmap_hook_delete (void (*) (struct if_rmap *)); extern struct if_rmap *if_rmap_lookup (const char *); extern int config_write_if_rmap (struct vty *); #endif /* _ZEBRA_IF_RMAP_H */ quagga-1.2.4/lib/jhash.c000066400000000000000000000072201325323223500147730ustar00rootroot00000000000000/* jhash.h: Jenkins hash support. * * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) * * http://burtleburtle.net/bob/hash/ * * These are the credits from Bob's sources: * * lookup2.c, by Bob Jenkins, December 1996, Public Domain. * hash(), hash2(), hash3, and mix() are externally useful functions. * Routines to test the hash are included if SELF_TEST is defined. * You can use this free for any purpose. It has no warranty. * * Copyright (C) 2003 David S. Miller (davem@redhat.com) * * I've modified Bob's hash to be useful in the Linux kernel, and * any bugs present are surely my fault. -DaveM */ #include "zebra.h" #include "jhash.h" /* The golden ration: an arbitrary value */ #define JHASH_GOLDEN_RATIO 0x9e3779b9 /* NOTE: Arguments are modified. */ #define __jhash_mix(a, b, c) \ { \ a -= b; a -= c; a ^= (c>>13); \ b -= c; b -= a; b ^= (a<<8); \ c -= a; c -= b; c ^= (b>>13); \ a -= b; a -= c; a ^= (c>>12); \ b -= c; b -= a; b ^= (a<<16); \ c -= a; c -= b; c ^= (b>>5); \ a -= b; a -= c; a ^= (c>>3); \ b -= c; b -= a; b ^= (a<<10); \ c -= a; c -= b; c ^= (b>>15); \ } /* The most generic version, hashes an arbitrary sequence * of bytes. No alignment or length assumptions are made about * the input key. */ u_int32_t jhash (const void *key, u_int32_t length, u_int32_t initval) { u_int32_t a, b, c, len; const u_int8_t *k = key; len = length; a = b = JHASH_GOLDEN_RATIO; c = initval; while (len >= 12) { a += (k[0] + ((u_int32_t) k[1] << 8) + ((u_int32_t) k[2] << 16) + ((u_int32_t) k[3] << 24)); b += (k[4] + ((u_int32_t) k[5] << 8) + ((u_int32_t) k[6] << 16) + ((u_int32_t) k[7] << 24)); c += (k[8] + ((u_int32_t) k[9] << 8) + ((u_int32_t) k[10] << 16) + ((u_int32_t) k[11] << 24)); __jhash_mix (a, b, c); k += 12; len -= 12; } c += length; switch (len) { case 11: c += ((u_int32_t) k[10] << 24); case 10: c += ((u_int32_t) k[9] << 16); case 9: c += ((u_int32_t) k[8] << 8); case 8: b += ((u_int32_t) k[7] << 24); case 7: b += ((u_int32_t) k[6] << 16); case 6: b += ((u_int32_t) k[5] << 8); case 5: b += k[4]; case 4: a += ((u_int32_t) k[3] << 24); case 3: a += ((u_int32_t) k[2] << 16); case 2: a += ((u_int32_t) k[1] << 8); case 1: a += k[0]; }; __jhash_mix (a, b, c); return c; } /* A special optimized version that handles 1 or more of u_int32_ts. * The length parameter here is the number of u_int32_ts in the key. */ u_int32_t jhash2 (const u_int32_t *k, u_int32_t length, u_int32_t initval) { u_int32_t a, b, c, len; a = b = JHASH_GOLDEN_RATIO; c = initval; len = length; while (len >= 3) { a += k[0]; b += k[1]; c += k[2]; __jhash_mix (a, b, c); k += 3; len -= 3; } c += length * 4; switch (len) { case 2: b += k[1]; case 1: a += k[0]; }; __jhash_mix (a, b, c); return c; } /* A special ultra-optimized versions that knows they are hashing exactly * 3, 2 or 1 word(s). * * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally * done at the end is not done here. */ u_int32_t jhash_3words (u_int32_t a, u_int32_t b, u_int32_t c, u_int32_t initval) { a += JHASH_GOLDEN_RATIO; b += JHASH_GOLDEN_RATIO; c += initval; __jhash_mix (a, b, c); return c; } u_int32_t jhash_2words (u_int32_t a, u_int32_t b, u_int32_t initval) { return jhash_3words (a, b, 0, initval); } u_int32_t jhash_1word (u_int32_t a, u_int32_t initval) { return jhash_3words (a, 0, 0, initval); } quagga-1.2.4/lib/jhash.h000066400000000000000000000031051325323223500147760ustar00rootroot00000000000000/* jhash.h: Jenkins hash support. * * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) * * http://burtleburtle.net/bob/hash/ * * These are the credits from Bob's sources: * * lookup2.c, by Bob Jenkins, December 1996, Public Domain. * hash(), hash2(), hash3, and mix() are externally useful functions. * Routines to test the hash are included if SELF_TEST is defined. * You can use this free for any purpose. It has no warranty. * * Copyright (C) 2003 David S. Miller (davem@redhat.com) * * I've modified Bob's hash to be useful in the Linux kernel, and * any bugs present are surely my fault. -DaveM */ #ifndef _QUAGGA_JHASH_H #define _QUAGGA_JHASH_H /* The most generic version, hashes an arbitrary sequence * of bytes. No alignment or length assumptions are made about * the input key. */ extern u_int32_t jhash(const void *key, u_int32_t length, u_int32_t initval); /* A special optimized version that handles 1 or more of u_int32_ts. * The length parameter here is the number of u_int32_ts in the key. */ extern u_int32_t jhash2(const u_int32_t *k, u_int32_t length, u_int32_t initval); /* A special ultra-optimized versions that knows they are hashing exactly * 3, 2 or 1 word(s). * * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally * done at the end is not done here. */ extern u_int32_t jhash_3words(u_int32_t a, u_int32_t b, u_int32_t c, u_int32_t initval); extern u_int32_t jhash_2words(u_int32_t a, u_int32_t b, u_int32_t initval); extern u_int32_t jhash_1word(u_int32_t a, u_int32_t initval); #endif /* _QUAGGA_JHASH_H */ quagga-1.2.4/lib/keychain.c000066400000000000000000000601771325323223500155030ustar00rootroot00000000000000/* 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; static struct keychain * keychain_new (void) { return XCALLOC (MTYPE_KEYCHAIN, sizeof (struct keychain)); } static void keychain_free (struct keychain *keychain) { XFREE (MTYPE_KEYCHAIN, keychain); } static struct key * key_new (void) { return XCALLOC (MTYPE_KEY, sizeof (struct key)); } static void key_free (struct key *key) { XFREE (MTYPE_KEY, key); } struct keychain * keychain_lookup (const char *name) { struct listnode *node; struct keychain *keychain; if (name == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO (keychain_list, node, keychain)) { if (strcmp (keychain->name, name) == 0) return keychain; } return NULL; } static int key_cmp_func (void *arg1, void *arg2) { const struct key *k1 = arg1; const struct key *k2 = arg2; if (k1->index > k2->index) return 1; if (k1->index < k2->index) return -1; return 0; } static void key_delete_func (struct key *key) { if (key->string) free (key->string); key_free (key); } static struct keychain * keychain_get (const 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; } static void keychain_delete (struct keychain *keychain) { if (keychain->name) free (keychain->name); list_delete (keychain->key); listnode_delete (keychain_list, keychain); keychain_free (keychain); } static struct key * key_lookup (const struct keychain *keychain, u_int32_t index) { struct listnode *node; struct key *key; for (ALL_LIST_ELEMENTS_RO (keychain->key, node, key)) { if (key->index == index) return key; } return NULL; } struct key * key_lookup_for_accept (const struct keychain *keychain, u_int32_t index) { struct listnode *node; struct key *key; time_t now; now = time (NULL); for (ALL_LIST_ELEMENTS_RO (keychain->key, node, key)) { 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 (const struct keychain *keychain, const char *auth_str) { struct listnode *node; struct key *key; time_t now; now = time (NULL); for (ALL_LIST_ELEMENTS_RO (keychain->key, node, key)) { 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 (const struct keychain *keychain) { struct listnode *node; struct key *key; time_t now; now = time (NULL); for (ALL_LIST_ELEMENTS_RO (keychain->key, node, key)) { 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; } static struct key * key_get (const 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; } static 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; keychain = vty->index; VTY_GET_INTEGER ("key identifier", index, argv[0]); 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; keychain = vty->index; VTY_GET_INTEGER ("key identifier", index, argv[0]); 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. */ static time_t key_str2time (const char *time_str, const char *day_str, const char *month_str, const char *year_str) { int i = 0; char *colon; struct tm tm; time_t time; unsigned int sec, min, hour; unsigned int day, month, year; const char *month_name[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL }; #define _GET_LONG_RANGE(V,STR,MMCOND) \ { \ unsigned long tmpl; \ char *endptr = NULL; \ tmpl = strtoul ((STR), &endptr, 10); \ if (*endptr != '\0' || tmpl == ULONG_MAX) \ return -1; \ if (MMCOND) \ return -1; \ (V) = tmpl; \ } #define GET_LONG_RANGE(V,STR,MIN,MAX) \ _GET_LONG_RANGE(V,STR,tmpl < (MIN) || tmpl > (MAX)) #define GET_LONG_RANGE0(V,STR,MAX) \ _GET_LONG_RANGE(V,STR,tmpl > (MAX)) /* Check hour field of time_str. */ colon = strchr (time_str, ':'); if (colon == NULL) return -1; *colon = '\0'; /* Hour must be between 0 and 23. */ GET_LONG_RANGE0 (hour, time_str, 23); /* 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. */ GET_LONG_RANGE0 (min, time_str, 59); /* Check sec field of time_str. */ time_str = colon + 1; if (*time_str == '\0') return -1; /* Sec must be between 0 and 59. */ GET_LONG_RANGE0 (sec, time_str, 59); /* Check day_str. Day must be <1-31>. */ GET_LONG_RANGE (day, day_str, 1, 31); /* 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>. */ GET_LONG_RANGE (year, year_str, 1993, 2035); 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; #undef GET_LONG_RANGE } static int key_lifetime_set (struct vty *vty, struct key_range *krange, const char *stime_str, const char *sday_str, const char *smonth_str, const char *syear_str, const char *etime_str, const char *eday_str, const char *emonth_str, const 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; } static int key_lifetime_duration_set (struct vty *vty, struct key_range *krange, const char *stime_str, const char *sday_str, const char *smonth_str, const char *syear_str, const char *duration_str) { time_t time_start; u_int32_t duration; 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; VTY_GET_INTEGER ("duration", duration, duration_str); krange->duration = 1; krange->end = time_start + duration; return CMD_SUCCESS; } static int key_lifetime_infinite_set (struct vty *vty, struct key_range *krange, const char *stime_str, const char *sday_str, const char *smonth_str, const 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]); } static struct cmd_node keychain_node = { KEYCHAIN_NODE, "%s(config-keychain)# ", 1 }; static struct cmd_node keychain_key_node = { KEYCHAIN_KEY_NODE, "%s(config-keychain-key)# ", 1 }; static 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; } static int keychain_config_write (struct vty *vty) { struct keychain *keychain; struct key *key; struct listnode *node; struct listnode *knode; char buf[BUFSIZ]; for (ALL_LIST_ELEMENTS_RO (keychain_list, node, keychain)) { vty_out (vty, "key chain %s%s", keychain->name, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (keychain->key, knode, key)) { 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", (long)(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", (long)(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); } quagga-1.2.4/lib/keychain.h000066400000000000000000000027001325323223500154740ustar00rootroot00000000000000/* 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; }; extern void keychain_init (void); extern struct keychain *keychain_lookup (const char *); extern struct key *key_lookup_for_accept (const struct keychain *, u_int32_t); extern struct key *key_match_for_accept (const struct keychain *, const char *); extern struct key *key_lookup_for_send (const struct keychain *); #endif /* _ZEBRA_KEYCHAIN_H */ quagga-1.2.4/lib/libospf.h000066400000000000000000000063251325323223500153460ustar00rootroot00000000000000/* * Defines and structures common to OSPFv2 and OSPFv3 * 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 _LIBOSPFD_H #define _LIBOSPFD_H /* IP precedence. */ #ifndef IPTOS_PREC_INTERNETCONTROL #define IPTOS_PREC_INTERNETCONTROL 0xC0 #endif /* IPTOS_PREC_INTERNETCONTROL */ /* Default protocol, port number. */ #ifndef IPPROTO_OSPFIGP #define IPPROTO_OSPFIGP 89 #endif /* IPPROTO_OSPFIGP */ /* Architectual Constants */ #ifdef DEBUG #define OSPF_LS_REFRESH_TIME 60 #else #define OSPF_LS_REFRESH_TIME 1800 #endif #define OSPF_MIN_LS_INTERVAL 5000 /* msec */ #define OSPF_MIN_LS_ARRIVAL 1000 /* msec */ #define OSPF_LSA_INITIAL_AGE 0 /* useful for debug */ #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 0x80000001U #define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffffU /* OSPF Interface Types */ #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 /* OSPF interface default values. */ #define OSPF_OUTPUT_COST_DEFAULT 10 #define OSPF_OUTPUT_COST_INFINITE UINT16_MAX #define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT 40 #define OSPF_ROUTER_DEAD_INTERVAL_MINIMAL 1 #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 #define OSPF_MTU_IGNORE_DEFAULT 0 #define OSPF_FAST_HELLO_DEFAULT 0 #define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ /* SPF Throttling timer values. */ #define OSPF_SPF_DELAY_DEFAULT 0 #define OSPF_SPF_HOLDTIME_DEFAULT 50 #define OSPF_SPF_MAX_HOLDTIME_DEFAULT 5000 #define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 #define OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 #endif /* _LIBOSPFD_H */ quagga-1.2.4/lib/linklist.c000066400000000000000000000150541325323223500155330ustar00rootroot00000000000000/* 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 (void) { return XCALLOC (MTYPE_LINK_LIST, sizeof (struct list)); } /* Free list. */ void list_free (struct list *l) { XFREE (MTYPE_LINK_LIST, l); } /* Allocate new listnode. Internal use only. */ static struct listnode * listnode_new (void) { return XCALLOC (MTYPE_LINK_NODE, sizeof (struct listnode)); } /* 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; assert (val != NULL); 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 a node to the list. If the list was sorted according to the * cmp function, insert a new node with the given val such that the * list remains sorted. The new node is always inserted; there is no * notion of omitting duplicates. */ void listnode_add_sort (struct list *list, void *val) { struct listnode *n; struct listnode *new; assert (val != NULL); 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; assert (val != NULL); 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; } list->count++; } struct listnode * listnode_add_before (struct list *list, struct listnode *pp, void *val) { struct listnode *nn; assert (val != NULL); nn = listnode_new (); nn->data = val; if (pp == NULL) { if (list->tail) list->tail->next = nn; else list->head = nn; nn->prev = list->tail; nn->next = pp; list->tail = nn; } else { if (pp->prev) pp->prev->next = nn; else list->head = nn; nn->prev = pp->prev; nn->next = pp; pp->prev = nn; } list->count++; return nn; } /* Move given listnode to tail of the list */ void listnode_move_to_tail (struct list *l, struct listnode *n) { LISTNODE_DETACH(l,n); LISTNODE_ATTACH(l,n); } /* Delete specific date pointer from the list. */ void listnode_delete (struct list *list, void *val) { struct listnode *node; assert(list); 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; assert(list); 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; assert(list); 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) { assert(list); list_delete_all_node (list); list_free (list); } /* Lookup the node which has given data. */ struct listnode * listnode_lookup (struct list *list, void *data) { struct listnode *node; assert(list); for (node = listhead(list); node; node = listnextnode (node)) if (data == listgetdata (node)) return node; return NULL; } /* Delete the node from list. For ospfd and ospf6d. */ void list_delete_node (struct list *list, struct 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 (struct list *list, struct listnode *current, void *val) { struct listnode *node; assert (val != NULL); 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 (struct list *list, struct listnode *current, void *val) { struct listnode *node; assert (val != NULL); 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; n = listnextnode (n)) listnode_add (l, n->data); } quagga-1.2.4/lib/linklist.h000066400000000000000000000116071325323223500155400ustar00rootroot00000000000000/* 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 /* listnodes must always contain data to be valid. Adding an empty node * to a list is invalid */ struct listnode { struct listnode *next; struct listnode *prev; /* private member, use getdata() to retrieve, do not access directly */ void *data; }; struct list { struct listnode *head; struct listnode *tail; /* invariant: count is the number of listnodes in the list */ unsigned int count; /* * Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2. * Used as definition of sorted for listnode_add_sort */ int (*cmp) (void *val1, void *val2); /* callback to free user-owned data when listnode is deleted. supplying * this callback is very much encouraged! */ void (*del) (void *val); }; #define listnextnode(X) ((X) ? ((X)->next) : NULL) #define listhead(X) ((X) ? ((X)->head) : NULL) #define listtail(X) ((X) ? ((X)->tail) : NULL) #define listcount(X) ((X)->count) #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL) #define listgetdata(X) (assert((X)->data != NULL), (X)->data) /* Prototypes. */ extern struct list *list_new(void); /* encouraged: set list.del callback on new lists */ extern void list_free (struct list *); extern void listnode_add (struct list *, void *); extern void listnode_add_sort (struct list *, void *); extern void listnode_add_after (struct list *, struct listnode *, void *); extern struct listnode *listnode_add_before (struct list *, struct listnode *, void *); extern void listnode_move_to_tail (struct list *, struct listnode *); extern void listnode_delete (struct list *, void *); extern struct listnode *listnode_lookup (struct list *, void *); extern void *listnode_head (struct list *); extern void list_delete (struct list *); extern void list_delete_all_node (struct list *); /* For ospfd and ospf6d. */ extern void list_delete_node (struct list *, struct listnode *); /* For ospf_spf.c */ extern void list_add_node_prev (struct list *, struct listnode *, void *); extern void list_add_node_next (struct list *, struct listnode *, void *); extern void list_add_list (struct list *, struct list *); /* List iteration macro. * Usage: for (ALL_LIST_ELEMENTS (...) { ... } * It is safe to delete the listnode using this macro. */ #define ALL_LIST_ELEMENTS(list,node,nextnode,data) \ (node) = listhead(list), ((data) = NULL); \ (node) != NULL && \ ((data) = listgetdata(node),(nextnode) = node->next, 1); \ (node) = (nextnode), ((data) = NULL) /* read-only list iteration macro. * Usage: as per ALL_LIST_ELEMENTS, but not safe to delete the listnode Only * use this macro when it is *immediately obvious* the listnode is not * deleted in the body of the loop. Does not have forward-reference overhead * of previous macro. */ #define ALL_LIST_ELEMENTS_RO(list,node,data) \ (node) = listhead(list), ((data) = NULL);\ (node) != NULL && ((data) = listgetdata(node), 1); \ (node) = listnextnode(node), ((data) = NULL) /* these *do not* cleanup list nodes and referenced data, as the functions * do - these macros simply {de,at}tach a listnode from/to a list. */ /* List node attach macro. */ #define LISTNODE_ATTACH(L,N) \ do { \ (N)->prev = (L)->tail; \ (N)->next = NULL; \ if ((L)->head == NULL) \ (L)->head = (N); \ else \ (L)->tail->next = (N); \ (L)->tail = (N); \ (L)->count++; \ } while (0) /* List node detach macro. */ #define LISTNODE_DETACH(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; \ (L)->count--; \ } while (0) /* Deprecated: 20050406 */ #if !defined(QUAGGA_NO_DEPRECATED_INTERFACES) #warning "Using deprecated libzebra interfaces" #define LISTNODE_ADD(L,N) LISTNODE_ATTACH(L,N) #define LISTNODE_DELETE(L,N) LISTNODE_DETACH(L,N) #define nextnode(X) ((X) = (X)->next) #define getdata(X) listgetdata(X) #define LIST_LOOP(L,V,N) \ for (ALL_LIST_ELEMENTS_RO (L,N,V)) #endif /* QUAGGA_NO_DEPRECATED_INTERFACES */ #endif /* _ZEBRA_LINKLIST_H */ quagga-1.2.4/lib/log.c000066400000000000000000000621611325323223500144640ustar00rootroot00000000000000/* * 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. */ #define QUAGGA_DEFINE_DESC_TABLE #include #include "log.h" #include "memory.h" #include "command.h" #ifndef SUNOS_5 #include #endif /* for printstack on solaris */ #ifdef HAVE_UCONTEXT_H #include #endif static int logfile_fd = -1; /* Used in signal handler. */ struct zlog *zlog_default = NULL; const char *zlog_proto_names[] = { "NONE", "DEFAULT", "ZEBRA", "RIP", "BGP", "OSPF", "RIPNG", "BABEL", "OSPF6", "ISIS", "PIM", "MASC", "NHRP", NULL, }; const char *zlog_priority[] = { "emergencies", "alerts", "critical", "errors", "warnings", "notifications", "informational", "debugging", NULL, }; /* For time string format. */ size_t quagga_timestamp(int timestamp_precision, char *buf, size_t buflen) { static struct { time_t last; size_t len; char buf[28]; } cache; struct timeval clock; /* would it be sufficient to use global 'recent_time' here? I fear not... */ gettimeofday(&clock, NULL); /* first, we update the cache if the time has changed */ if (cache.last != clock.tv_sec) { struct tm *tm; cache.last = clock.tv_sec; tm = localtime(&cache.last); cache.len = strftime(cache.buf, sizeof(cache.buf), "%Y/%m/%d %H:%M:%S", tm); } /* note: it's not worth caching the subsecond part, because chances are that back-to-back calls are not sufficiently close together for the clock not to have ticked forward */ if (buflen > cache.len) { memcpy(buf, cache.buf, cache.len); if ((timestamp_precision > 0) && (buflen > cache.len+1+timestamp_precision)) { /* should we worry about locale issues? */ static const int divisor[] = {0, 100000, 10000, 1000, 100, 10, 1}; int prec; char *p = buf+cache.len+1+(prec = timestamp_precision); *p-- = '\0'; while (prec > 6) /* this is unlikely to happen, but protect anyway */ { *p-- = '0'; prec--; } clock.tv_usec /= divisor[prec]; do { *p-- = '0'+(clock.tv_usec % 10); clock.tv_usec /= 10; } while (--prec > 0); *p = '.'; return cache.len+1+timestamp_precision; } buf[cache.len] = '\0'; return cache.len; } if (buflen > 0) buf[0] = '\0'; return 0; } /* Utility routine for current time printing. */ static void time_print(FILE *fp, struct timestamp_control *ctl) { if (!ctl->already_rendered) { ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); ctl->already_rendered = 1; } fprintf(fp, "%s ", ctl->buf); } /* va_list version of zlog. */ static void vzlog (struct zlog *zl, int priority, const char *format, va_list args) { int original_errno = errno; struct timestamp_control tsctl; tsctl.already_rendered = 0; /* 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) { tsctl.precision = 0; time_print(stderr, &tsctl); fprintf (stderr, "%s: ", "unknown"); vfprintf (stderr, format, args); fprintf (stderr, "\n"); fflush (stderr); /* In this case we return at here. */ errno = original_errno; return; } tsctl.precision = zl->timestamp_precision; /* Syslog output */ if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG]) { va_list ac; va_copy(ac, args); vsyslog (priority|zlog_default->facility, format, ac); va_end(ac); } /* File output. */ if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) { va_list ac; time_print (zl->fp, &tsctl); if (zl->record_priority) fprintf (zl->fp, "%s: ", zlog_priority[priority]); fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]); va_copy(ac, args); vfprintf (zl->fp, format, ac); va_end(ac); fprintf (zl->fp, "\n"); fflush (zl->fp); } /* stdout output. */ if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) { va_list ac; time_print (stdout, &tsctl); if (zl->record_priority) fprintf (stdout, "%s: ", zlog_priority[priority]); fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]); va_copy(ac, args); vfprintf (stdout, format, ac); va_end(ac); fprintf (stdout, "\n"); fflush (stdout); } /* Terminal monitor. */ if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) vty_log ((zl->record_priority ? zlog_priority[priority] : NULL), zlog_proto_names[zl->protocol], format, &tsctl, args); errno = original_errno; } static char * str_append(char *dst, int len, const char *src) { while ((len-- > 0) && *src) *dst++ = *src++; return dst; } static char * num_append(char *s, int len, u_long x) { char buf[30]; char *t; if (!x) return str_append(s,len,"0"); *(t = &buf[sizeof(buf)-1]) = '\0'; while (x && (t > buf)) { *--t = '0'+(x % 10); x /= 10; } return str_append(s,len,t); } #if defined(SA_SIGINFO) || defined(HAVE_STACK_TRACE) static char * hex_append(char *s, int len, u_long x) { char buf[30]; char *t; if (!x) return str_append(s,len,"0"); *(t = &buf[sizeof(buf)-1]) = '\0'; while (x && (t > buf)) { u_int cc = (x % 16); *--t = ((cc < 10) ? ('0'+cc) : ('a'+cc-10)); x /= 16; } return str_append(s,len,t); } #endif /* Needs to be enhanced to support Solaris. */ static int syslog_connect(void) { #ifdef SUNOS_5 return -1; #else int fd; char *s; struct sockaddr_un addr; if ((fd = socket(AF_UNIX,SOCK_DGRAM,0)) < 0) return -1; addr.sun_family = AF_UNIX; #ifdef _PATH_LOG #define SYSLOG_SOCKET_PATH _PATH_LOG #else #define SYSLOG_SOCKET_PATH "/dev/log" #endif s = str_append(addr.sun_path,sizeof(addr.sun_path),SYSLOG_SOCKET_PATH); #undef SYSLOG_SOCKET_PATH *s = '\0'; if (connect(fd,(struct sockaddr *)&addr,sizeof(addr)) < 0) { close(fd); return -1; } return fd; #endif } static void syslog_sigsafe(int priority, const char *msg, size_t msglen) { static int syslog_fd = -1; char buf[sizeof("<1234567890>ripngd[1234567890]: ")+msglen+50]; char *s; if ((syslog_fd < 0) && ((syslog_fd = syslog_connect()) < 0)) return; #define LOC s,buf+sizeof(buf)-s s = buf; s = str_append(LOC,"<"); s = num_append(LOC,priority); s = str_append(LOC,">"); /* forget about the timestamp, too difficult in a signal handler */ s = str_append(LOC,zlog_default->ident); if (zlog_default->syslog_options & LOG_PID) { s = str_append(LOC,"["); s = num_append(LOC,getpid()); s = str_append(LOC,"]"); } s = str_append(LOC,": "); s = str_append(LOC,msg); write(syslog_fd,buf,s-buf); #undef LOC } static int open_crashlog(void) { #define CRASHLOG_PREFIX "/var/tmp/quagga." #define CRASHLOG_SUFFIX "crashlog" if (zlog_default && zlog_default->ident) { /* Avoid strlen since it is not async-signal-safe. */ const char *p; size_t ilen; for (p = zlog_default->ident, ilen = 0; *p; p++) ilen++; { char buf[sizeof(CRASHLOG_PREFIX)+ilen+sizeof(CRASHLOG_SUFFIX)+3]; char *s = buf; #define LOC s,buf+sizeof(buf)-s s = str_append(LOC, CRASHLOG_PREFIX); s = str_append(LOC, zlog_default->ident); s = str_append(LOC, "."); s = str_append(LOC, CRASHLOG_SUFFIX); #undef LOC *s = '\0'; return open(buf, O_WRONLY|O_CREAT|O_EXCL, LOGFILE_MASK); } } return open(CRASHLOG_PREFIX CRASHLOG_SUFFIX, O_WRONLY|O_CREAT|O_EXCL, LOGFILE_MASK); #undef CRASHLOG_SUFFIX #undef CRASHLOG_PREFIX } /* Note: the goal here is to use only async-signal-safe functions. */ void zlog_signal(int signo, const char *action #ifdef SA_SIGINFO , siginfo_t *siginfo, void *program_counter #endif ) { time_t now; char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")+100]; char *s = buf; char *msgstart = buf; #define LOC s,buf+sizeof(buf)-s time(&now); if (zlog_default) { s = str_append(LOC,zlog_proto_names[zlog_default->protocol]); *s++ = ':'; *s++ = ' '; msgstart = s; } s = str_append(LOC,"Received signal "); s = num_append(LOC,signo); s = str_append(LOC," at "); s = num_append(LOC,now); #ifdef SA_SIGINFO s = str_append(LOC," (si_addr 0x"); s = hex_append(LOC,(u_long)(siginfo->si_addr)); if (program_counter) { s = str_append(LOC,", PC 0x"); s = hex_append(LOC,(u_long)program_counter); } s = str_append(LOC,"); "); #else /* SA_SIGINFO */ s = str_append(LOC,"; "); #endif /* SA_SIGINFO */ s = str_append(LOC,action); if (s < buf+sizeof(buf)) *s++ = '\n'; /* N.B. implicit priority is most severe */ #define PRI LOG_CRIT #define DUMP(FD) write(FD, buf, s-buf); /* If no file logging configured, try to write to fallback log file. */ if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0)) DUMP(logfile_fd) if (!zlog_default) DUMP(STDERR_FILENO) else { if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT]) DUMP(STDOUT_FILENO) /* Remove trailing '\n' for monitor and syslog */ *--s = '\0'; if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) vty_log_fixed(buf,s-buf); if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) syslog_sigsafe(PRI|zlog_default->facility,msgstart,s-msgstart); } #undef DUMP zlog_backtrace_sigsafe(PRI, #ifdef SA_SIGINFO program_counter #else NULL #endif ); s = buf; if (!thread_current) s = str_append (LOC, "no thread information available\n"); else { s = str_append (LOC, "in thread "); s = str_append (LOC, thread_current->funcname); s = str_append (LOC, " scheduled from "); s = str_append (LOC, thread_current->schedfrom); s = str_append (LOC, ":"); s = num_append (LOC, thread_current->schedfrom_line); s = str_append (LOC, "\n"); } #define DUMP(FD) write(FD, buf, s-buf); /* If no file logging configured, try to write to fallback log file. */ if (logfile_fd >= 0) DUMP(logfile_fd) if (!zlog_default) DUMP(STDERR_FILENO) else { if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT]) DUMP(STDOUT_FILENO) /* Remove trailing '\n' for monitor and syslog */ *--s = '\0'; if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) vty_log_fixed(buf,s-buf); if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) syslog_sigsafe(PRI|zlog_default->facility,msgstart,s-msgstart); } #undef DUMP #undef PRI #undef LOC } /* Log a backtrace using only async-signal-safe functions. Needs to be enhanced to support syslog logging. */ void zlog_backtrace_sigsafe(int priority, void *program_counter) { #ifdef HAVE_STACK_TRACE static const char pclabel[] = "Program counter: "; void *array[64]; int size; char buf[100]; char *s, **bt = NULL; #define LOC s,buf+sizeof(buf)-s #ifdef HAVE_GLIBC_BACKTRACE size = backtrace(array, array_size(array)); if (size <= 0 || (size_t)size > array_size(array)) return; #define DUMP(FD) { \ if (program_counter) \ { \ write(FD, pclabel, sizeof(pclabel)-1); \ backtrace_symbols_fd(&program_counter, 1, FD); \ } \ write(FD, buf, s-buf); \ backtrace_symbols_fd(array, size, FD); \ } #elif defined(HAVE_PRINTSTACK) #define DUMP(FD) { \ if (program_counter) \ write((FD), pclabel, sizeof(pclabel)-1); \ write((FD), buf, s-buf); \ printstack((FD)); \ } #endif /* HAVE_GLIBC_BACKTRACE, HAVE_PRINTSTACK */ s = buf; s = str_append(LOC,"Backtrace for "); s = num_append(LOC,size); s = str_append(LOC," stack frames:\n"); if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0)) DUMP(logfile_fd) if (!zlog_default) DUMP(STDERR_FILENO) else { if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT]) DUMP(STDOUT_FILENO) /* Remove trailing '\n' for monitor and syslog */ *--s = '\0'; if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) vty_log_fixed(buf,s-buf); if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) syslog_sigsafe(priority|zlog_default->facility,buf,s-buf); { int i; #ifdef HAVE_GLIBC_BACKTRACE bt = backtrace_symbols(array, size); #endif /* Just print the function addresses. */ for (i = 0; i < size; i++) { s = buf; if (bt) s = str_append(LOC, bt[i]); else { s = str_append(LOC,"[bt "); s = num_append(LOC,i); s = str_append(LOC,"] 0x"); s = hex_append(LOC,(u_long)(array[i])); } *s = '\0'; if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) vty_log_fixed(buf,s-buf); if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) syslog_sigsafe(priority|zlog_default->facility,buf,s-buf); } if (bt) free(bt); } } #undef DUMP #undef LOC #endif /* HAVE_STRACK_TRACE */ } void zlog_backtrace(int priority) { #ifndef HAVE_GLIBC_BACKTRACE zlog(NULL, priority, "No backtrace available on this platform."); #else void *array[20]; int size, i; char **strings; size = backtrace(array, array_size(array)); if (size <= 0 || (size_t)size > array_size(array)) { zlog_err("Cannot get backtrace, returned invalid # of frames %d " "(valid range is between 1 and %lu)", size, (unsigned long)(array_size(array))); return; } zlog(NULL, priority, "Backtrace for %d stack frames:", size); if (!(strings = backtrace_symbols(array, size))) { zlog_err("Cannot get backtrace symbols (out of memory?)"); for (i = 0; i < size; i++) zlog(NULL, priority, "[bt %d] %p",i,array[i]); } else { for (i = 0; i < size; i++) zlog(NULL, priority, "[bt %d] %s",i,strings[i]); free(strings); } #endif /* HAVE_GLIBC_BACKTRACE */ } void zlog (struct zlog *zl, int priority, const char *format, ...) { va_list args; va_start(args, format); vzlog (zl, priority, format, args); va_end (args); } #define ZLOG_FUNC(FUNCNAME,PRIORITY) \ void \ FUNCNAME(const char *format, ...) \ { \ va_list args; \ va_start(args, format); \ vzlog (NULL, PRIORITY, format, args); \ va_end(args); \ } ZLOG_FUNC(zlog_err, LOG_ERR) ZLOG_FUNC(zlog_warn, LOG_WARNING) ZLOG_FUNC(zlog_info, LOG_INFO) ZLOG_FUNC(zlog_notice, LOG_NOTICE) ZLOG_FUNC(zlog_debug, LOG_DEBUG) #undef ZLOG_FUNC #define PLOG_FUNC(FUNCNAME,PRIORITY) \ void \ FUNCNAME(struct zlog *zl, const char *format, ...) \ { \ va_list args; \ va_start(args, format); \ vzlog (zl, PRIORITY, format, args); \ va_end(args); \ } PLOG_FUNC(plog_err, LOG_ERR) PLOG_FUNC(plog_warn, LOG_WARNING) PLOG_FUNC(plog_info, LOG_INFO) PLOG_FUNC(plog_notice, LOG_NOTICE) PLOG_FUNC(plog_debug, LOG_DEBUG) #undef PLOG_FUNC void zlog_thread_info (int log_level) { if (thread_current) zlog(NULL, log_level, "Current thread function %s, scheduled from " "file %s, line %u", thread_current->funcname, thread_current->schedfrom, thread_current->schedfrom_line); else zlog(NULL, log_level, "Current thread not known/applicable"); } void _zlog_assert_failed (const char *assertion, const char *file, unsigned int line, const char *function) { /* Force fallback file logging? */ if (zlog_default && !zlog_default->fp && ((logfile_fd = open_crashlog()) >= 0) && ((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL)) zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR; zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s", assertion,file,line,(function ? function : "?")); zlog_backtrace(LOG_CRIT); zlog_thread_info(LOG_CRIT); abort(); } /* Open log stream */ struct zlog * openzlog (const char *progname, zlog_proto_t protocol, int syslog_flags, int syslog_facility) { struct zlog *zl; u_int i; zl = XCALLOC(MTYPE_ZLOG, sizeof (struct zlog)); zl->ident = progname; zl->protocol = protocol; zl->facility = syslog_facility; zl->syslog_options = syslog_flags; /* Set default logging levels. */ for (i = 0; i < array_size(zl->maxlvl); i++) zl->maxlvl[i] = ZLOG_DISABLED; zl->maxlvl[ZLOG_DEST_MONITOR] = LOG_DEBUG; zl->default_lvl = LOG_DEBUG; openlog (progname, syslog_flags, zl->facility); return zl; } void closezlog (struct zlog *zl) { closelog(); if (zl->fp != NULL) fclose (zl->fp); if (zl->filename != NULL) free (zl->filename); XFREE (MTYPE_ZLOG, zl); } /* Called from command.c. */ void zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level) { if (zl == NULL) zl = zlog_default; zl->maxlvl[dest] = log_level; } int zlog_set_file (struct zlog *zl, const char *filename, int log_level) { FILE *fp; mode_t oldumask; /* There is opend file. */ zlog_reset_file (zl); /* Set default zl. */ if (zl == NULL) zl = zlog_default; /* Open file. */ oldumask = umask (0777 & ~LOGFILE_MASK); fp = fopen (filename, "a"); umask(oldumask); if (fp == NULL) return 0; /* Set flags. */ zl->filename = strdup (filename); zl->maxlvl[ZLOG_DEST_FILE] = log_level; zl->fp = fp; logfile_fd = fileno(fp); return 1; } /* Reset opend file. */ int zlog_reset_file (struct zlog *zl) { if (zl == NULL) zl = zlog_default; if (zl->fp) fclose (zl->fp); zl->fp = NULL; logfile_fd = -1; zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; if (zl->filename) free (zl->filename); zl->filename = NULL; return 1; } /* Reopen log file. */ int zlog_rotate (struct zlog *zl) { int level; if (zl == NULL) zl = zlog_default; if (zl->fp) fclose (zl->fp); zl->fp = NULL; logfile_fd = -1; level = zl->maxlvl[ZLOG_DEST_FILE]; zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; if (zl->filename) { mode_t oldumask; int save_errno; oldumask = umask (0777 & ~LOGFILE_MASK); zl->fp = fopen (zl->filename, "a"); save_errno = errno; umask(oldumask); if (zl->fp == NULL) { zlog_err("Log rotate failed: cannot open file %s for append: %s", zl->filename, safe_strerror(save_errno)); return -1; } logfile_fd = fileno(zl->fp); zl->maxlvl[ZLOG_DEST_FILE] = level; } return 1; } /* Message lookup function. */ const char * lookup (const struct message *mes, int key) { const struct message *pnt; for (pnt = mes; pnt->key != 0; pnt++) if (pnt->key == key) return pnt->str; return ""; } /* Older/faster version of message lookup function, but requires caller to pass * in the array size (instead of relying on a 0 key to terminate the search). * * The return value is the message string if found, or the 'none' pointer * provided otherwise. */ const char * mes_lookup (const struct message *meslist, int max, int index, const char *none, const char *mesname) { int pos = index - meslist[0].key; /* first check for best case: index is in range and matches the key * value in that slot. * NB: key numbering might be offset from 0. E.g. protocol constants * often start at 1. */ if ((pos >= 0) && (pos < max) && (meslist[pos].key == index)) return meslist[pos].str; /* fall back to linear search */ { int i; for (i = 0; i < max; i++, meslist++) { if (meslist->key == index) { const char *str = (meslist->str ? meslist->str : none); zlog_debug ("message index %d [%s] found in %s at position %d (max is %d)", index, str, mesname, i, max); return str; } } } zlog_err("message index %d not found in %s (max is %d)", index, mesname, max); assert (none); return none; } /* Wrapper around strerror to handle case where it returns NULL. */ const char * safe_strerror(int errnum) { const char *s = strerror(errnum); return (s != NULL) ? s : "Unknown error"; } #define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' } static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_INTERFACE_ADD), DESC_ENTRY (ZEBRA_INTERFACE_DELETE), DESC_ENTRY (ZEBRA_INTERFACE_ADDRESS_ADD), DESC_ENTRY (ZEBRA_INTERFACE_ADDRESS_DELETE), DESC_ENTRY (ZEBRA_INTERFACE_UP), DESC_ENTRY (ZEBRA_INTERFACE_DOWN), DESC_ENTRY (ZEBRA_IPV4_ROUTE_ADD), DESC_ENTRY (ZEBRA_IPV4_ROUTE_DELETE), DESC_ENTRY (ZEBRA_IPV6_ROUTE_ADD), DESC_ENTRY (ZEBRA_IPV6_ROUTE_DELETE), DESC_ENTRY (ZEBRA_REDISTRIBUTE_ADD), DESC_ENTRY (ZEBRA_REDISTRIBUTE_DELETE), DESC_ENTRY (ZEBRA_REDISTRIBUTE_DEFAULT_ADD), DESC_ENTRY (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE), DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_LOOKUP), DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_LOOKUP), DESC_ENTRY (ZEBRA_IPV4_IMPORT_LOOKUP), DESC_ENTRY (ZEBRA_IPV6_IMPORT_LOOKUP), DESC_ENTRY (ZEBRA_INTERFACE_RENAME), DESC_ENTRY (ZEBRA_ROUTER_ID_ADD), DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE), DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE), DESC_ENTRY (ZEBRA_HELLO), DESC_ENTRY (ZEBRA_NEXTHOP_REGISTER), DESC_ENTRY (ZEBRA_NEXTHOP_UNREGISTER), DESC_ENTRY (ZEBRA_NEXTHOP_UPDATE), }; #undef DESC_ENTRY static const struct zebra_desc_table unknown = { 0, "unknown", '?' }; static const struct zebra_desc_table * zroute_lookup(u_int zroute) { u_int i; if (zroute >= array_size(route_types)) { zlog_err("unknown zebra route type: %u", zroute); return &unknown; } if (zroute == route_types[zroute].type) return &route_types[zroute]; for (i = 0; i < array_size(route_types); i++) { if (zroute == route_types[i].type) { zlog_warn("internal error: route type table out of order " "while searching for %u, please notify developers", zroute); return &route_types[i]; } } zlog_err("internal error: cannot find route type %u in table!", zroute); return &unknown; } const char * zebra_route_string(u_int zroute) { return zroute_lookup(zroute)->string; } char zebra_route_char(u_int zroute) { return zroute_lookup(zroute)->chr; } const char * zserv_command_string (unsigned int command) { if (command >= array_size(command_types)) { zlog_err ("unknown zserv command type: %u", command); return unknown.string; } return command_types[command].string; } int proto_name2num(const char *s) { unsigned i; for (i=0; i= len) /* end of block, not really printing */ s += sprintf(s, " "); else if(isprint((int)((char*)mem)[j])) /* printable char */ s += sprintf(s, "%c", 0xFF & ((char*)mem)[j]); else /* other char */ s += sprintf(s, "."); } s += sprintf(s, "\n"); } } zlog_debug("\n%s", buf); } quagga-1.2.4/lib/log.h000066400000000000000000000177051325323223500144750ustar00rootroot00000000000000/* * 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 #include /* Here is some guidance on logging levels to use: * * LOG_DEBUG - For all messages that are enabled by optional debugging * features, typically preceded by "if (IS...DEBUG...)" * LOG_INFO - Information that may be of interest, but everything seems * to be working properly. * LOG_NOTICE - Only for message pertaining to daemon startup or shutdown. * LOG_WARNING - Warning conditions: unexpected events, but the daemon believes * it can continue to operate correctly. * LOG_ERR - Error situations indicating malfunctions. Probably require * attention. * * Note: LOG_CRIT, LOG_ALERT, and LOG_EMERG are currently not used anywhere, * please use LOG_ERR instead. */ typedef enum { ZLOG_NONE, ZLOG_DEFAULT, ZLOG_ZEBRA, ZLOG_RIP, ZLOG_BGP, ZLOG_OSPF, ZLOG_RIPNG, ZLOG_BABEL, ZLOG_OSPF6, ZLOG_ISIS, ZLOG_PIM, ZLOG_MASC, ZLOG_NHRP, } zlog_proto_t; /* If maxlvl is set to ZLOG_DISABLED, then no messages will be sent to that logging destination. */ #define ZLOG_DISABLED (LOG_EMERG-1) typedef enum { ZLOG_DEST_SYSLOG = 0, ZLOG_DEST_STDOUT, ZLOG_DEST_MONITOR, ZLOG_DEST_FILE } zlog_dest_t; #define ZLOG_NUM_DESTS (ZLOG_DEST_FILE+1) struct zlog { const char *ident; /* daemon name (first arg to openlog) */ zlog_proto_t protocol; int maxlvl[ZLOG_NUM_DESTS]; /* maximum priority to send to associated logging destination */ int default_lvl; /* maxlvl to use if none is specified */ FILE *fp; char *filename; int facility; /* as per syslog facility */ int record_priority; /* should messages logged through stdio include the priority of the message? */ int syslog_options; /* 2nd arg to openlog */ int timestamp_precision; /* # of digits of subsecond precision */ }; /* Message structure. */ struct message { int key; const char *str; }; /* Default logging strucutre. */ extern struct zlog *zlog_default; /* Open zlog function */ extern struct zlog *openzlog (const char *progname, zlog_proto_t protocol, int syslog_options, int syslog_facility); /* Close zlog function. */ extern 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. */ extern void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); /* Handy zlog functions. */ extern void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); extern void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); extern void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); extern void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); extern void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); /* For bgpd's peer oriented log. */ extern void plog_err (struct zlog *, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); extern void plog_warn (struct zlog *, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); extern void plog_info (struct zlog *, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); extern void plog_notice (struct zlog *, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); extern void plog_debug (struct zlog *, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); extern void zlog_thread_info (int log_level); /* Set logging level for the given destination. If the log_level argument is ZLOG_DISABLED, then the destination is disabled. This function should not be used for file logging (use zlog_set_file or zlog_reset_file instead). */ extern void zlog_set_level (struct zlog *zl, zlog_dest_t, int log_level); /* Set logging to the given filename at the specified level. */ extern int zlog_set_file (struct zlog *zl, const char *filename, int log_level); /* Disable file logging. */ extern int zlog_reset_file (struct zlog *zl); /* Rotate log. */ extern int zlog_rotate (struct zlog *); /* For hackey message lookup and check */ #define LOOKUP_DEF(x, y, def) mes_lookup(x, x ## _max, y, def, #x) #define LOOKUP(x, y) LOOKUP_DEF(x, y, "(no item found)") extern const char *lookup (const struct message *, int); extern const char *mes_lookup (const struct message *meslist, int max, int index, const char *no_item, const char *mesname); extern const char *zlog_priority[]; extern const char *zlog_proto_names[]; /* Safe version of strerror -- never returns NULL. */ extern const char *safe_strerror(int errnum); /* To be called when a fatal signal is caught. */ extern void zlog_signal(int signo, const char *action #ifdef SA_SIGINFO , siginfo_t *siginfo, void *program_counter #endif ); /* Log a backtrace. */ extern void zlog_backtrace(int priority); /* Log a backtrace, but in an async-signal-safe way. Should not be called unless the program is about to exit or abort, since it messes up the state of zlog file pointers. If program_counter is non-NULL, that is logged in addition to the current backtrace. */ extern void zlog_backtrace_sigsafe(int priority, void *program_counter); /* Puts a current timestamp in buf and returns the number of characters written (not including the terminating NUL). The purpose of this function is to avoid calls to localtime appearing all over the code. It caches the most recent localtime result and can therefore avoid multiple calls within the same second. If buflen is too small, *buf will be set to '\0', and 0 will be returned. */ #define QUAGGA_TIMESTAMP_LEN 40 extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */, char *buf, size_t buflen); extern void zlog_hexdump(void *mem, unsigned int len); /* structure useful for avoiding repeated rendering of the same timestamp */ struct timestamp_control { size_t len; /* length of rendered timestamp */ int precision; /* configuration parameter */ int already_rendered; /* should be initialized to 0 */ char buf[QUAGGA_TIMESTAMP_LEN]; /* will contain the rendered timestamp */ }; /* Defines for use in command construction: */ #define LOG_LEVELS "(emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)" #define LOG_LEVEL_DESC \ "System is unusable\n" \ "Immediate action needed\n" \ "Critical conditions\n" \ "Error conditions\n" \ "Warning conditions\n" \ "Normal but significant conditions\n" \ "Informational messages\n" \ "Debugging messages\n" #define LOG_FACILITIES "(kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)" #define LOG_FACILITY_DESC \ "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" #endif /* _ZEBRA_LOG_H */ quagga-1.2.4/lib/md5.c000066400000000000000000000305301325323223500143630ustar00rootroot00000000000000/* $USAGI: md5.c,v 1.2 2000/11/02 11:59:24 yoshfuji Exp $ */ /* $KAME: md5.c,v 1.2 2000/05/27 07:07:48 jinmei Exp $ */ /* $Id: md5.c,v 1.6 2006/01/17 23:39:04 vincent Exp $ */ /* * Copyright (C) 2004 6WIND * * All rights reserved. * * This MD5 code is Big endian and Little Endian compatible. */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "md5.h" #define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s)))) #define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z))) #define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z))) #define H(X, Y, Z) ((X) ^ (Y) ^ (Z)) #define I(X, Y, Z) ((Y) ^ ((X) | (~Z))) #define ROUND1(a, b, c, d, k, s, i) { \ (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \ (a) = SHIFT((a), (s)); \ (a) = (b) + (a); \ } #define ROUND2(a, b, c, d, k, s, i) { \ (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \ (a) = SHIFT((a), (s)); \ (a) = (b) + (a); \ } #define ROUND3(a, b, c, d, k, s, i) { \ (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \ (a) = SHIFT((a), (s)); \ (a) = (b) + (a); \ } #define ROUND4(a, b, c, d, k, s, i) { \ (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \ (a) = SHIFT((a), (s)); \ (a) = (b) + (a); \ } #define Sa 7 #define Sb 12 #define Sc 17 #define Sd 22 #define Se 5 #define Sf 9 #define Sg 14 #define Sh 20 #define Si 4 #define Sj 11 #define Sk 16 #define Sl 23 #define Sm 6 #define Sn 10 #define So 15 #define Sp 21 #define MD5_A0 0x67452301 #define MD5_B0 0xefcdab89 #define MD5_C0 0x98badcfe #define MD5_D0 0x10325476 /* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */ static const uint32_t T[65] = { 0, 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static const uint8_t md5_paddat[MD5_BUFLEN] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static void md5_calc (const uint8_t *, md5_ctxt *); void md5_init(md5_ctxt *ctxt) { ctxt->md5_n = 0; ctxt->md5_i = 0; ctxt->md5_sta = MD5_A0; ctxt->md5_stb = MD5_B0; ctxt->md5_stc = MD5_C0; ctxt->md5_std = MD5_D0; memset (ctxt->md5_buf, 0, sizeof(ctxt->md5_buf)); } void md5_loop(md5_ctxt *ctxt, const void *vinput, uint len) { uint gap, i; const uint8_t *input = vinput; ctxt->md5_n += len * 8; /* byte to bit */ gap = MD5_BUFLEN - ctxt->md5_i; if (len >= gap) { memcpy (ctxt->md5_buf + ctxt->md5_i, input, gap); md5_calc(ctxt->md5_buf, ctxt); for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) { md5_calc((input + i), ctxt); } ctxt->md5_i = len - i; memcpy (ctxt->md5_buf, (input + i), ctxt->md5_i); } else { memcpy (ctxt->md5_buf + ctxt->md5_i, input, len); ctxt->md5_i += len; } } void md5_pad(md5_ctxt *ctxt) { uint gap; /* Don't count up padding. Keep md5_n. */ gap = MD5_BUFLEN - ctxt->md5_i; if (gap > 8) { memcpy (ctxt->md5_buf + ctxt->md5_i, md5_paddat, gap - sizeof(ctxt->md5_n)); } else { /* including gap == 8 */ memcpy (ctxt->md5_buf + ctxt->md5_i, md5_paddat, gap); md5_calc (ctxt->md5_buf, ctxt); memcpy (ctxt->md5_buf, md5_paddat + gap, MD5_BUFLEN - sizeof(ctxt->md5_n)); } /* 8 byte word */ if (BYTE_ORDER == LITTLE_ENDIAN) memcpy (&ctxt->md5_buf[56], &ctxt->md5_n8[0], 8); else { ctxt->md5_buf[56] = ctxt->md5_n8[7]; ctxt->md5_buf[57] = ctxt->md5_n8[6]; ctxt->md5_buf[58] = ctxt->md5_n8[5]; ctxt->md5_buf[59] = ctxt->md5_n8[4]; ctxt->md5_buf[60] = ctxt->md5_n8[3]; ctxt->md5_buf[61] = ctxt->md5_n8[2]; ctxt->md5_buf[62] = ctxt->md5_n8[1]; ctxt->md5_buf[63] = ctxt->md5_n8[0]; } md5_calc(ctxt->md5_buf, ctxt); } void md5_result(uint8_t *digest, md5_ctxt *ctxt) { /* 4 byte words */ if (BYTE_ORDER == LITTLE_ENDIAN) memcpy (digest, &ctxt->md5_st8[0], 16); else if (BYTE_ORDER == BIG_ENDIAN) { digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2]; digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0]; digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6]; digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4]; digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10]; digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8]; digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14]; digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12]; } } static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt) { uint32_t A = ctxt->md5_sta; uint32_t B = ctxt->md5_stb; uint32_t C = ctxt->md5_stc; uint32_t D = ctxt->md5_std; #if (BYTE_ORDER == LITTLE_ENDIAN) const uint32_t *X = (const uint32_t *)b64; #elif (BYTE_ORDER == BIG_ENDIAN) uint32_t X[16]; if (BYTE_ORDER == BIG_ENDIAN) { /* 4 byte words */ /* what a brute force but fast! */ uint8_t *y = (uint8_t *)X; y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0]; y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4]; y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8]; y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12]; y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16]; y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20]; y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24]; y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28]; y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32]; y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36]; y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40]; y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44]; y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48]; y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52]; y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56]; y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60]; } #endif ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2); ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4); ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6); ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8); ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10); ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12); ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14); ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16); ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18); ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20); ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22); ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24); ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26); ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28); ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30); ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32); ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34); ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36); ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38); ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40); ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42); ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44); ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46); ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48); ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64); ctxt->md5_sta += A; ctxt->md5_stb += B; ctxt->md5_stc += C; ctxt->md5_std += D; } /* From RFC 2104 */ void hmac_md5(text, text_len, key, key_len, digest) unsigned char* text; /* pointer to data stream */ int text_len; /* length of data stream */ unsigned char* key; /* pointer to authentication key */ int key_len; /* length of authentication key */ uint8_t * digest; /* caller digest to be filled in */ { MD5_CTX context; unsigned char k_ipad[65]; /* inner padding - * key XORd with ipad */ unsigned char k_opad[65]; /* outer padding - * key XORd with opad */ unsigned char tk[16]; int i; /* if key is longer than 64 bytes reset it to key=MD5(key) */ if (key_len > 64) { MD5_CTX tctx; MD5Init(&tctx); MD5Update(&tctx, key, key_len); MD5Final(tk, &tctx); key = tk; key_len = 16; } /* * the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in pads */ bzero( k_ipad, sizeof k_ipad); bzero( k_opad, sizeof k_opad); bcopy( key, k_ipad, key_len); bcopy( key, k_opad, key_len); /* XOR key with ipad and opad values */ for (i=0; i<64; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; } /* * perform inner MD5 */ MD5Init(&context); /* init context for 1st * pass */ MD5Update(&context, k_ipad, 64); /* start with inner pad */ MD5Update(&context, text, text_len); /* then text of datagram */ MD5Final(digest, &context); /* finish up 1st pass */ /* * perform outer MD5 */ MD5Init(&context); /* init context for 2nd * pass */ MD5Update(&context, k_opad, 64); /* start with outer pad */ MD5Update(&context, digest, 16); /* then results of 1st * hash */ MD5Final(digest, &context); /* finish up 2nd pass */ } quagga-1.2.4/lib/md5.h000066400000000000000000000057521325323223500144000ustar00rootroot00000000000000/* $USAGI: md5.h,v 1.2 2000/11/02 11:59:25 yoshfuji Exp $ */ /* $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */ /* $Id: md5.h,v 1.3 2006/01/17 17:40:45 paul Exp $ */ /* * Copyright (C) 2004 6WIND * * All rights reserved. * * This MD5 code is Big endian and Little Endian compatible. */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _LIBZEBRA_MD5_H_ #define _LIBZEBRA_MD5_H_ #define MD5_BUFLEN 64 typedef struct { union { uint32_t md5_state32[4]; uint8_t md5_state8[16]; } md5_st; #define md5_sta md5_st.md5_state32[0] #define md5_stb md5_st.md5_state32[1] #define md5_stc md5_st.md5_state32[2] #define md5_std md5_st.md5_state32[3] #define md5_st8 md5_st.md5_state8 union { uint64_t md5_count64; uint8_t md5_count8[8]; } md5_count; #define md5_n md5_count.md5_count64 #define md5_n8 md5_count.md5_count8 uint md5_i; uint8_t md5_buf[MD5_BUFLEN]; } md5_ctxt; extern void md5_init (md5_ctxt *); extern void md5_loop (md5_ctxt *, const void *, u_int); extern void md5_pad (md5_ctxt *); extern void md5_result (uint8_t *, md5_ctxt *); /* compatibility */ #define MD5_CTX md5_ctxt #define MD5Init(x) md5_init((x)) #define MD5Update(x, y, z) md5_loop((x), (y), (z)) #define MD5Final(x, y) \ do { \ md5_pad((y)); \ md5_result((x), (y)); \ } while (0) /* From RFC 2104 */ void hmac_md5(unsigned char* text, int text_len, unsigned char* key, int key_len, uint8_t *digest); #endif /* ! _LIBZEBRA_MD5_H_*/ quagga-1.2.4/lib/memory.c000066400000000000000000000263401325323223500152120ustar00rootroot00000000000000/* * 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 /* malloc.h is generally obsolete, however GNU Libc mallinfo wants it. */ #if !defined(HAVE_STDLIB_H) || (defined(GNU_LINUX) && defined(HAVE_MALLINFO)) #include #endif /* !HAVE_STDLIB_H || HAVE_MALLINFO */ #include "log.h" #include "memory.h" static void alloc_inc (int); static void alloc_dec (int); static void log_memstats(int log_priority); static const 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 occurred. */ static void __attribute__ ((noreturn)) zerror (const char *fname, int type, size_t size) { zlog_err ("%s : can't allocate memory for `%s' size %d: %s\n", fname, lookup (mstr, type), (int) size, safe_strerror(errno)); log_memstats(LOG_WARNING); /* N.B. It might be preferable to call zlog_backtrace_sigsafe here, since that function should definitely be safe in an OOM condition. But unfortunately zlog_backtrace_sigsafe does not support syslog logging at this time... */ zlog_backtrace(LOG_WARNING); abort(); } /* * Allocate memory of a given size, to be tracked by a given type. * Effects: Returns a pointer to usable memory. If memory cannot * be allocated, aborts execution. */ void * zmalloc (int type, size_t size) { void *memory; memory = malloc (size); if (memory == NULL) zerror ("malloc", type, size); alloc_inc (type); return memory; } /* * Allocate memory as in zmalloc, and also clear the memory. * Add an extra 'z' prefix to function name to avoid collision when linking * statically with zlib that exports the 'zcalloc' symbol. */ void * zzcalloc (int type, size_t size) { void *memory; memory = calloc (1, size); if (memory == NULL) zerror ("calloc", type, size); alloc_inc (type); return memory; } /* * Given a pointer returned by zmalloc or zzcalloc, free it and * return a pointer to a new size, basically acting like realloc(). * Requires: ptr was returned by zmalloc, zzcalloc, or zrealloc with the * same type. * Effects: Returns a pointer to the new memory, or aborts. */ void * zrealloc (int type, void *ptr, size_t size) { void *memory; if (ptr == NULL) /* is really alloc */ return zzcalloc(type, size); memory = realloc (ptr, size); if (memory == NULL) zerror ("realloc", type, size); if (ptr == NULL) alloc_inc (type); return memory; } /* * Free memory allocated by z*alloc or zstrdup. * Requires: ptr was returned by zmalloc, zzcalloc, or zrealloc with the * same type. * Effects: The memory is freed and may no longer be referenced. */ void zfree (int type, void *ptr) { if (ptr != NULL) { alloc_dec (type); free (ptr); } } /* * Duplicate a string, counting memory usage by type. * Effects: The string is duplicated, and the return value must * eventually be passed to zfree with the same type. The function will * succeed or abort. */ char * zstrdup (int type, const char *str) { void *dup; dup = strdup (str); if (dup == NULL) zerror ("strdup", type, strlen (str)); alloc_inc (type); return dup; } #ifdef MEMORY_LOG static struct { const char *name; 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]; static void mtype_log (char *func, void *memory, const char *file, int line, int type) { zlog_debug ("%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 = zzcalloc (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, const char *str) { char *memory; mstat[type].c_strdup++; memory = zstrdup (type, str); mtype_log ("xstrdup", memory, file, line, type); return memory; } #else static struct { char *name; long alloc; } mstat [MTYPE_MAX]; #endif /* MEMORY_LOG */ /* Increment allocation counter. */ static void alloc_inc (int type) { mstat[type].alloc++; } /* Decrement allocation counter. */ static void alloc_dec (int type) { mstat[type].alloc--; } /* Looking up memory status from vty interface. */ #include "vector.h" #include "vty.h" #include "command.h" static void log_memstats(int pri) { struct mlist *ml; for (ml = mlists; ml->list; ml++) { struct memory_list *m; zlog (NULL, pri, "Memory utilization in module %s:", ml->name); for (m = ml->list; m->index >= 0; m++) if (m->index && mstat[m->index].alloc) zlog (NULL, pri, " %-30s: %10ld", m->format, mstat[m->index].alloc); } } void log_memstats_stderr (const char *prefix) { struct mlist *ml; struct memory_list *m; int i; int j = 0; for (ml = mlists; ml->list; ml++) { i = 0; for (m = ml->list; m->index >= 0; m++) if (m->index && mstat[m->index].alloc) { if (!i) fprintf (stderr, "%s: memstats: Current memory utilization in module %s:\n", prefix, ml->name); fprintf (stderr, "%s: memstats: %-30s: %10ld%s\n", prefix, m->format, mstat[m->index].alloc, mstat[m->index].alloc < 0 ? " (REPORT THIS BUG!)" : ""); i = j = 1; } } if (j) fprintf (stderr, "%s: memstats: NOTE: If configuration exists, utilization may be " "expected.\n", prefix); else fprintf (stderr, "%s: memstats: No remaining tracked memory utilization.\n", prefix); } static void show_separator(struct vty *vty) { vty_out (vty, "-----------------------------\r\n"); } static int show_memory_vty (struct vty *vty, struct memory_list *list) { struct memory_list *m; int needsep = 0; for (m = list; m->index >= 0; m++) if (m->index == 0) { if (needsep) { show_separator (vty); needsep = 0; } } else if (mstat[m->index].alloc) { vty_out (vty, "%-30s: %10ld\r\n", m->format, mstat[m->index].alloc); needsep = 1; } return needsep; } #ifdef HAVE_MALLINFO static int show_memory_mallinfo (struct vty *vty) { struct mallinfo minfo = mallinfo(); char buf[MTYPE_MEMSTR_LEN]; vty_out (vty, "System allocator statistics:%s", VTY_NEWLINE); vty_out (vty, " Total heap allocated: %s%s", mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.arena), VTY_NEWLINE); vty_out (vty, " Holding block headers: %s%s", mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.hblkhd), VTY_NEWLINE); vty_out (vty, " Used small blocks: %s%s", mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.usmblks), VTY_NEWLINE); vty_out (vty, " Used ordinary blocks: %s%s", mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.uordblks), VTY_NEWLINE); vty_out (vty, " Free small blocks: %s%s", mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fsmblks), VTY_NEWLINE); vty_out (vty, " Free ordinary blocks: %s%s", mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fordblks), VTY_NEWLINE); vty_out (vty, " Ordinary blocks: %ld%s", (unsigned long)minfo.ordblks, VTY_NEWLINE); vty_out (vty, " Small blocks: %ld%s", (unsigned long)minfo.smblks, VTY_NEWLINE); vty_out (vty, " Holding blocks: %ld%s", (unsigned long)minfo.hblks, VTY_NEWLINE); vty_out (vty, "(see system documentation for 'mallinfo' for meaning)%s", VTY_NEWLINE); return 1; } #endif /* HAVE_MALLINFO */ DEFUN (show_memory, show_memory_cmd, "show memory", "Show running system information\n" "Memory statistics\n") { struct mlist *ml; int needsep = 0; #ifdef HAVE_MALLINFO needsep = show_memory_mallinfo (vty); #endif /* HAVE_MALLINFO */ for (ml = mlists; ml->list; ml++) { if (needsep) show_separator (vty); needsep = show_memory_vty (vty, ml->list); } return CMD_SUCCESS; } void memory_init (void) { install_element (RESTRICTED_NODE, &show_memory_cmd); install_element (VIEW_NODE, &show_memory_cmd); } /* Stats querying from users */ /* Return a pointer to a human friendly string describing * the byte count passed in. E.g: * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc. * Up to 4 significant figures will be given. * The pointer returned may be NULL (indicating an error) * or point to the given buffer, or point to static storage. */ const char * mtype_memstr (char *buf, size_t len, unsigned long bytes) { unsigned int m, k; /* easy cases */ if (!bytes) return "0 bytes"; if (bytes == 1) return "1 byte"; /* * When we pass the 2gb barrier mallinfo() can no longer report * correct data so it just does something odd... * Reporting like Terrabytes of data. Which makes users... * edgy.. yes edgy that's the term for it. * So let's just give up gracefully */ if (bytes > 0x7fffffff) return "> 2GB"; m = bytes >> 20; k = bytes >> 10; if (m > 10) { if (bytes & (1 << 19)) m++; snprintf (buf, len, "%d MiB", m); } else if (k > 10) { if (bytes & (1 << 9)) k++; snprintf (buf, len, "%d KiB", k); } else snprintf (buf, len, "%ld bytes", bytes); return buf; } unsigned long mtype_stats_alloc (int type) { return mstat[type].alloc; } quagga-1.2.4/lib/memory.h000066400000000000000000000062441325323223500152200ustar00rootroot00000000000000/* 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 array_size(ar) (sizeof(ar) / sizeof(ar[0])) /* For pretty printing of memory allocate information. */ struct memory_list { int index; const char *format; }; struct mlist { struct memory_list *list; const char *name; }; #include "lib/memtypes.h" extern struct mlist mlists[]; /* #define MEMORY_LOG */ #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) \ do { \ mtype_zfree (__FILE__, __LINE__, (mtype), (ptr)); \ (ptr) = NULL; } \ while (0) #define XSTRDUP(mtype, str) \ mtype_zstrdup (__FILE__, __LINE__, (mtype), (str)) #else #define XMALLOC(mtype, size) zmalloc ((mtype), (size)) #define XCALLOC(mtype, size) zzcalloc ((mtype), (size)) #define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size)) #define XFREE(mtype, ptr) do { \ zfree ((mtype), (ptr)); \ (ptr) = NULL; } \ while (0) #define XSTRDUP(mtype, str) zstrdup ((mtype), (str)) #endif /* MEMORY_LOG */ /* Prototypes of memory function. */ extern void *zmalloc (int type, size_t size); extern void *zzcalloc (int type, size_t size); extern void *zrealloc (int type, void *ptr, size_t size); extern void zfree (int type, void *ptr); extern char *zstrdup (int type, const char *str); extern void *mtype_zmalloc (const char *file, int line, int type, size_t size); extern void *mtype_zcalloc (const char *file, int line, int type, size_t size); extern void *mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size); extern void mtype_zfree (const char *file, int line, int type, void *ptr); extern char *mtype_zstrdup (const char *file, int line, int type, const char *str); extern void memory_init (void); extern void log_memstats_stderr (const char *); /* return number of allocations outstanding for the type */ extern unsigned long mtype_stats_alloc (int); /* Human friendly string for given byte count */ #define MTYPE_MEMSTR_LEN 20 extern const char *mtype_memstr (char *, size_t, unsigned long); #endif /* _ZEBRA_MEMORY_H */ quagga-1.2.4/lib/memtypes.awk000066400000000000000000000056151325323223500161070ustar00rootroot00000000000000### # Copyright (C) Paul Jakma 2005 # # This file is part of Quagga. # # Quagga is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any # later version. # # Quagga is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Quagga; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. ### # # Scan a file of memory definitions (see eg memtypes.c) and generate # a corresponding header file with an enum of the MTYPE's and declarations # for the struct memory_list arrays # # struct memory_list's must be declared as: # '\nstruct memory_list memory_list_[] .....' # # Each MTYPE_ within the definition must the second token on the line, # tokens being delineated by whitespace. It may only consist of the set of # characters [[:upper:]_[:digit:]]. Eg: # # '\n { MTYPE_AWESOME_IPV8 , "Amazing new protocol, says genius" {}..boo' # # We try to ignore lines whose first token is /* or *, ie C comment lines. # So the following should work fine: # # '/* This is the best memory_list ever! # ' * It's got all my MTYPE's */ # ' # 'struct memory_list memory_list_my_amazing_mlist[] = = # '{ # ' { MTYPE_DONGLE, "Dongle widget" } # ' { MTYPE_FROB, "Frobulator" }, # '{ MTYPE_WIPPLE, "Wipple combombulator"} # '}}} # # Even if it isn't quite a valid C declaration. # BEGIN { mlistregex = "memory_list_(.*)\\[\\]"; mtyperegex = "^(MTYPE_[[:upper:]_[:digit:]]+).*"; header = "/* Auto-generated from memtypes.c by " ARGV[0] ". */\n"; header = header "/* Do not edit! */\n"; header = header "\n#ifndef _QUAGGA_MEMTYPES_H\n"; header = header "#define _QUAGGA_MEMTYPES_H\n"; footer = "\n#endif /* _QUAGGA_MEMTYPES_H */\n\n"; mlistformat = "extern struct memory_list memory_list_%s[];"; printf ("%s\n", header); } # catch lines beginning with 'struct memory list ' and try snag the # memory_list name. Has to be 3rd field. ($0 ~ /^struct memory_list /) && (NF >= 3) { mlists[lcount++] = gensub(mlistregex, "\\1", "g",$3); } # snag the MTYPE, it must self-standing and the second field, # though we do manage to tolerate the , C seperator being appended ($1 !~ /^\/?\*/) && ($2 ~ /^MTYPE_/) { mtype[tcount++] = gensub(mtyperegex, "\\1", "g", $2); } END { printf("enum\n{\n MTYPE_TMP = 1,\n"); for (i = 0; i < tcount; i++) { if (mtype[i] != "" && mtype[i] != "MTYPE_TMP") printf (" %s,\n", mtype[i]); } printf (" MTYPE_MAX,\n};\n\n"); for (i = 0; i < lcount; i++) { if (mlists[i] != "") printf (mlistformat "\n", mlists[i]); } printf (footer); } quagga-1.2.4/lib/memtypes.c000066400000000000000000000302711325323223500155430ustar00rootroot00000000000000/* * Memory type definitions. This file is parsed by memtypes.awk to extract * MTYPE_ and memory_list_.. information in order to autogenerate * memtypes.h. * * The script is sensitive to the format (though not whitespace), see * the top of memtypes.awk for more details. */ #include "zebra.h" #include "memory.h" struct memory_list memory_list_lib[] = { { MTYPE_TMP, "Temporary memory" }, { MTYPE_STRVEC, "String vector" }, { MTYPE_VECTOR, "Vector" }, { MTYPE_VECTOR_INDEX, "Vector index" }, { MTYPE_LINK_LIST, "Link List" }, { MTYPE_LINK_NODE, "Link Node" }, { MTYPE_THREAD, "Thread" }, { MTYPE_THREAD_MASTER, "Thread master" }, { MTYPE_THREAD_STATS, "Thread stats" }, { MTYPE_VTY, "VTY" }, { MTYPE_VTY_OUT_BUF, "VTY output buffer" }, { MTYPE_VTY_HIST, "VTY history" }, { MTYPE_IF, "Interface" }, { MTYPE_CONNECTED, "Connected" }, { MTYPE_CONNECTED_LABEL, "Connected interface label" }, { MTYPE_BUFFER, "Buffer" }, { MTYPE_BUFFER_DATA, "Buffer data" }, { MTYPE_STREAM, "Stream" }, { MTYPE_STREAM_DATA, "Stream data" }, { MTYPE_STREAM_FIFO, "Stream FIFO" }, { MTYPE_PREFIX, "Prefix" }, { MTYPE_PREFIX_IPV4, "Prefix IPv4" }, { MTYPE_PREFIX_IPV6, "Prefix IPv6" }, { MTYPE_HASH, "Hash" }, { MTYPE_HASH_BACKET, "Hash Bucket" }, { MTYPE_HASH_INDEX, "Hash Index" }, { MTYPE_ROUTE_TABLE, "Route table" }, { MTYPE_ROUTE_NODE, "Route node" }, { MTYPE_DISTRIBUTE, "Distribute list" }, { MTYPE_DISTRIBUTE_IFNAME, "Dist-list ifname" }, { 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_ENTRY, "Prefix List Entry" }, { MTYPE_PREFIX_LIST_STR, "Prefix List Str" }, { 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_ROUTE_MAP_COMPILED, "Route map compiled" }, { MTYPE_CMD_TOKENS, "Command desc" }, { MTYPE_KEY, "Key" }, { MTYPE_KEYCHAIN, "Key chain" }, { MTYPE_IF_RMAP, "Interface route map" }, { MTYPE_IF_RMAP_NAME, "I.f. route map name", }, { MTYPE_SOCKUNION, "Socket union" }, { MTYPE_PRIVS, "Privilege information" }, { MTYPE_ZLOG, "Logging" }, { MTYPE_ZCLIENT, "Zclient" }, { MTYPE_WORK_QUEUE, "Work queue" }, { MTYPE_WORK_QUEUE_ITEM, "Work queue item" }, { MTYPE_WORK_QUEUE_NAME, "Work queue name string" }, { MTYPE_PQUEUE, "Priority queue" }, { MTYPE_PQUEUE_DATA, "Priority queue data" }, { MTYPE_HOST, "Host config" }, { MTYPE_VRF, "VRF" }, { MTYPE_VRF_NAME, "VRF name" }, { MTYPE_VRF_BITMAP, "VRF bit-map" }, { MTYPE_IF_LINK_PARAMS, "Informational Link Parameters" }, { -1, NULL }, }; struct memory_list memory_list_zebra[] = { { MTYPE_RTADV_PREFIX, "Router Advertisement Prefix" }, { MTYPE_ZEBRA_VRF, "ZEBRA VRF" }, { MTYPE_NEXTHOP, "Nexthop" }, { MTYPE_RIB, "RIB" }, { MTYPE_RIB_QUEUE, "RIB process work queue" }, { MTYPE_STATIC_ROUTE, "Static route" }, { MTYPE_RIB_DEST, "RIB destination" }, { MTYPE_RIB_TABLE_INFO, "RIB table info" }, { MTYPE_NETLINK_NAME, "Netlink name" }, { MTYPE_NETLINK_RCVBUF, "Netlink receive buffer" }, { MTYPE_RNH, "Nexthop tracking object" }, { -1, NULL }, }; struct memory_list memory_list_bgp[] = { { MTYPE_BGP, "BGP instance" }, { MTYPE_BGP_LISTENER, "BGP listen socket details" }, { MTYPE_BGP_PEER, "BGP peer" }, { MTYPE_BGP_PEER_HOST, "BGP peer hostname" }, { MTYPE_PEER_GROUP, "Peer group" }, { MTYPE_PEER_DESC, "Peer description" }, { MTYPE_PEER_PASSWORD, "Peer password string" }, { MTYPE_ATTR, "BGP attribute" }, { MTYPE_ATTR_EXTRA, "BGP extra attributes" }, { MTYPE_AS_PATH, "BGP aspath" }, { MTYPE_AS_SEG, "BGP aspath seg" }, { MTYPE_AS_SEG_DATA, "BGP aspath segment data" }, { MTYPE_AS_STR, "BGP aspath str" }, { 0, NULL }, { MTYPE_BGP_TABLE, "BGP table" }, { MTYPE_BGP_NODE, "BGP node" }, { MTYPE_BGP_ROUTE, "BGP route" }, { MTYPE_BGP_ROUTE_EXTRA, "BGP ancillary route info" }, { MTYPE_BGP_CONN, "BGP connected" }, { MTYPE_BGP_STATIC, "BGP static" }, { MTYPE_BGP_ADVERTISE_ATTR, "BGP adv attr" }, { MTYPE_BGP_ADVERTISE, "BGP adv" }, { MTYPE_BGP_SYNCHRONISE, "BGP synchronise" }, { MTYPE_BGP_ADJ_IN, "BGP adj in" }, { MTYPE_BGP_ADJ_OUT, "BGP adj out" }, { MTYPE_BGP_MPATH_INFO, "BGP multipath info" }, { 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" }, { MTYPE_COMMUNITY_LIST_HANDLER, "community-list handler" }, { 0, NULL }, { MTYPE_CLUSTER, "Cluster list" }, { MTYPE_CLUSTER_VAL, "Cluster list val" }, { 0, NULL }, { MTYPE_BGP_PROCESS_QUEUE, "BGP Process queue" }, { MTYPE_BGP_CLEAR_NODE_QUEUE, "BGP node clear queue" }, { 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, "BGP peer update interface" }, { MTYPE_BGP_DAMP_INFO, "Dampening info" }, { MTYPE_BGP_DAMP_ARRAY, "BGP Dampening array" }, { MTYPE_BGP_REGEXP, "BGP regexp" }, { MTYPE_BGP_AGGREGATE, "BGP aggregate" }, { MTYPE_BGP_ADDR, "BGP own address" }, { MTYPE_ENCAP_TLV, "ENCAP TLV", }, { MTYPE_LCOMMUNITY, "Large Community", }, { MTYPE_LCOMMUNITY_STR, "Large Community str", }, { MTYPE_LCOMMUNITY_VAL, "Large Community val", }, { -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_ripng[] = { { MTYPE_RIPNG, "RIPng structure" }, { MTYPE_RIPNG_ROUTE, "RIPng route info" }, { MTYPE_RIPNG_AGGREGATE, "RIPng aggregate" }, { MTYPE_RIPNG_PEER, "RIPng peer" }, { MTYPE_RIPNG_OFFSET_LIST, "RIPng offset lst" }, { MTYPE_RIPNG_RTE_DATA, "RIPng rte data" }, { -1, NULL } }; struct memory_list memory_list_babel[] = { { MTYPE_BABEL, "Babel structure" }, { MTYPE_BABEL_IF, "Babel interface" }, { -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" }, { MTYPE_OSPF_NEIGHBOR_STATIC,"OSPF static nbr" }, { 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_VERTEX_PARENT, "OSPF vertex parent", }, { 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" }, { MTYPE_OSPF_MESSAGE, "OSPF message" }, { MTYPE_OSPF_MPLS_TE, "OSPF MPLS parameters" }, { MTYPE_OSPF_PCE_PARAMS, "OSPF PCE parameters" }, { -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" }, { MTYPE_OSPF6_DISTANCE, "OSPF6 distance" }, { -1, NULL }, }; struct memory_list memory_list_isis[] = { { MTYPE_ISIS, "ISIS" }, { MTYPE_ISIS_TMP, "ISIS TMP" }, { MTYPE_ISIS_CIRCUIT, "ISIS circuit" }, { MTYPE_ISIS_LSP, "ISIS LSP" }, { MTYPE_ISIS_ADJACENCY, "ISIS adjacency" }, { MTYPE_ISIS_AREA, "ISIS area" }, { MTYPE_ISIS_AREA_ADDR, "ISIS area address" }, { MTYPE_ISIS_TLV, "ISIS TLV" }, { MTYPE_ISIS_DYNHN, "ISIS dyn hostname" }, { MTYPE_ISIS_SPFTREE, "ISIS SPFtree" }, { MTYPE_ISIS_VERTEX, "ISIS vertex" }, { MTYPE_ISIS_ROUTE_INFO, "ISIS route info" }, { MTYPE_ISIS_NEXTHOP, "ISIS nexthop" }, { MTYPE_ISIS_NEXTHOP6, "ISIS nexthop6" }, { MTYPE_ISIS_DICT, "ISIS dictionary" }, { MTYPE_ISIS_DICT_NODE, "ISIS dictionary node" }, { MTYPE_ISIS_MPLS_TE, "ISIS MPLS_TE parameters" }, { -1, NULL }, }; struct memory_list memory_list_pim[] = { { MTYPE_PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL" }, { MTYPE_PIM_INTERFACE, "PIM interface" }, { MTYPE_PIM_IGMP_JOIN, "PIM interface IGMP static join" }, { MTYPE_PIM_IGMP_SOCKET, "PIM interface IGMP socket" }, { MTYPE_PIM_IGMP_GROUP, "PIM interface IGMP group" }, { MTYPE_PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source" }, { MTYPE_PIM_NEIGHBOR, "PIM interface neighbor" }, { MTYPE_PIM_IFCHANNEL, "PIM interface (S,G) state" }, { MTYPE_PIM_UPSTREAM, "PIM upstream (S,G) state" }, { MTYPE_PIM_SSMPINGD, "PIM sspimgd socket" }, { MTYPE_PIM_STATIC_ROUTE, "PIM Static Route" }, { -1, NULL }, }; struct memory_list memory_list_nhrp[] = { { MTYPE_NHRP_IF, "NHRP interface" }, { MTYPE_NHRP_VC, "NHRP virtual connection" }, { MTYPE_NHRP_PEER, "NHRP peer entry" }, { MTYPE_NHRP_CACHE, "NHRP cache entry" }, { MTYPE_NHRP_NHS, "NHRP next hop server" }, { MTYPE_NHRP_REGISTRATION, "NHRP registration entries" }, { MTYPE_NHRP_SHORTCUT, "NHRP shortcut" }, { MTYPE_NHRP_ROUTE, "NHRP routing entry" }, { -1, NULL } }; struct memory_list memory_list_vtysh[] = { { MTYPE_VTYSH_CONFIG, "Vtysh configuration", }, { MTYPE_VTYSH_CONFIG_LINE, "Vtysh configuration line" }, { -1, NULL }, }; struct mlist mlists[] __attribute__ ((unused)) = { { memory_list_lib, "LIB" }, { memory_list_zebra, "ZEBRA" }, { memory_list_rip, "RIP" }, { memory_list_ripng, "RIPNG" }, { memory_list_ospf, "OSPF" }, { memory_list_ospf6, "OSPF6" }, { memory_list_isis, "ISIS" }, { memory_list_bgp, "BGP" }, { memory_list_pim, "PIM" }, { memory_list_nhrp, "NHRP" }, { NULL, NULL}, }; quagga-1.2.4/lib/memtypes.h000066400000000000000000000125661325323223500155570ustar00rootroot00000000000000/* Auto-generated from memtypes.c by gawk. */ /* Do not edit! */ #ifndef _QUAGGA_MEMTYPES_H #define _QUAGGA_MEMTYPES_H enum { MTYPE_TMP = 1, MTYPE_STRVEC, MTYPE_VECTOR, MTYPE_VECTOR_INDEX, MTYPE_LINK_LIST, MTYPE_LINK_NODE, MTYPE_THREAD, MTYPE_THREAD_MASTER, MTYPE_THREAD_STATS, MTYPE_VTY, MTYPE_VTY_OUT_BUF, MTYPE_VTY_HIST, MTYPE_IF, MTYPE_CONNECTED, MTYPE_CONNECTED_LABEL, 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_BACKET, MTYPE_HASH_INDEX, MTYPE_ROUTE_TABLE, MTYPE_ROUTE_NODE, MTYPE_DISTRIBUTE, MTYPE_DISTRIBUTE_IFNAME, MTYPE_ACCESS_LIST, MTYPE_ACCESS_LIST_STR, MTYPE_ACCESS_FILTER, MTYPE_PREFIX_LIST, MTYPE_PREFIX_LIST_ENTRY, MTYPE_PREFIX_LIST_STR, 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_CMD_TOKENS, MTYPE_KEY, MTYPE_KEYCHAIN, MTYPE_IF_RMAP, MTYPE_IF_RMAP_NAME, MTYPE_SOCKUNION, MTYPE_PRIVS, MTYPE_ZLOG, MTYPE_ZCLIENT, MTYPE_WORK_QUEUE, MTYPE_WORK_QUEUE_ITEM, MTYPE_WORK_QUEUE_NAME, MTYPE_PQUEUE, MTYPE_PQUEUE_DATA, MTYPE_HOST, MTYPE_VRF, MTYPE_VRF_NAME, MTYPE_VRF_BITMAP, MTYPE_IF_LINK_PARAMS, MTYPE_RTADV_PREFIX, MTYPE_ZEBRA_VRF, MTYPE_NEXTHOP, MTYPE_RIB, MTYPE_RIB_QUEUE, MTYPE_STATIC_ROUTE, MTYPE_RIB_DEST, MTYPE_RIB_TABLE_INFO, MTYPE_NETLINK_NAME, MTYPE_NETLINK_RCVBUF, MTYPE_RNH, MTYPE_BGP, MTYPE_BGP_LISTENER, MTYPE_BGP_PEER, MTYPE_BGP_PEER_HOST, MTYPE_PEER_GROUP, MTYPE_PEER_DESC, MTYPE_PEER_PASSWORD, MTYPE_ATTR, MTYPE_ATTR_EXTRA, MTYPE_AS_PATH, MTYPE_AS_SEG, MTYPE_AS_SEG_DATA, MTYPE_AS_STR, MTYPE_BGP_TABLE, MTYPE_BGP_NODE, MTYPE_BGP_ROUTE, MTYPE_BGP_ROUTE_EXTRA, MTYPE_BGP_CONN, MTYPE_BGP_STATIC, MTYPE_BGP_ADVERTISE_ATTR, MTYPE_BGP_ADVERTISE, MTYPE_BGP_SYNCHRONISE, MTYPE_BGP_ADJ_IN, MTYPE_BGP_ADJ_OUT, MTYPE_BGP_MPATH_INFO, MTYPE_AS_LIST, MTYPE_AS_FILTER, MTYPE_AS_FILTER_STR, MTYPE_COMMUNITY, MTYPE_COMMUNITY_VAL, MTYPE_COMMUNITY_STR, MTYPE_ECOMMUNITY, MTYPE_ECOMMUNITY_VAL, MTYPE_ECOMMUNITY_STR, MTYPE_COMMUNITY_LIST, MTYPE_COMMUNITY_LIST_NAME, MTYPE_COMMUNITY_LIST_ENTRY, MTYPE_COMMUNITY_LIST_CONFIG, MTYPE_COMMUNITY_LIST_HANDLER, MTYPE_CLUSTER, MTYPE_CLUSTER_VAL, MTYPE_BGP_PROCESS_QUEUE, MTYPE_BGP_CLEAR_NODE_QUEUE, MTYPE_TRANSIT, MTYPE_TRANSIT_VAL, MTYPE_BGP_DISTANCE, MTYPE_BGP_NEXTHOP_CACHE, MTYPE_BGP_CONFED_LIST, MTYPE_PEER_UPDATE_SOURCE, MTYPE_BGP_DAMP_INFO, MTYPE_BGP_DAMP_ARRAY, MTYPE_BGP_REGEXP, MTYPE_BGP_AGGREGATE, MTYPE_BGP_ADDR, MTYPE_ENCAP_TLV, MTYPE_LCOMMUNITY, MTYPE_LCOMMUNITY_STR, MTYPE_LCOMMUNITY_VAL, MTYPE_RIP, MTYPE_RIP_INFO, MTYPE_RIP_INTERFACE, MTYPE_RIP_PEER, MTYPE_RIP_OFFSET_LIST, MTYPE_RIP_DISTANCE, MTYPE_RIPNG, MTYPE_RIPNG_ROUTE, MTYPE_RIPNG_AGGREGATE, MTYPE_RIPNG_PEER, MTYPE_RIPNG_OFFSET_LIST, MTYPE_RIPNG_RTE_DATA, MTYPE_BABEL, MTYPE_BABEL_IF, 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_VERTEX_PARENT, MTYPE_OSPF_NEXTHOP, MTYPE_OSPF_PATH, MTYPE_OSPF_VL_DATA, MTYPE_OSPF_CRYPT_KEY, MTYPE_OSPF_EXTERNAL_INFO, MTYPE_OSPF_DISTANCE, MTYPE_OSPF_IF_INFO, MTYPE_OSPF_IF_PARAMS, MTYPE_OSPF_MESSAGE, MTYPE_OSPF_MPLS_TE, MTYPE_OSPF_PCE_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_OSPF6_DISTANCE, MTYPE_ISIS, MTYPE_ISIS_TMP, MTYPE_ISIS_CIRCUIT, MTYPE_ISIS_LSP, MTYPE_ISIS_ADJACENCY, MTYPE_ISIS_AREA, MTYPE_ISIS_AREA_ADDR, MTYPE_ISIS_TLV, MTYPE_ISIS_DYNHN, MTYPE_ISIS_SPFTREE, MTYPE_ISIS_VERTEX, MTYPE_ISIS_ROUTE_INFO, MTYPE_ISIS_NEXTHOP, MTYPE_ISIS_NEXTHOP6, MTYPE_ISIS_DICT, MTYPE_ISIS_DICT_NODE, MTYPE_ISIS_MPLS_TE, MTYPE_PIM_CHANNEL_OIL, MTYPE_PIM_INTERFACE, MTYPE_PIM_IGMP_JOIN, MTYPE_PIM_IGMP_SOCKET, MTYPE_PIM_IGMP_GROUP, MTYPE_PIM_IGMP_GROUP_SOURCE, MTYPE_PIM_NEIGHBOR, MTYPE_PIM_IFCHANNEL, MTYPE_PIM_UPSTREAM, MTYPE_PIM_SSMPINGD, MTYPE_PIM_STATIC_ROUTE, MTYPE_NHRP_IF, MTYPE_NHRP_VC, MTYPE_NHRP_PEER, MTYPE_NHRP_CACHE, MTYPE_NHRP_NHS, MTYPE_NHRP_REGISTRATION, MTYPE_NHRP_SHORTCUT, MTYPE_NHRP_ROUTE, MTYPE_VTYSH_CONFIG, MTYPE_VTYSH_CONFIG_LINE, MTYPE_MAX, }; extern struct memory_list memory_list_lib[]; extern struct memory_list memory_list_zebra[]; extern struct memory_list memory_list_bgp[]; extern struct memory_list memory_list_rip[]; extern struct memory_list memory_list_ripng[]; extern struct memory_list memory_list_babel[]; extern struct memory_list memory_list_ospf[]; extern struct memory_list memory_list_ospf6[]; extern struct memory_list memory_list_isis[]; extern struct memory_list memory_list_pim[]; extern struct memory_list memory_list_nhrp[]; extern struct memory_list memory_list_vtysh[]; #endif /* _QUAGGA_MEMTYPES_H */ quagga-1.2.4/lib/network.c000066400000000000000000000046421325323223500153740ustar00rootroot00000000000000/* * 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 #include "log.h" #include "network.h" /* Read nbytes from fd and store into ptr. */ int readn (int fd, u_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, const u_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; } int set_nonblocking(int fd) { int flags; /* According to the Single UNIX Spec, the return value for F_GETFL should never be negative. */ if ((flags = fcntl(fd, F_GETFL)) < 0) { zlog_warn("fcntl(F_GETFL) failed for fd %d: %s", fd, safe_strerror(errno)); return -1; } if (fcntl(fd, F_SETFL, (flags | O_NONBLOCK)) < 0) { zlog_warn("fcntl failed setting fd %d non-blocking: %s", fd, safe_strerror(errno)); return -1; } return 0; } float htonf (float host) { #if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 0 #warning "Unknown floating-point format on platform, htonf may break" #endif u_int32_t lu1, lu2; float convert; memcpy (&lu1, &host, sizeof (u_int32_t)); lu2 = htonl (lu1); memcpy (&convert, &lu2, sizeof (u_int32_t)); return convert; } float ntohf (float net) { return htonf (net); } quagga-1.2.4/lib/network.h000066400000000000000000000027311325323223500153760ustar00rootroot00000000000000/* * 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 /* Both readn and writen are deprecated and will be removed. They are not suitable for use with non-blocking file descriptors. */ extern int readn (int, u_char *, int); extern int writen (int, const u_char *, int); /* Set the file descriptor to use non-blocking I/O. Returns 0 for success, -1 on error. */ extern int set_nonblocking(int fd); /* Does the I/O error indicate that the operation should be retried later? */ #define ERRNO_IO_RETRY(EN) \ (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) extern float htonf (float); extern float ntohf (float); #endif /* _ZEBRA_NETWORK_H */ quagga-1.2.4/lib/nexthop.c000066400000000000000000000077241325323223500153740ustar00rootroot00000000000000/* A generic nexthop structure * Copyright (C) 2013 Cumulus Networks, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "linklist.h" #include "thread.h" #include "prefix.h" #include "nexthop.h" /* check if nexthops are same, non-recursive */ int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2) { if (next1->type != next2->type) return 0; switch (next1->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) return 0; if (next1->ifindex && (next1->ifindex != next2->ifindex)) return 0; break; case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: if (next1->ifindex != next2->ifindex) return 0; break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) return 0; break; case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_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 */ default: /* do nothing */ break; } return 1; } /* * nexthop_type_to_str */ const char * nexthop_type_to_str (enum nexthop_types_t nh_type) { static const char *desc[] = { "none", "Directly connected", "Interface route", "IPv4 nexthop", "IPv4 nexthop with ifindex", "IPv4 nexthop with ifname", "IPv6 nexthop", "IPv6 nexthop with ifindex", "IPv6 nexthop with ifname", "Null0 nexthop", }; if (nh_type >= ZEBRA_NUM_OF (desc)) return ""; return desc[nh_type]; } struct nexthop * nexthop_new (void) { return XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); } /* Add nexthop to the end of a nexthop list. */ void nexthop_add (struct nexthop **target, struct nexthop *nexthop) { struct nexthop *last; for (last = *target; last && last->next; last = last->next) ; if (last) last->next = nexthop; else *target = nexthop; nexthop->prev = last; } void copy_nexthops (struct nexthop **tnh, struct nexthop *nh) { struct nexthop *nexthop; struct nexthop *nh1; for (nh1 = nh; nh1; nh1 = nh1->next) { nexthop = nexthop_new(); nexthop->flags = nh->flags; nexthop->type = nh->type; nexthop->ifindex = nh->ifindex; if (nh->ifname) nexthop->ifname = XSTRDUP(0, nh->ifname); memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); nexthop_add(tnh, nexthop); if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE)) copy_nexthops(&nexthop->resolved, nh1->resolved); } } /* Free nexthop. */ void nexthop_free (struct nexthop *nexthop) { if (nexthop->ifname) XFREE (0, nexthop->ifname); if (nexthop->resolved) nexthops_free(nexthop->resolved); XFREE (MTYPE_NEXTHOP, nexthop); } /* Frees a list of nexthops */ void nexthops_free (struct nexthop *nexthop) { struct nexthop *nh, *next; for (nh = nexthop; nh; nh = next) { next = nh->next; nexthop_free (nh); } } quagga-1.2.4/lib/nexthop.h000066400000000000000000000057471325323223500154040ustar00rootroot00000000000000/* * Nexthop structure definition. * Copyright (C) 1997, 98, 99, 2001 Kunihiro Ishiguro * Copyright (C) 2013 Cumulus Networks, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _LIB_NEXTHOP_H #define _LIB_NEXTHOP_H #include "prefix.h" union g_addr { struct in_addr ipv4; #ifdef HAVE_IPV6 struct in6_addr ipv6; #endif /* HAVE_IPV6 */ }; enum nexthop_types_t { NEXTHOP_TYPE_IFINDEX = 1, /* Directly connected. */ NEXTHOP_TYPE_IFNAME, /* Interface route. */ NEXTHOP_TYPE_IPV4, /* IPv4 nexthop. */ NEXTHOP_TYPE_IPV4_IFINDEX, /* IPv4 nexthop with ifindex. */ NEXTHOP_TYPE_IPV4_IFNAME, /* IPv4 nexthop with ifname. */ NEXTHOP_TYPE_IPV6, /* IPv6 nexthop. */ NEXTHOP_TYPE_IPV6_IFINDEX, /* IPv6 nexthop with ifindex. */ NEXTHOP_TYPE_IPV6_IFNAME, /* IPv6 nexthop with ifname. */ NEXTHOP_TYPE_BLACKHOLE, /* Null0 nexthop. */ }; /* Nexthop structure. */ struct nexthop { struct nexthop *next; struct nexthop *prev; /* Interface index. */ char *ifname; ifindex_t ifindex; enum nexthop_types_t type; 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. */ #define NEXTHOP_FLAG_ONLINK (1 << 3) /* Nexthop should be installed onlink. */ #define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */ /* Nexthop address */ union g_addr gate; union g_addr src; /* Nexthops obtained by recursive resolution. * * If the nexthop struct needs to be resolved recursively, * NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops * obtained by recursive resolution will be added to `resolved'. * Only one level of recursive resolution is currently supported. */ struct nexthop *resolved; }; struct nexthop *nexthop_new (void); void nexthop_add (struct nexthop **target, struct nexthop *nexthop); void copy_nexthops (struct nexthop **tnh, struct nexthop *nh); void nexthop_free (struct nexthop *nexthop); void nexthops_free (struct nexthop *nexthop); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2); #endif /*_LIB_NEXTHOP_H */ quagga-1.2.4/lib/pid_output.c000066400000000000000000000052351325323223500160760ustar00rootroot00000000000000/* * 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 #include #include #include "version.h" #define PIDFILE_MASK 0644 #ifndef HAVE_FCNTL pid_t pid_output (const char *path) { FILE *fp; pid_t pid; mode_t oldumask; pid = getpid(); oldumask = umask(0777 & ~PIDFILE_MASK); fp = fopen (path, "w"); if (fp != NULL) { fprintf (fp, "%d\n", (int) pid); fclose (fp); umask(oldumask); return pid; } /* XXX Why do we continue instead of exiting? This seems incompatible with the behavior of the fcntl version below. */ zlog_warn("Can't fopen pid lock file %s (%s), continuing", path, safe_strerror(errno)); umask(oldumask); return -1; } #else /* HAVE_FCNTL */ pid_t pid_output (const char *path) { int tmp; int fd; pid_t pid; char buf[16]; struct flock lock; mode_t oldumask; pid = getpid (); oldumask = umask(0777 & ~PIDFILE_MASK); fd = open (path, O_RDWR | O_CREAT, PIDFILE_MASK); if (fd < 0) { zlog_err("Can't create pid lock file %s (%s), exiting", path, safe_strerror(errno)); umask(oldumask); exit(1); } else { size_t pidsize; umask(oldumask); memset (&lock, 0, sizeof(lock)); lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; if (fcntl(fd, F_SETLK, &lock) < 0) { zlog_err("Could not lock pid_file %s, exiting", path); exit(1); } sprintf (buf, "%d\n", (int) pid); pidsize = strlen(buf); if ((tmp = write (fd, buf, pidsize)) != (int)pidsize) zlog_err("Could not write pid %d to pid_file %s, rc was %d: %s", (int)pid,path,tmp,safe_strerror(errno)); else if (ftruncate(fd, pidsize) < 0) zlog_err("Could not truncate pid_file %s to %u bytes: %s", path,(u_int)pidsize,safe_strerror(errno)); } return pid; } #endif /* HAVE_FCNTL */ quagga-1.2.4/lib/plist.c000066400000000000000000002254111325323223500150350ustar00rootroot00000000000000/* 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" #include "stream.h" #include "log.h" #include "plist_int.h" /* 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) (struct prefix_list *); /* Hook function which is executed when prefix_list is deleted. */ void (*delete_hook) (struct prefix_list *); }; /* 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_v4 = { {NULL, NULL}, {NULL, NULL}, 1, NULL, NULL, }; /* Static structure of BGP ORF prefix_list's master. */ static struct prefix_master prefix_master_orf_v6 = { {NULL, NULL}, {NULL, NULL}, 1, NULL, NULL, }; static struct prefix_master * prefix_master_get (afi_t afi, int orf) { if (afi == AFI_IP) return orf ? &prefix_master_orf_v4 : &prefix_master_ipv4; if (afi == AFI_IP6) return orf ? &prefix_master_orf_v6 : &prefix_master_ipv6; return NULL; } const char *prefix_list_name (struct prefix_list *plist) { return plist->name; } /* Lookup prefix_list from list of prefix_list by name. */ static struct prefix_list * prefix_list_lookup_do (afi_t afi, int orf, const char *name) { struct prefix_list *plist; struct prefix_master *master; if (name == NULL) return NULL; master = prefix_master_get (afi, orf); 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_lookup (afi_t afi, const char *name) { return prefix_list_lookup_do (afi, 0, name); } struct prefix_list * prefix_bgp_orf_lookup (afi_t afi, const char *name) { return prefix_list_lookup_do (afi, 1, name); } static struct prefix_list * prefix_list_new (void) { struct prefix_list *new; new = XCALLOC (MTYPE_PREFIX_LIST, sizeof (struct prefix_list)); return new; } static void prefix_list_free (struct prefix_list *plist) { XFREE (MTYPE_PREFIX_LIST, plist); } static struct prefix_list_entry * prefix_list_entry_new (void) { struct prefix_list_entry *new; new = XCALLOC (MTYPE_PREFIX_LIST_ENTRY, sizeof (struct prefix_list_entry)); return new; } static 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. */ static struct prefix_list * prefix_list_insert (afi_t afi, int orf, const char *name) { unsigned 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, orf); 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; } static struct prefix_list * prefix_list_get (afi_t afi, int orf, const char *name) { struct prefix_list *plist; plist = prefix_list_lookup_do (afi, orf, name); if (plist == NULL) plist = prefix_list_insert (afi, orf, name); return plist; } /* Delete prefix-list from prefix_list_master and free it. */ static 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) (NULL); } static 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. */ static 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. */ static 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; } static 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; } static 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; } } static 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 const char * prefix_list_type_str (struct prefix_list_entry *pentry) { switch (pentry->type) { case PREFIX_PERMIT: return "permit"; case PREFIX_DENY: return "deny"; default: return ""; } } static 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; } static void __attribute__ ((unused)) 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. */ static 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; } static int vty_invalid_prefix_range (struct vty *vty, const char *prefix) { vty_out (vty, "%% Invalid prefix range for %s, make sure: len < ge-value <= le-value%s", prefix, VTY_NEWLINE); return CMD_WARNING; } static int vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, const char *seq, const char *typestr, const char *prefix, const char *ge, const 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; /* This code only works for IP. Provide a safe-guard and user-visible * warning */ if (!(afi == AFI_IP || afi == AFI_IP6)) { vty_out (vty, "%% prefix must be IPv4 or IPv6!%s", VTY_NEWLINE); return CMD_WARNING; } /* 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. */ switch (afi) { case 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; } break; case 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; } break; case AFI_ETHER: default: vty_out (vty, "%% Unrecognized AFI (%d)%s", afi, VTY_NEWLINE); return CMD_WARNING; break; } /* 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, 0, 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; } static int vty_prefix_list_uninstall (struct vty *vty, afi_t afi, const char *name, const char *seq, const char *typestr, const char *prefix, const char *ge, const 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; } /* We must have, at a minimum, both the type and prefix here */ if ((typestr == NULL) || (prefix == NULL)) { vty_out (vty, "%% Both prefix and type required%s", VTY_NEWLINE); return CMD_WARNING; } /* 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; } static int vty_prefix_list_desc_unset (struct vty *vty, afi_t afi, const 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 }; static 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; /* Print the name of the protocol */ if (zlog_default) vty_out (vty, "%s: ", zlog_proto_names[zlog_default->protocol]); 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); } } } static int vty_show_prefix_list (struct vty *vty, afi_t afi, const char *name, const char *seq, enum display_type dtype) { struct prefix_list *plist; struct prefix_master *master; int seqnum = 0; master = prefix_master_get (afi, 0); 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; } static int vty_show_prefix_list_prefix (struct vty *vty, afi_t afi, const char *name, const 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; } static int vty_clear_prefix_list (struct vty *vty, afi_t afi, const char *name, const 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, 0); 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; plist = prefix_list_get (AFI_IP, 0, argv[0]); if (plist->desc) { XFREE (MTYPE_TMP, plist->desc); plist->desc = NULL; } plist->desc = argv_concat(argv, argc, 1); 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; plist = prefix_list_get (AFI_IP6, 0, argv[0]); if (plist->desc) { XFREE (MTYPE_TMP, plist->desc); plist->desc = NULL; } plist->desc = argv_concat(argv, argc, 1); 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. */ static 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, 0); 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; } 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, 1, 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 (afi_t afi, char *name) { struct prefix_list *plist; plist = prefix_bgp_orf_lookup (afi, 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_bgp_orf_lookup (afi, 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; } static void prefix_list_reset_afi (afi_t afi, int orf) { struct prefix_list *plist; struct prefix_list *next; struct prefix_master *master; master = prefix_master_get (afi, orf); 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. */ static struct cmd_node prefix_node = { PREFIX_NODE, "", /* Prefix list has no interface. */ 1 }; static int config_write_prefix_ipv4 (struct vty *vty) { return config_write_prefix_afi (AFI_IP, vty); } static void prefix_list_init_ipv4 (void) { 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, &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); } /* Prefix-list node. */ static struct cmd_node prefix_ipv6_node = { PREFIX_IPV6_NODE, "", /* Prefix list has no interface. */ 1 }; static int config_write_prefix_ipv6 (struct vty *vty) { return config_write_prefix_afi (AFI_IP6, vty); } static void prefix_list_init_ipv6 (void) { 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, &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); } 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_afi (AFI_IP, 0); prefix_list_reset_afi (AFI_IP6, 0); prefix_list_reset_afi (AFI_IP, 1); prefix_list_reset_afi (AFI_IP6, 1); } quagga-1.2.4/lib/plist.h000066400000000000000000000037221325323223500150410ustar00rootroot00000000000000/* * 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. */ #ifndef _QUAGGA_PLIST_H #define _QUAGGA_PLIST_H enum prefix_list_type { PREFIX_DENY, PREFIX_PERMIT, }; struct prefix_list; struct orf_prefix { u_int32_t seq; u_char ge; u_char le; struct prefix p; }; /* Prototypes. */ extern void prefix_list_init (void); extern void prefix_list_reset (void); extern void prefix_list_add_hook (void (*func) (struct prefix_list *)); extern void prefix_list_delete_hook (void (*func) (struct prefix_list *)); extern const char *prefix_list_name (struct prefix_list *); extern struct prefix_list *prefix_list_lookup (afi_t, const char *); extern enum prefix_list_type prefix_list_apply (struct prefix_list *, void *); extern struct prefix_list *prefix_bgp_orf_lookup (afi_t, const char *); extern struct stream * prefix_bgp_orf_entry (struct stream *, struct prefix_list *, u_char, u_char, u_char); extern int prefix_bgp_orf_set (char *, afi_t, struct orf_prefix *, int, int); extern void prefix_bgp_orf_remove_all (afi_t, char *); extern int prefix_bgp_show_prefix_list (struct vty *, afi_t, char *); #endif /* _QUAGGA_PLIST_H */ quagga-1.2.4/lib/plist_int.h000066400000000000000000000030261325323223500157100ustar00rootroot00000000000000/* * Prefix list internal definitions. * 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 _QUAGGA_PLIST_INT_H #define _QUAGGA_PLIST_INT_H 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; }; /* 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; }; #endif /* _QUAGGA_PLIST_INT_H */ quagga-1.2.4/lib/pqueue.c000066400000000000000000000121051325323223500152000ustar00rootroot00000000000000/* 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 "memory.h" #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) 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)]; if (queue->update != NULL) (*queue->update) (queue->array[index], index); index = PARENT_OF (index); } /* Restore the tmp node to appropriate place. */ queue->array[index] = tmp; if (queue->update != NULL) (*queue->update) (tmp, index); } 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]; if (queue->update != NULL) (*queue->update) (queue->array[index], index); index = which; } /* Restore the tmp node to appropriate place. */ queue->array[index] = tmp; if (queue->update != NULL) (*queue->update) (tmp, index); } struct pqueue * pqueue_create (void) { struct pqueue *queue; queue = XCALLOC (MTYPE_PQUEUE, sizeof (struct pqueue)); queue->array = XCALLOC (MTYPE_PQUEUE_DATA, DATA_SIZE * PQUEUE_INIT_ARRAYSIZE); queue->array_size = PQUEUE_INIT_ARRAYSIZE; /* By default we want nothing to happen when a node changes. */ queue->update = NULL; return queue; } void pqueue_delete (struct pqueue *queue) { XFREE (MTYPE_PQUEUE_DATA, queue->array); XFREE (MTYPE_PQUEUE, queue); } static int pqueue_expand (struct pqueue *queue) { void **newarray; newarray = XCALLOC (MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2); if (newarray == NULL) return 0; memcpy (newarray, queue->array, queue->array_size * DATA_SIZE); XFREE (MTYPE_PQUEUE_DATA, 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; if (queue->update != NULL) (*queue->update) (data, queue->size); 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; } void pqueue_remove_at (int index, struct pqueue *queue) { queue->array[index] = queue->array[--queue->size]; if (index > 0 && (*queue->cmp) (queue->array[index], queue->array[PARENT_OF(index)]) < 0) { trickle_up (index, queue); } else { trickle_down (index, queue); } } quagga-1.2.4/lib/pqueue.h000066400000000000000000000026371325323223500152160ustar00rootroot00000000000000/* 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 *); void (*update) (void * node, int actual_position); }; #define PQUEUE_INIT_ARRAYSIZE 32 extern struct pqueue *pqueue_create (void); extern void pqueue_delete (struct pqueue *queue); extern void pqueue_enqueue (void *data, struct pqueue *queue); extern void *pqueue_dequeue (struct pqueue *queue); extern void pqueue_remove_at (int index, struct pqueue *queue); extern void trickle_down (int index, struct pqueue *queue); extern void trickle_up (int index, struct pqueue *queue); #endif /* _ZEBRA_PQUEUE_H */ quagga-1.2.4/lib/prefix.c000066400000000000000000001062301325323223500151740ustar00rootroot00000000000000/* * 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 const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; static const struct in6_addr maskbytes6[] = { /* /0 */ { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /1 */ { { { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /2 */ { { { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /3 */ { { { 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /4 */ { { { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /5 */ { { { 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /6 */ { { { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /7 */ { { { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /8 */ { { { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /9 */ { { { 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /10 */ { { { 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /11 */ { { { 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /12 */ { { { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /13 */ { { { 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /14 */ { { { 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /15 */ { { { 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /16 */ { { { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /17 */ { { { 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /18 */ { { { 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /19 */ { { { 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /20 */ { { { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /21 */ { { { 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /22 */ { { { 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /23 */ { { { 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /24 */ { { { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /25 */ { { { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /26 */ { { { 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /27 */ { { { 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /28 */ { { { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /29 */ { { { 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /30 */ { { { 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /31 */ { { { 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /32 */ { { { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /33 */ { { { 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /34 */ { { { 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /35 */ { { { 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /36 */ { { { 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /37 */ { { { 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /38 */ { { { 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /39 */ { { { 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /40 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /41 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /42 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /43 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /44 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /45 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /46 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /47 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /48 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /49 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /50 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /51 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /52 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /53 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /54 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /55 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /56 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /57 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /58 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /59 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /60 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /61 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /62 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /63 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /64 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /65 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /66 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /67 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /68 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /69 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /70 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /71 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /72 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /73 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /74 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /75 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /76 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /77 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /78 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /79 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /80 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /81 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /82 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /83 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /84 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /85 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /86 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /87 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /88 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, /* /89 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 } } }, /* /90 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 } } }, /* /91 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00 } } }, /* /92 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } } }, /* /93 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00 } } }, /* /94 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00 } } }, /* /95 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00 } } }, /* /96 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } }, /* /97 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00 } } }, /* /98 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00 } } }, /* /99 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00 } } }, /* /100 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 } } }, /* /101 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00 } } }, /* /102 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00 } } }, /* /103 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00 } } }, /* /104 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } } }, /* /105 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 } } }, /* /106 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00 } } }, /* /107 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00 } } }, /* /108 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 } } }, /* /109 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00 } } }, /* /110 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00 } } }, /* /111 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00 } } }, /* /112 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } } }, /* /113 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00 } } }, /* /114 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 } } }, /* /115 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00 } } }, /* /116 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 } } }, /* /117 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00 } } }, /* /118 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 } } }, /* /119 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00 } } }, /* /120 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 } } }, /* /121 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 } } }, /* /122 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 } } }, /* /123 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0 } } }, /* /124 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 } } }, /* /125 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8 } } }, /* /126 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc } } }, /* /127 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe } } }, /* /128 */ { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } } }; /* Number of bits in prefix type. */ #ifndef PNBBY #define PNBBY 8 #endif /* PNBBY */ #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen) { unsigned int offset = prefixlen / 8; unsigned int shift = 7 - (prefixlen % 8); return (prefix[offset] >> shift) & 1; } unsigned int prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen) { return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen); } int str2family(const char *string) { if (!strcmp("ipv4", string)) return AF_INET; else if (!strcmp("ipv6", string)) return AF_INET6; else if (!strcmp("ethernet", string)) return AF_ETHERNET; return -1; } /* Address Famiy Identifier to Address Family converter. */ int afi2family (afi_t afi) { if (afi == AFI_IP) return AF_INET; #ifdef HAVE_IPV6 else if (afi == AFI_IP6) return AF_INET6; #endif /* HAVE_IPV6 */ else if (afi == AFI_ETHER) return AF_ETHERNET; return 0; } afi_t family2afi (int family) { if (family == AF_INET) return AFI_IP; #ifdef HAVE_IPV6 else if (family == AF_INET6) return AFI_IP6; #endif /* HAVE_IPV6 */ else if (family == AF_ETHERNET) return AFI_ETHER; return 0; } const char * afi2str(afi_t afi) { switch (afi) { case AFI_IP: return "IPv4"; case AFI_IP6: return "IPv6"; case AFI_ETHER: return "ethernet"; } return NULL; } const char * safi2str(safi_t safi) { switch (safi) { case SAFI_UNICAST: return "unicast"; case SAFI_MULTICAST: return "multicast"; case SAFI_ENCAP: return "encap"; case SAFI_MPLS_VPN: return "vpn"; } return NULL; } /* If n includes p prefix then return 1 else return 0. */ int prefix_match (const struct prefix *n, const struct prefix *p) { int offset; int shift; const u_char *np, *pp; /* If n's prefix is longer than p's one return 0. */ if (n->prefixlen > p->prefixlen) return 0; /* Set both prefix's head pointer. */ np = (const u_char *)&n->u.prefix; pp = (const u_char *)&p->u.prefix; 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, const 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 if (src->family == AF_ETHERNET) { dest->u.prefix_eth = src->u.prefix_eth; } else { zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d", src->family); assert (0); } } /* * Return 1 if the address/netmask contained in the prefix structure * is the same, and else return 0. For this routine, 'same' requires * that not only the prefix length and the network part be the same, * but also the host part. Thus, 10.0.0.1/8 and 10.0.0.2/8 are not * the same. Note that this routine has the same return value sense * as '==' (which is different from prefix_cmp). */ int prefix_same (const struct prefix *p1, const struct prefix *p2) { if (p1->family == p2->family && p1->prefixlen == p2->prefixlen) { if (p1->family == AF_INET) if (IPV4_ADDR_SAME (&p1->u.prefix4.s_addr, &p2->u.prefix4.s_addr)) return 1; #ifdef HAVE_IPV6 if (p1->family == AF_INET6 ) if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr)) return 1; #endif /* HAVE_IPV6 */ if (p1->family == AF_ETHERNET) { if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN)) return 1; } } return 0; } /* * Return 0 if the network prefixes represented by the struct prefix * arguments are the same prefix, and 1 otherwise. Network prefixes * are considered the same if the prefix lengths are equal and the * network parts are the same. Host bits (which are considered masked * by the prefix length) are not significant. Thus, 10.0.0.1/8 and * 10.0.0.2/8 are considered equivalent by this routine. Note that * this routine has the same return sense as strcmp (which is different * from prefix_same). */ int prefix_cmp (const struct prefix *p1, const struct prefix *p2) { int offset; int shift; /* Set both prefix's head pointer. */ const u_char *pp1 = (const u_char *)&p1->u.prefix; const u_char *pp2 = (const u_char *)&p2->u.prefix; if (p1->family != p2->family || p1->prefixlen != p2->prefixlen) return 1; offset = p1->prefixlen / PNBBY; shift = p1->prefixlen % PNBBY; if (shift) if (maskbit[shift] & (pp1[offset] ^ pp2[offset])) return 1; while (offset--) if (pp1[offset] != pp2[offset]) return 1; return 0; } /* * Count the number of common bits in 2 prefixes. The prefix length is * ignored for this function; the whole prefix is compared. If the prefix * address families don't match, return -1; otherwise the return value is * in range 0 ... maximum prefix length for the address family. */ int prefix_common_bits (const struct prefix *p1, const struct prefix *p2) { int pos, bit; int length = 0; u_char xor; /* Set both prefix's head pointer. */ const u_char *pp1 = (const u_char *)&p1->u.prefix; const u_char *pp2 = (const u_char *)&p2->u.prefix; if (p1->family == AF_INET) length = IPV4_MAX_BYTELEN; #ifdef HAVE_IPV6 if (p1->family == AF_INET6) length = IPV6_MAX_BYTELEN; #endif if (p1->family != p2->family || !length) return -1; for (pos = 0; pos < length; pos++) if (pp1[pos] != pp2[pos]) break; if (pos == length) return pos * 8; xor = pp1[pos] ^ pp2[pos]; for (bit = 0; bit < 8; bit++) if (xor & (1 << (7 - bit))) break; return pos * 8 + bit; } /* Return prefix family type string. */ const char * prefix_family_str (const struct prefix *p) { if (p->family == AF_INET) return "inet"; #ifdef HAVE_IPV6 if (p->family == AF_INET6) return "inet6"; #endif /* HAVE_IPV6 */ if (p->family == AF_ETHERNET) return "ether"; return "unspec"; } /* Allocate new prefix_ipv4 structure. */ struct prefix_ipv4 * prefix_ipv4_new () { struct prefix_ipv4 *p; /* Call prefix_new to allocate a full-size struct prefix to avoid problems where the struct prefix_ipv4 is cast to struct prefix and unallocated bytes were being referenced (e.g. in structure assignments). */ p = (struct prefix_ipv4 *)prefix_new(); p->family = AF_INET; return p; } /* Free prefix_ipv4 structure. */ void prefix_ipv4_free (struct prefix_ipv4 *p) { prefix_free((struct prefix *)p); } /* When string format is invalid return 0. */ int str2prefix_ipv4 (const 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 > IPV4_MAX_PREFIXLEN) return 0; p->family = AF_INET; p->prefixlen = plen; } return ret; } /* When string format is invalid return 0. */ int str2prefix_eth (const char *str, struct prefix_eth *p) { int ret = 0; int plen = 48; char *pnt; char *cp = NULL; const char *str_addr = str; unsigned int a[6]; int i; /* Find slash inside string. */ pnt = strchr (str, '/'); if (pnt) { /* Get prefix length. */ plen = (u_char) atoi (++pnt); if (plen > 48) { ret = 0; goto done; } cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1); strncpy (cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; str_addr = cp; } /* Convert string to prefix. */ if (sscanf(str_addr, "%2x:%2x:%2x:%2x:%2x:%2x", a+0, a+1, a+2, a+3, a+4, a+5) != 6) { ret = 0; goto done; } for (i = 0; i < 6; ++i) { p->eth_addr.octet[i] = a[i] & 0xff; } p->prefixlen = plen; p->family = AF_ETHERNET; ret = 1; done: if (cp) XFREE (MTYPE_TMP, cp); return ret; } /* Convert masklen into IP address's netmask (network byte order). */ void masklen2ip (const int masklen, struct in_addr *netmask) { assert (masklen >= 0 && masklen <= IPV4_MAX_BITLEN); /* left shift is only defined for less than the size of the type. * we unconditionally use long long in case the target platform * has defined behaviour for << 32 (or has a 64-bit left shift) */ if (sizeof(unsigned long long) > 4) netmask->s_addr = htonl(0xffffffffULL << (32 - masklen)); else netmask->s_addr = htonl(masklen ? 0xffffffffU << (32 - masklen) : 0); } /* 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) { uint32_t tmp = ~ntohl(netmask.s_addr); if (tmp) /* clz: count leading zeroes. sadly, the behaviour of this builtin * is undefined for a 0 argument, even though most CPUs give 32 */ return __builtin_clz(tmp); else return 32; } /* Apply mask to IPv4 prefix (network byte order). */ void apply_mask_ipv4 (struct prefix_ipv4 *p) { struct in_addr mask; masklen2ip(p->prefixlen, &mask); p->prefix.s_addr &= mask.s_addr; } /* If prefix is 0.0.0.0/0 then return 1 else return 0. */ int prefix_ipv4_any (const 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 (void) { struct prefix_ipv6 *p; /* Allocate a full-size struct prefix to avoid problems with structure size mismatches. */ p = (struct prefix_ipv6 *)prefix_new(); p->family = AF_INET6; return p; } /* Free prefix for IPv6. */ void prefix_ipv6_free (struct prefix_ipv6 *p) { prefix_free((struct prefix *)p); } /* If given string is valid return pin6 else return NULL */ int str2prefix_ipv6 (const 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 == 0) return 0; p->prefixlen = IPV6_MAX_BITLEN; } else { int plen; cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1); strncpy (cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_pton (AF_INET6, cp, &p->prefix); free (cp); if (ret == 0) return 0; plen = (u_char) atoi (++pnt); if (plen > IPV6_MAX_BITLEN) return 0; p->prefixlen = plen; } p->family = AF_INET6; return ret; } /* Convert struct in6_addr netmask into integer. * FIXME return u_char as ip_maskleni() does. */ int ip6_masklen (struct in6_addr netmask) { int len = 0; unsigned char val; unsigned char *pnt; pnt = (unsigned char *) & netmask; while ((*pnt == 0xff) && len < IPV6_MAX_BITLEN) { len += 8; pnt++; } if (len < IPV6_MAX_BITLEN) { val = *pnt; while (val) { len++; val <<= 1; } } return len; } void masklen2ip6 (const int masklen, struct in6_addr *netmask) { assert (masklen >= 0 && masklen <= IPV6_MAX_BITLEN); memcpy (netmask, maskbytes6 + masklen, sizeof (struct in6_addr)); } 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 (const 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. * FIXME This function isn't used anywhere. */ struct prefix * sockunion2prefix (const union sockunion *dest, const 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 (const union sockunion *su, struct prefix *prefix) { if (su->sa.sa_family == AF_INET) { struct prefix_ipv4 *p; p = prefix ? (struct prefix_ipv4 *) prefix : 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 ? (struct prefix_ipv6 *) prefix : 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; } void prefix2sockunion (const struct prefix *p, union sockunion *su) { memset (su, 0, sizeof (*su)); su->sa.sa_family = p->family; if (p->family == AF_INET) su->sin.sin_addr = p->u.prefix4; #ifdef HAVE_IPV6 if (p->family == AF_INET6) memcpy (&su->sin6.sin6_addr, &p->u.prefix6, sizeof (struct in6_addr)); #endif /* HAVE_IPV6 */ } int prefix_blen (const 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 */ case AF_ETHERNET: return ETHER_ADDR_LEN; } return 0; } /* Generic function for conversion string to struct prefix. */ int str2prefix (const 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 */ /* Next we try to convert string to struct prefix_eth. */ ret = str2prefix_eth (str, (struct prefix_eth *) p); if (ret) return ret; return 0; } const char * prefix2str (union prefix46constptr pu, char *str, int size) { const struct prefix *p = pu.p; char buf[BUFSIZ]; if (p->family == AF_ETHERNET) { int i; char *s = str; assert(size > (3*ETHER_ADDR_LEN) + 1 /* slash */ + 3 /* plen */ ); for (i = 0; i < ETHER_ADDR_LEN; ++i) { sprintf(s, "%02x", p->u.prefix_eth.octet[i]); if (i < (ETHER_ADDR_LEN - 1)) { *(s+2) = ':'; s += 3; } else { s += 2; } } sprintf(s, "/%d", p->prefixlen); return 0; } inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ); snprintf (str, size, "%s/%d", buf, p->prefixlen); return str; } 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. * FIXME str.[c|h] would be better place for this function. */ int all_digit (const 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 == IPV4_MAX_PREFIXLEN); /* 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); } } in_addr_t ipv4_network_addr (in_addr_t hostaddr, int masklen) { struct in_addr mask; masklen2ip (masklen, &mask); return hostaddr & mask.s_addr; } in_addr_t ipv4_broadcast_addr (in_addr_t hostaddr, int masklen) { struct in_addr mask; masklen2ip (masklen, &mask); return (masklen != IPV4_MAX_PREFIXLEN-1) ? /* normal case */ (hostaddr | ~mask.s_addr) : /* special case for /31 */ (hostaddr ^ ~mask.s_addr); } /* 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 (const char *net_str, const 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; } #ifdef HAVE_IPV6 /* Utility function for making IPv6 address string. */ const char * inet6_ntoa (struct in6_addr addr) { static char buf[INET6_ADDRSTRLEN]; inet_ntop (AF_INET6, &addr, buf, INET6_ADDRSTRLEN); return buf; } #endif /* HAVE_IPV6 */ quagga-1.2.4/lib/prefix.h000066400000000000000000000210551325323223500152020ustar00rootroot00000000000000/* * 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 #ifdef SUNOS_5 # include #else # ifdef GNU_LINUX # include # else # include # endif #endif #include "sockunion.h" #ifndef ETHER_ADDR_LEN #define ETHER_ADDR_LEN ETHERADDRL #endif /* * there isn't a portable ethernet address type. We define our * own to simplify internal handling */ struct ethaddr { u_char octet[ETHER_ADDR_LEN]; } __packed; /* * A struct prefix contains an address family, a prefix length, and an * address. This can represent either a 'network prefix' as defined * by CIDR, where the 'host bits' of the prefix are 0 * (e.g. AF_INET:10.0.0.0/8), or an address and netmask * (e.g. AF_INET:10.0.0.9/8), such as might be configured on an * interface. */ /* different OSes use different names */ #if defined(AF_PACKET) #define AF_ETHERNET AF_PACKET #else #if defined(AF_LINK) #define AF_ETHERNET AF_LINK #endif #endif /* 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; struct ethaddr prefix_eth; /* AF_ETHERNET */ u_char val[8]; uintptr_t ptr; } 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))); }; /* Prefix for ethernet. */ struct prefix_eth { u_char family; u_char prefixlen; struct ethaddr eth_addr __attribute__ ((aligned (8))); /* AF_ETHERNET */ }; /* Prefix for a generic pointer */ struct prefix_ptr { u_char family; u_char prefixlen; uintptr_t prefix __attribute__ ((aligned (8))); }; /* helper to get type safety/avoid casts on calls * (w/o this, functions accepting all prefix types need casts on the caller * side, which strips type safety since the cast will accept any pointer * type.) */ union prefix46ptr { struct prefix *p; struct prefix_ipv4 *p4; struct prefix_ipv6 *p6; } __attribute__ ((transparent_union)); union prefix46constptr { const struct prefix *p; const struct prefix_ipv4 *p4; const struct prefix_ipv6 *p6; } __attribute__ ((transparent_union)); #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 */ /* Maximum prefix string length (IPv6) */ #define PREFIX_STRLEN 51 /* 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) #define IPV4_LINKLOCAL(a) ((((u_int32_t) (a)) & 0xffff0000) == 0xa9fe0000) #define IPV4_CLASS_DE(a) ((((u_int32_t) (a)) & 0xe0000000) == 0xe0000000) /* 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) /* glibc defines s6_addr32 to __in6_u.__u6_addr32 if __USE_{MISC || GNU} */ #ifndef s6_addr32 #if defined(SUNOS_5) /* Some SunOS define s6_addr32 only to kernel */ #define s6_addr32 _S6_un._S6_u32 #else #define s6_addr32 __u6_addr.__u6_addr32 #endif /* SUNOS_5 */ #endif /*s6_addr32*/ /* Prototypes. */ extern int str2family(const char *); extern int afi2family (afi_t); extern afi_t family2afi (int); extern const char *safi2str(safi_t safi); extern const char *afi2str(afi_t afi); /* Check bit of the prefix. */ extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen); extern unsigned int prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen); extern struct prefix *prefix_new (void); extern void prefix_free (struct prefix *); extern const char *prefix_family_str (const struct prefix *); extern int prefix_blen (const struct prefix *); extern int str2prefix (const char *, struct prefix *); extern const char *prefix2str (union prefix46constptr, char *, int); extern int prefix_match (const struct prefix *, const struct prefix *); extern int prefix_same (const struct prefix *, const struct prefix *); extern int prefix_cmp (const struct prefix *, const struct prefix *); extern int prefix_common_bits (const struct prefix *, const struct prefix *); extern void prefix_copy (struct prefix *dest, const struct prefix *src); extern void apply_mask (struct prefix *); extern struct prefix *sockunion2prefix (const union sockunion *dest, const union sockunion *mask); extern struct prefix *sockunion2hostprefix (const union sockunion *, struct prefix *p); extern void prefix2sockunion (const struct prefix *, union sockunion *); extern int str2prefix_eth (const char *, struct prefix_eth *); extern struct prefix_ipv4 *prefix_ipv4_new (void); extern void prefix_ipv4_free (struct prefix_ipv4 *); extern int str2prefix_ipv4 (const char *, struct prefix_ipv4 *); extern void apply_mask_ipv4 (struct prefix_ipv4 *); #define PREFIX_COPY_IPV4(DST, SRC) \ *((struct prefix_ipv4 *)(DST)) = *((const struct prefix_ipv4 *)(SRC)); extern int prefix_ipv4_any (const struct prefix_ipv4 *); extern void apply_classful_mask_ipv4 (struct prefix_ipv4 *); extern u_char ip_masklen (struct in_addr); extern void masklen2ip (const int, struct in_addr *); /* returns the network portion of the host address */ extern in_addr_t ipv4_network_addr (in_addr_t hostaddr, int masklen); /* given the address of a host on a network and the network mask length, * calculate the broadcast address for that network; * special treatment for /31: returns the address of the other host * on the network by flipping the host bit */ extern in_addr_t ipv4_broadcast_addr (in_addr_t hostaddr, int masklen); extern int netmask_str2prefix_str (const char *, const char *, char *); #ifdef HAVE_IPV6 extern struct prefix_ipv6 *prefix_ipv6_new (void); extern void prefix_ipv6_free (struct prefix_ipv6 *); extern int str2prefix_ipv6 (const char *, struct prefix_ipv6 *); extern void apply_mask_ipv6 (struct prefix_ipv6 *); #define PREFIX_COPY_IPV6(DST, SRC) \ *((struct prefix_ipv6 *)(DST)) = *((const struct prefix_ipv6 *)(SRC)); extern int ip6_masklen (struct in6_addr); extern void masklen2ip6 (const int, struct in6_addr *); extern void str2in6_addr (const char *, struct in6_addr *); extern const char *inet6_ntoa (struct in6_addr); #endif /* HAVE_IPV6 */ extern int all_digit (const char *); static inline int ipv4_martian (struct in_addr *addr) { in_addr_t ip = addr->s_addr; if (IPV4_NET0(ip) || IPV4_NET127(ip) || IPV4_CLASS_DE(ip)) { return 1; } return 0; } #endif /* _ZEBRA_PREFIX_H */ quagga-1.2.4/lib/privs.c000066400000000000000000000602471325323223500150510ustar00rootroot00000000000000/* * Zebra privileges. * * Copyright (C) 2003 Paul Jakma. * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "privs.h" #include "memory.h" #ifdef HAVE_CAPABILITIES /* sort out some generic internal types for: * * privilege values (cap_value_t, priv_t) -> pvalue_t * privilege set (..., priv_set_t) -> pset_t * privilege working storage (cap_t, ...) -> pstorage_t * * values we think of as numeric (they're ints really, but we dont know) * sets are mostly opaque, to hold a set of privileges, related in some way. * storage binds together a set of sets we're interested in. * (in reality: cap_value_t and priv_t are ints) */ #ifdef HAVE_LCAPS /* Linux doesn't have a 'set' type: a set of related privileges */ struct _pset { int num; cap_value_t *caps; }; typedef cap_value_t pvalue_t; typedef struct _pset pset_t; typedef cap_t pstorage_t; #elif defined (HAVE_SOLARIS_CAPABILITIES) typedef priv_t pvalue_t; typedef priv_set_t pset_t; typedef priv_set_t *pstorage_t; #else /* neither LCAPS nor SOLARIS_CAPABILITIES */ #error "HAVE_CAPABILITIES defined, but neither LCAPS nor Solaris Capabilties!" #endif /* HAVE_LCAPS */ #endif /* HAVE_CAPABILITIES */ /* the default NULL state we report is RAISED, but could be LOWERED if * zprivs_terminate is called and the NULL handler is installed. */ static zebra_privs_current_t zprivs_null_state = ZPRIVS_RAISED; /* internal privileges state */ static struct _zprivs_t { #ifdef HAVE_CAPABILITIES pstorage_t caps; /* working storage */ pset_t *syscaps_p; /* system-type requested permitted caps */ pset_t *syscaps_i; /* system-type requested inheritable caps */ #endif /* HAVE_CAPABILITIES */ uid_t zuid, /* uid to run as */ zsuid; /* saved uid */ gid_t zgid; /* gid to run as */ gid_t vtygrp; /* gid for vty sockets */ } zprivs_state; /* externally exported but not directly accessed functions */ #ifdef HAVE_CAPABILITIES int zprivs_change_caps (zebra_privs_ops_t); zebra_privs_current_t zprivs_state_caps (void); #endif /* HAVE_CAPABILITIES */ int zprivs_change_uid (zebra_privs_ops_t); zebra_privs_current_t zprivs_state_uid (void); int zprivs_change_null (zebra_privs_ops_t); zebra_privs_current_t zprivs_state_null (void); #ifdef HAVE_CAPABILITIES /* internal capability API */ static pset_t *zcaps2sys (zebra_capabilities_t *, int); static void zprivs_caps_init (struct zebra_privs_t *); static void zprivs_caps_terminate (void); /* Map of Quagga abstract capabilities to system capabilities */ static struct { int num; pvalue_t *system_caps; } cap_map [ZCAP_MAX] = { #ifdef HAVE_LCAPS /* Quagga -> Linux capabilities mappings */ [ZCAP_SETID] = { 2, (pvalue_t []) { CAP_SETGID, CAP_SETUID }, }, [ZCAP_BIND] = { 1, (pvalue_t []) { CAP_NET_BIND_SERVICE }, }, [ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { CAP_NET_ADMIN }, }, [ZCAP_NET_RAW] = { 1, (pvalue_t []) { CAP_NET_RAW }, }, [ZCAP_CHROOT] = { 1, (pvalue_t []) { CAP_SYS_CHROOT, }, }, [ZCAP_NICE] = { 1, (pvalue_t []) { CAP_SYS_NICE }, }, [ZCAP_PTRACE] = { 1, (pvalue_t []) { CAP_SYS_PTRACE }, }, [ZCAP_DAC_OVERRIDE] = { 1, (pvalue_t []) { CAP_DAC_OVERRIDE }, }, [ZCAP_READ_SEARCH] = { 1, (pvalue_t []) { CAP_DAC_READ_SEARCH }, }, [ZCAP_SYS_ADMIN] = { 1, (pvalue_t []) { CAP_SYS_ADMIN }, }, [ZCAP_FOWNER] = { 1, (pvalue_t []) { CAP_FOWNER }, }, #elif defined(HAVE_SOLARIS_CAPABILITIES) /* HAVE_LCAPS */ /* Quagga -> Solaris privilege mappings */ [ZCAP_SETID] = { 1, (pvalue_t []) { PRIV_PROC_SETID }, }, [ZCAP_BIND] = { 1, (pvalue_t []) { PRIV_NET_PRIVADDR }, }, /* IP_CONFIG is a subset of NET_CONFIG and is allowed in zones */ #ifdef PRIV_SYS_IP_CONFIG [ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { PRIV_SYS_IP_CONFIG }, }, #else [ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { PRIV_SYS_NET_CONFIG }, }, #endif [ZCAP_NET_RAW] = { 2, (pvalue_t []) { PRIV_NET_RAWACCESS, PRIV_NET_ICMPACCESS }, }, [ZCAP_CHROOT] = { 1, (pvalue_t []) { PRIV_PROC_CHROOT }, }, [ZCAP_NICE] = { 1, (pvalue_t []) { PRIV_PROC_PRIOCNTL }, }, [ZCAP_PTRACE] = { 1, (pvalue_t []) { PRIV_PROC_SESSION }, }, [ZCAP_DAC_OVERRIDE] = { 4, (pvalue_t []) { PRIV_FILE_DAC_EXECUTE, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_WRITE, PRIV_FILE_DAC_SEARCH }, }, [ZCAP_READ_SEARCH] = { 2, (pvalue_t []) { PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ }, }, [ZCAP_SYS_ADMIN] = { 1, (pvalue_t []) { PRIV_SYS_ADMIN }, }, [ZCAP_FOWNER] = { 1, (pvalue_t []) { PRIV_FILE_OWNER }, }, #endif /* HAVE_SOLARIS_CAPABILITIES */ }; #ifdef HAVE_LCAPS /* Linux forms of capabilities methods */ /* convert zebras privileges to system capabilities */ static pset_t * zcaps2sys (zebra_capabilities_t *zcaps, int num) { pset_t *syscaps; int i, j = 0, count = 0; if (!num) return NULL; /* first count up how many system caps we have */ for (i= 0; i < num; i++) count += cap_map[zcaps[i]].num; if ( (syscaps = XCALLOC (MTYPE_PRIVS, (sizeof(pset_t) * num))) == NULL) { fprintf (stderr, "%s: could not allocate syscaps!", __func__); return NULL; } syscaps->caps = XCALLOC (MTYPE_PRIVS, (sizeof (pvalue_t) * count)); if (!syscaps->caps) { fprintf (stderr, "%s: could not XCALLOC caps!", __func__); return NULL; } /* copy the capabilities over */ count = 0; for (i=0; i < num; i++) for (j = 0; j < cap_map[zcaps[i]].num; j++) syscaps->caps[count++] = cap_map[zcaps[i]].system_caps[j]; /* iterations above should be exact same as previous count, obviously.. */ syscaps->num = count; return syscaps; } /* set or clear the effective capabilities to/from permitted */ int zprivs_change_caps (zebra_privs_ops_t op) { cap_flag_value_t cflag; /* should be no possibility of being called without valid caps */ assert (zprivs_state.syscaps_p && zprivs_state.caps); if (! (zprivs_state.syscaps_p && zprivs_state.caps)) exit (1); if (op == ZPRIVS_RAISE) cflag = CAP_SET; else if (op == ZPRIVS_LOWER) cflag = CAP_CLEAR; else return -1; if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE, zprivs_state.syscaps_p->num, zprivs_state.syscaps_p->caps, cflag)) return cap_set_proc (zprivs_state.caps); return -1; } zebra_privs_current_t zprivs_state_caps (void) { int i; cap_flag_value_t val; /* should be no possibility of being called without valid caps */ assert (zprivs_state.syscaps_p && zprivs_state.caps); if (! (zprivs_state.syscaps_p && zprivs_state.caps)) exit (1); for (i=0; i < zprivs_state.syscaps_p->num; i++) { if ( cap_get_flag (zprivs_state.caps, zprivs_state.syscaps_p->caps[i], CAP_EFFECTIVE, &val) ) { zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s", safe_strerror (errno) ); return ZPRIVS_UNKNOWN; } if (val == CAP_SET) return ZPRIVS_RAISED; } return ZPRIVS_LOWERED; } static void zprivs_caps_init (struct zebra_privs_t *zprivs) { zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p); zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i); /* Tell kernel we want caps maintained across uid changes */ if ( prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1 ) { fprintf (stderr, "privs_init: could not set PR_SET_KEEPCAPS, %s\n", safe_strerror (errno) ); exit(1); } if ( !zprivs_state.syscaps_p ) { fprintf (stderr, "privs_init: capabilities enabled, " "but no capabilities supplied\n"); } /* we have caps, we have no need to ever change back the original user */ if (zprivs_state.zuid) { if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) ) { fprintf (stderr, "zprivs_init (cap): could not setreuid, %s\n", safe_strerror (errno)); exit (1); } } if ( !(zprivs_state.caps = cap_init()) ) { fprintf (stderr, "privs_init: failed to cap_init, %s\n", safe_strerror (errno)); exit (1); } if ( cap_clear (zprivs_state.caps) ) { fprintf (stderr, "privs_init: failed to cap_clear, %s\n", safe_strerror (errno)); exit (1); } /* set permitted caps */ cap_set_flag(zprivs_state.caps, CAP_PERMITTED, zprivs_state.syscaps_p->num, zprivs_state.syscaps_p->caps, CAP_SET); /* set inheritable caps, if any */ if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num) { cap_set_flag(zprivs_state.caps, CAP_INHERITABLE, zprivs_state.syscaps_i->num, zprivs_state.syscaps_i->caps, CAP_SET); } /* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as * and when, and only when, they are needed. */ if ( cap_set_proc (zprivs_state.caps) ) { cap_t current_caps; char *current_caps_text = NULL; char *wanted_caps_text = NULL; fprintf(stderr, "privs_init: initial cap_set_proc failed: %s\n", safe_strerror(errno)); current_caps = cap_get_proc(); if (current_caps) { current_caps_text = cap_to_text(current_caps, NULL); cap_free(current_caps); } wanted_caps_text = cap_to_text(zprivs_state.caps, NULL); fprintf(stderr, "Wanted caps: %s\n", wanted_caps_text ? wanted_caps_text : "???"); fprintf(stderr, "Have caps: %s\n", current_caps_text ? current_caps_text : "???"); if (current_caps_text) cap_free(current_caps_text); if (wanted_caps_text) cap_free(wanted_caps_text); exit (1); } /* set methods for the caller to use */ zprivs->change = zprivs_change_caps; zprivs->current_state = zprivs_state_caps; } static void zprivs_caps_terminate (void) { /* clear all capabilities */ if (zprivs_state.caps) cap_clear (zprivs_state.caps); /* and boom, capabilities are gone forever */ if ( cap_set_proc (zprivs_state.caps) ) { fprintf (stderr, "privs_terminate: cap_set_proc failed, %s", safe_strerror (errno) ); exit (1); } /* free up private state */ if (zprivs_state.syscaps_p->num) { XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p->caps); XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p); } if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num) { XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i->caps); XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i); } cap_free (zprivs_state.caps); } #elif defined (HAVE_SOLARIS_CAPABILITIES) /* !HAVE_LCAPS */ /* Solaris specific capability/privilege methods * * Resources: * - the 'privileges' man page * - http://cvs.opensolaris.org * - http://blogs.sun.com/roller/page/gbrunett?entry=privilege_enabling_set_id_programs1 */ static pset_t * zprivs_caps_minimal () { pset_t *minimal; if ((minimal = priv_str_to_set("basic", ",", NULL)) == NULL) { fprintf (stderr, "%s: couldn't get basic set!\n", __func__); exit (1); } /* create a minimal privilege set from the basic set */ (void) priv_delset(minimal, PRIV_PROC_EXEC); (void) priv_delset(minimal, PRIV_PROC_INFO); (void) priv_delset(minimal, PRIV_PROC_SESSION); (void) priv_delset(minimal, PRIV_FILE_LINK_ANY); return minimal; } /* convert zebras privileges to system capabilities */ static pset_t * zcaps2sys (zebra_capabilities_t *zcaps, int num) { pset_t *syscaps; int i, j = 0; if ((syscaps = priv_allocset()) == NULL) { fprintf (stderr, "%s: could not allocate syscaps!\n", __func__); exit (1); } priv_emptyset (syscaps); for (i=0; i < num; i++) for (j = 0; j < cap_map[zcaps[i]].num; j++) priv_addset (syscaps, cap_map[zcaps[i]].system_caps[j]); return syscaps; } /* callback exported to users to RAISE and LOWER effective privileges * from nothing to the given permitted set and back down */ int zprivs_change_caps (zebra_privs_ops_t op) { pset_t *privset; /* should be no possibility of being called without valid caps */ assert (zprivs_state.syscaps_p); if (!zprivs_state.syscaps_p) { fprintf (stderr, "%s: Eek, missing privileged caps!", __func__); exit (1); } assert (zprivs_state.caps); if (!zprivs_state.caps) { fprintf (stderr, "%s: Eek, missing caps!", __func__); exit (1); } /* to raise: copy original permitted as our working effective set * to lower: copy regular effective set stored in zprivs_state.caps */ if (op == ZPRIVS_RAISE) privset = zprivs_state.syscaps_p; else if (op == ZPRIVS_LOWER) privset = zprivs_state.caps; else return -1; if (setppriv (PRIV_SET, PRIV_EFFECTIVE, privset) != 0) return -1; return 0; } /* Retrieve current privilege state, is it RAISED or LOWERED? */ zebra_privs_current_t zprivs_state_caps (void) { zebra_privs_current_t result; pset_t *effective; if ( (effective = priv_allocset()) == NULL) { fprintf (stderr, "%s: failed to get priv_allocset! %s\n", __func__, safe_strerror (errno)); return ZPRIVS_UNKNOWN; } if (getppriv (PRIV_EFFECTIVE, effective)) { fprintf (stderr, "%s: failed to get state! %s\n", __func__, safe_strerror (errno)); result = ZPRIVS_UNKNOWN; } else { if (priv_isequalset (effective, zprivs_state.syscaps_p)) result = ZPRIVS_RAISED; else if (priv_isequalset (effective, zprivs_state.caps)) result = ZPRIVS_LOWERED; else result = ZPRIVS_UNKNOWN; } priv_freeset (effective); return result; } static void zprivs_caps_init (struct zebra_privs_t *zprivs) { pset_t *basic; pset_t *minimal; /* the specified sets */ zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p); zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i); /* nonsensical to have gotten here but not have capabilities */ if (!zprivs_state.syscaps_p) { fprintf (stderr, "%s: capabilities enabled, " "but no valid capabilities supplied\n", __func__); } /* We retain the basic set in our permitted set, as Linux has no * equivalent. The basic set on Linux hence is implicit, always * there. */ if ((basic = priv_str_to_set("basic", ",", NULL)) == NULL) { fprintf (stderr, "%s: couldn't get basic set!\n", __func__); exit (1); } /* Add the basic set to the permitted set */ priv_union (basic, zprivs_state.syscaps_p); priv_freeset (basic); /* Hey kernel, we know about privileges! * this isn't strictly required, use of setppriv should have same effect */ if (setpflags (PRIV_AWARE, 1)) { fprintf (stderr, "%s: error setting PRIV_AWARE!, %s\n", __func__, safe_strerror (errno) ); exit (1); } /* need either valid or empty sets for both p and i.. */ assert (zprivs_state.syscaps_i && zprivs_state.syscaps_p); /* we have caps, we have no need to ever change back the original user * change real, effective and saved to the specified user. */ if (zprivs_state.zuid) { if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) ) { fprintf (stderr, "%s: could not setreuid, %s\n", __func__, safe_strerror (errno)); exit (1); } } /* set the permitted set */ if (setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.syscaps_p)) { fprintf (stderr, "%s: error setting permitted set!, %s\n", __func__, safe_strerror (errno) ); exit (1); } /* set the inheritable set */ if (setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.syscaps_i)) { fprintf (stderr, "%s: error setting inheritable set!, %s\n", __func__, safe_strerror (errno) ); exit (1); } /* we need a minimal basic set for 'effective', potentially for inheritable too */ minimal = zprivs_caps_minimal(); /* now set the effective set with a subset of basic privileges */ if (setppriv (PRIV_SET, PRIV_EFFECTIVE, minimal)) { fprintf (stderr, "%s: error setting effective set!, %s\n", __func__, safe_strerror (errno) ); exit (1); } /* we'll use the minimal set as our working-storage privset */ zprivs_state.caps = minimal; /* set methods for the caller to use */ zprivs->change = zprivs_change_caps; zprivs->current_state = zprivs_state_caps; } static void zprivs_caps_terminate (void) { assert (zprivs_state.caps); /* clear all capabilities by using working-storage privset */ setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps); setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.caps); setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps); /* free up private state */ if (zprivs_state.syscaps_p) priv_freeset (zprivs_state.syscaps_p); if (zprivs_state.syscaps_i) priv_freeset (zprivs_state.syscaps_i); priv_freeset (zprivs_state.caps); } #else /* !HAVE_LCAPS && ! HAVE_SOLARIS_CAPABILITIES */ #error "Neither Solaris nor Linux capabilities, dazed and confused..." #endif /* HAVE_LCAPS */ #endif /* HAVE_CAPABILITIES */ int zprivs_change_uid (zebra_privs_ops_t op) { if (op == ZPRIVS_RAISE) return seteuid (zprivs_state.zsuid); else if (op == ZPRIVS_LOWER) return seteuid (zprivs_state.zuid); else return -1; } zebra_privs_current_t zprivs_state_uid (void) { return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED); } int zprivs_change_null (zebra_privs_ops_t op) { return 0; } zebra_privs_current_t zprivs_state_null (void) { return zprivs_null_state; } #ifndef HAVE_GETGROUPLIST /* Solaris 11 has no getgrouplist() */ static int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) { struct group *grp; size_t usridx; int pos = 0, ret; if (pos < *ngroups) groups[pos] = group; pos++; setgrent(); while ((grp = getgrent())) { if (grp->gr_gid == group) continue; for (usridx = 0; grp->gr_mem[usridx] != NULL; usridx++) if (!strcmp (grp->gr_mem[usridx], user)) { if (pos < *ngroups) groups[pos] = grp->gr_gid; pos++; break; } } endgrent(); ret = (pos <= *ngroups) ? pos : -1; *ngroups = pos; return ret; } #endif /* HAVE_GETGROUPLIST */ void zprivs_init(struct zebra_privs_t *zprivs) { struct passwd *pwentry = NULL; struct group *grentry = NULL; gid_t groups[NGROUPS_MAX]; int i, ngroups = 0; int found = 0; if (!zprivs) { fprintf (stderr, "zprivs_init: called with NULL arg!\n"); exit (1); } /* NULL privs */ if (! (zprivs->user || zprivs->group || zprivs->cap_num_p || zprivs->cap_num_i) ) { zprivs->change = zprivs_change_null; zprivs->current_state = zprivs_state_null; return; } if (zprivs->user) { if ( (pwentry = getpwnam (zprivs->user)) == NULL ) { /* cant use log.h here as it depends on vty */ fprintf (stderr, "privs_init: could not lookup user %s\n", zprivs->user); exit (1); } zprivs_state.zuid = pwentry->pw_uid; zprivs_state.zgid = pwentry->pw_gid; } grentry = NULL; if (zprivs->group) { if ( (grentry = getgrnam (zprivs->group)) == NULL ) { fprintf (stderr, "privs_init: could not lookup group %s\n", zprivs->group); exit (1); } zprivs_state.zgid = grentry->gr_gid; } if (zprivs->user) { ngroups = sizeof(groups); if ( (ngroups = getgrouplist (zprivs->user, zprivs_state.zgid, groups, &ngroups )) < 0 ) { /* cant use log.h here as it depends on vty */ fprintf (stderr, "privs_init: could not getgrouplist for user %s\n", zprivs->user); exit (1); } } if (zprivs->vty_group) /* Add the vty_group to the supplementary groups so it can be chowned to */ { if ( (grentry = getgrnam (zprivs->vty_group)) ) { zprivs_state.vtygrp = grentry->gr_gid; for ( i = 0; i < ngroups; i++ ) if ( groups[i] == zprivs_state.vtygrp ) { found++; break; } if (!found) { fprintf (stderr, "privs_init: user(%s) is not part of vty group specified(%s)\n", zprivs->user, zprivs->vty_group); exit (1); } if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) ) { groups[i] = zprivs_state.vtygrp; } } else { fprintf (stderr, "privs_init: could not lookup vty group %s\n", zprivs->vty_group); exit (1); } } if (ngroups) { if ( setgroups (ngroups, groups) ) { fprintf (stderr, "privs_init: could not setgroups, %s\n", safe_strerror (errno) ); exit (1); } } if (zprivs_state.zgid) { /* change group now, forever. uid we do later */ if ( setregid (zprivs_state.zgid, zprivs_state.zgid) ) { fprintf (stderr, "zprivs_init: could not setregid, %s\n", safe_strerror (errno) ); exit (1); } } #ifdef HAVE_CAPABILITIES zprivs_caps_init (zprivs); #else /* !HAVE_CAPABILITIES */ /* we dont have caps. we'll need to maintain rid and saved uid * and change euid back to saved uid (who we presume has all neccessary * privileges) whenever we are asked to raise our privileges. * * This is not worth that much security wise, but all we can do. */ zprivs_state.zsuid = geteuid(); if ( zprivs_state.zuid ) { if ( setreuid (-1, zprivs_state.zuid) ) { fprintf (stderr, "privs_init (uid): could not setreuid, %s\n", safe_strerror (errno)); exit (1); } } zprivs->change = zprivs_change_uid; zprivs->current_state = zprivs_state_uid; #endif /* HAVE_CAPABILITIES */ } void zprivs_terminate (struct zebra_privs_t *zprivs) { if (!zprivs) { fprintf (stderr, "%s: no privs struct given, terminating", __func__); exit (0); } #ifdef HAVE_CAPABILITIES zprivs_caps_terminate(); #else /* !HAVE_CAPABILITIES */ if (zprivs_state.zuid) { if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) ) { fprintf (stderr, "privs_terminate: could not setreuid, %s", safe_strerror (errno) ); exit (1); } } #endif /* HAVE_LCAPS */ zprivs->change = zprivs_change_null; zprivs->current_state = zprivs_state_null; zprivs_null_state = ZPRIVS_LOWERED; return; } void zprivs_get_ids(struct zprivs_ids_t *ids) { ids->uid_priv = getuid(); (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid) : (ids->uid_normal = -1); (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid) : (ids->gid_normal = -1); (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp) : (ids->gid_vty = -1); return; } quagga-1.2.4/lib/privs.h000066400000000000000000000050501325323223500150450ustar00rootroot00000000000000/* * Zebra privileges header. * * Copyright (C) 2003 Paul Jakma. * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_PRIVS_H #define _ZEBRA_PRIVS_H /* list of zebra capabilities */ typedef enum { ZCAP_SETID, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, ZCAP_CHROOT, ZCAP_NICE, ZCAP_PTRACE, ZCAP_DAC_OVERRIDE, ZCAP_READ_SEARCH, ZCAP_FOWNER, ZCAP_MAX } zebra_capabilities_t; typedef enum { ZPRIVS_LOWERED, ZPRIVS_RAISED, ZPRIVS_UNKNOWN, } zebra_privs_current_t; typedef enum { ZPRIVS_RAISE, ZPRIVS_LOWER, } zebra_privs_ops_t; struct zebra_privs_t { zebra_capabilities_t *caps_p; /* caps required for operation */ zebra_capabilities_t *caps_i; /* caps to allow inheritance of */ int cap_num_p; /* number of caps in arrays */ int cap_num_i; const char *user; /* user and group to run as */ const char *group; const char *vty_group; /* group to chown vty socket to */ /* methods */ int (*change) (zebra_privs_ops_t); /* change privileges, 0 on success */ zebra_privs_current_t (*current_state) (void); /* current privilege state */ }; struct zprivs_ids_t { /* -1 is undefined */ uid_t uid_priv; /* privileged uid */ uid_t uid_normal; /* normal uid */ gid_t gid_priv; /* privileged uid */ gid_t gid_normal; /* normal uid */ gid_t gid_vty; /* vty gid */ }; /* initialise zebra privileges */ extern void zprivs_init (struct zebra_privs_t *zprivs); /* drop all and terminate privileges */ extern void zprivs_terminate (struct zebra_privs_t *); /* query for runtime uid's and gid's, eg vty needs this */ extern void zprivs_get_ids(struct zprivs_ids_t *); #endif /* _ZEBRA_PRIVS_H */ quagga-1.2.4/lib/queue.h000066400000000000000000000517601325323223500150370ustar00rootroot00000000000000/*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 * $FreeBSD$ */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines four types of data structures: singly-linked lists, * singly-linked tail queues, lists and tail queues. * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A singly-linked tail queue is headed by a pair of pointers, one to the * head of the list and the other to the tail of the list. The elements are * singly linked for minimum space and pointer manipulation overhead at the * expense of O(n) removal for arbitrary elements. New elements can be added * to the list after an existing element, at the head of the list, or at the * end of the list. Elements being removed from the head of the tail queue * should use the explicit macro for this purpose for optimum efficiency. * A singly-linked tail queue may only be traversed in the forward direction. * Singly-linked tail queues are ideal for applications with large datasets * and few or no removals or for implementing a FIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * For details on the use of these macros, see the queue(3) manual page. * * * SLIST LIST STAILQ TAILQ * _HEAD + + + + * _HEAD_INITIALIZER + + + + * _ENTRY + + + + * _INIT + + + + * _EMPTY + + + + * _FIRST + + + + * _NEXT + + + + * _PREV - - - + * _LAST - - + + * _FOREACH + + + + * _FOREACH_SAFE + + + + * _FOREACH_REVERSE - - - + * _FOREACH_REVERSE_SAFE - - - + * _INSERT_HEAD + + + + * _INSERT_BEFORE - + - + * _INSERT_AFTER + + + + * _INSERT_TAIL - - + + * _CONCAT - - + + * _REMOVE_AFTER + - + - * _REMOVE_HEAD + - + - * _REMOVE + + + + * _SWAP + + + + * */ #ifdef QUEUE_MACRO_DEBUG /* Store the last 2 places the queue element or head was altered */ struct qm_trace { char * lastfile; int lastline; char * prevfile; int prevline; }; #define TRACEBUF struct qm_trace trace; #define TRASHIT(x) do {(x) = (void *)-1;} while (0) #define QMD_SAVELINK(name, link) void **name = (void *)&(link) #define QMD_TRACE_HEAD(head) do { \ (head)->trace.prevline = (head)->trace.lastline; \ (head)->trace.prevfile = (head)->trace.lastfile; \ (head)->trace.lastline = __LINE__; \ (head)->trace.lastfile = __FILE__; \ } while (0) #define QMD_TRACE_ELEM(elem) do { \ (elem)->trace.prevline = (elem)->trace.lastline; \ (elem)->trace.prevfile = (elem)->trace.lastfile; \ (elem)->trace.lastline = __LINE__; \ (elem)->trace.lastfile = __FILE__; \ } while (0) #else #define QMD_TRACE_ELEM(elem) #define QMD_TRACE_HEAD(head) #define QMD_SAVELINK(name, link) #define TRACEBUF #define TRASHIT(x) #endif /* QUEUE_MACRO_DEBUG */ /* * Singly-linked List declarations. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List functions. */ #define SLIST_EMPTY(head) ((head)->slh_first == NULL) #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_FOREACH(var, head, field) \ for ((var) = SLIST_FIRST((head)); \ (var); \ (var) = SLIST_NEXT((var), field)) #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = SLIST_FIRST((head)); \ (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ (var) = (tvar)) #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ for ((varp) = &SLIST_FIRST((head)); \ ((var) = *(varp)) != NULL; \ (varp) = &SLIST_NEXT((var), field)) #define SLIST_INIT(head) do { \ SLIST_FIRST((head)) = NULL; \ } while (0) #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ SLIST_NEXT((slistelm), field) = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ SLIST_FIRST((head)) = (elm); \ } while (0) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_REMOVE(head, elm, type, field) do { \ QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ if (SLIST_FIRST((head)) == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ else { \ struct type *curelm = SLIST_FIRST((head)); \ while (SLIST_NEXT(curelm, field) != (elm)) \ curelm = SLIST_NEXT(curelm, field); \ SLIST_REMOVE_AFTER(curelm, field); \ } \ TRASHIT(*oldnext); \ } while (0) #define SLIST_REMOVE_AFTER(elm, field) do { \ SLIST_NEXT(elm, field) = \ SLIST_NEXT(SLIST_NEXT(elm, field), field); \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ } while (0) #define SLIST_SWAP(head1, head2, type) do { \ struct type *swap_first = SLIST_FIRST(head1); \ SLIST_FIRST(head1) = SLIST_FIRST(head2); \ SLIST_FIRST(head2) = swap_first; \ } while (0) /* * Singly-linked Tail queue declarations. */ #define STAILQ_HEAD(name, type) \ struct name { \ struct type *stqh_first;/* first element */ \ struct type **stqh_last;/* addr of last next element */ \ } #define STAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).stqh_first } #define STAILQ_ENTRY(type) \ struct { \ struct type *stqe_next; /* next element */ \ } /* * Singly-linked Tail queue functions. */ #define STAILQ_CONCAT(head1, head2) do { \ if (!STAILQ_EMPTY((head2))) { \ *(head1)->stqh_last = (head2)->stqh_first; \ (head1)->stqh_last = (head2)->stqh_last; \ STAILQ_INIT((head2)); \ } \ } while (0) #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) #define STAILQ_FIRST(head) ((head)->stqh_first) #define STAILQ_FOREACH(var, head, field) \ for((var) = STAILQ_FIRST((head)); \ (var); \ (var) = STAILQ_NEXT((var), field)) #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = STAILQ_FIRST((head)); \ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ (var) = (tvar)) #define STAILQ_INIT(head) do { \ STAILQ_FIRST((head)) = NULL; \ (head)->stqh_last = &STAILQ_FIRST((head)); \ } while (0) #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ STAILQ_NEXT((tqelm), field) = (elm); \ } while (0) #define STAILQ_INSERT_HEAD(head, elm, field) do { \ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ STAILQ_FIRST((head)) = (elm); \ } while (0) #define STAILQ_INSERT_TAIL(head, elm, field) do { \ STAILQ_NEXT((elm), field) = NULL; \ *(head)->stqh_last = (elm); \ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ } while (0) #define STAILQ_LAST(head, type, field) \ (STAILQ_EMPTY((head)) ? \ NULL : \ ((struct type *)(void *) \ ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) #define STAILQ_REMOVE(head, elm, type, field) do { \ QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ if (STAILQ_FIRST((head)) == (elm)) { \ STAILQ_REMOVE_HEAD((head), field); \ } \ else { \ struct type *curelm = STAILQ_FIRST((head)); \ while (STAILQ_NEXT(curelm, field) != (elm)) \ curelm = STAILQ_NEXT(curelm, field); \ STAILQ_REMOVE_AFTER(head, curelm, field); \ } \ TRASHIT(*oldnext); \ } while (0) #define STAILQ_REMOVE_AFTER(head, elm, field) do { \ if ((STAILQ_NEXT(elm, field) = \ STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ } while (0) #define STAILQ_REMOVE_HEAD(head, field) do { \ if ((STAILQ_FIRST((head)) = \ STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ (head)->stqh_last = &STAILQ_FIRST((head)); \ } while (0) #define STAILQ_SWAP(head1, head2, type) do { \ struct type *swap_first = STAILQ_FIRST(head1); \ struct type **swap_last = (head1)->stqh_last; \ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ (head1)->stqh_last = (head2)->stqh_last; \ STAILQ_FIRST(head2) = swap_first; \ (head2)->stqh_last = swap_last; \ if (STAILQ_EMPTY(head1)) \ (head1)->stqh_last = &STAILQ_FIRST(head1); \ if (STAILQ_EMPTY(head2)) \ (head2)->stqh_last = &STAILQ_FIRST(head2); \ } while (0) /* * List declarations. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List functions. */ #if (defined(_KERNEL) && defined(INVARIANTS)) #define QMD_LIST_CHECK_HEAD(head, field) do { \ if (LIST_FIRST((head)) != NULL && \ LIST_FIRST((head))->field.le_prev != \ &LIST_FIRST((head))) \ panic("Bad list head %p first->prev != head", (head)); \ } while (0) #define QMD_LIST_CHECK_NEXT(elm, field) do { \ if (LIST_NEXT((elm), field) != NULL && \ LIST_NEXT((elm), field)->field.le_prev != \ &((elm)->field.le_next)) \ panic("Bad link elm %p next->prev != elm", (elm)); \ } while (0) #define QMD_LIST_CHECK_PREV(elm, field) do { \ if (*(elm)->field.le_prev != (elm)) \ panic("Bad link elm %p prev->next != elm", (elm)); \ } while (0) #else #define QMD_LIST_CHECK_HEAD(head, field) #define QMD_LIST_CHECK_NEXT(elm, field) #define QMD_LIST_CHECK_PREV(elm, field) #endif /* (_KERNEL && INVARIANTS) */ #define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_FIRST(head) ((head)->lh_first) #define LIST_FOREACH(var, head, field) \ for ((var) = LIST_FIRST((head)); \ (var); \ (var) = LIST_NEXT((var), field)) #define LIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = LIST_FIRST((head)); \ (var) && ((tvar) = LIST_NEXT((var), field), 1); \ (var) = (tvar)) #define LIST_INIT(head) do { \ LIST_FIRST((head)) = NULL; \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ QMD_LIST_CHECK_NEXT(listelm, field); \ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ LIST_NEXT((listelm), field)->field.le_prev = \ &LIST_NEXT((elm), field); \ LIST_NEXT((listelm), field) = (elm); \ (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ QMD_LIST_CHECK_PREV(listelm, field); \ (elm)->field.le_prev = (listelm)->field.le_prev; \ LIST_NEXT((elm), field) = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ QMD_LIST_CHECK_HEAD((head), field); \ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ LIST_FIRST((head)) = (elm); \ (elm)->field.le_prev = &LIST_FIRST((head)); \ } while (0) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_REMOVE(elm, field) do { \ QMD_SAVELINK(oldnext, (elm)->field.le_next); \ QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ QMD_LIST_CHECK_NEXT(elm, field); \ QMD_LIST_CHECK_PREV(elm, field); \ if (LIST_NEXT((elm), field) != NULL) \ LIST_NEXT((elm), field)->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = LIST_NEXT((elm), field); \ TRASHIT(*oldnext); \ TRASHIT(*oldprev); \ } while (0) #define LIST_SWAP(head1, head2, type, field) do { \ struct type *swap_tmp = LIST_FIRST((head1)); \ LIST_FIRST((head1)) = LIST_FIRST((head2)); \ LIST_FIRST((head2)) = swap_tmp; \ if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ } while (0) /* * Tail queue declarations. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ TRACEBUF \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ TRACEBUF \ } /* * Tail queue functions. */ #if (defined(_KERNEL) && defined(INVARIANTS)) #define QMD_TAILQ_CHECK_HEAD(head, field) do { \ if (!TAILQ_EMPTY(head) && \ TAILQ_FIRST((head))->field.tqe_prev != \ &TAILQ_FIRST((head))) \ panic("Bad tailq head %p first->prev != head", (head)); \ } while (0) #define QMD_TAILQ_CHECK_TAIL(head, field) do { \ if (*(head)->tqh_last != NULL) \ panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ } while (0) #define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ if (TAILQ_NEXT((elm), field) != NULL && \ TAILQ_NEXT((elm), field)->field.tqe_prev != \ &((elm)->field.tqe_next)) \ panic("Bad link elm %p next->prev != elm", (elm)); \ } while (0) #define QMD_TAILQ_CHECK_PREV(elm, field) do { \ if (*(elm)->field.tqe_prev != (elm)) \ panic("Bad link elm %p prev->next != elm", (elm)); \ } while (0) #else #define QMD_TAILQ_CHECK_HEAD(head, field) #define QMD_TAILQ_CHECK_TAIL(head, headname) #define QMD_TAILQ_CHECK_NEXT(elm, field) #define QMD_TAILQ_CHECK_PREV(elm, field) #endif /* (_KERNEL && INVARIANTS) */ #define TAILQ_CONCAT(head1, head2, field) do { \ if (!TAILQ_EMPTY(head2)) { \ *(head1)->tqh_last = (head2)->tqh_first; \ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ (head1)->tqh_last = (head2)->tqh_last; \ TAILQ_INIT((head2)); \ QMD_TRACE_HEAD(head1); \ QMD_TRACE_HEAD(head2); \ } \ } while (0) #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_FOREACH(var, head, field) \ for ((var) = TAILQ_FIRST((head)); \ (var); \ (var) = TAILQ_NEXT((var), field)) #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = TAILQ_FIRST((head)); \ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ (var) = (tvar)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for ((var) = TAILQ_LAST((head), headname); \ (var); \ (var) = TAILQ_PREV((var), headname, field)) #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ for ((var) = TAILQ_LAST((head), headname); \ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ (var) = (tvar)) #define TAILQ_INIT(head) do { \ TAILQ_FIRST((head)) = NULL; \ (head)->tqh_last = &TAILQ_FIRST((head)); \ QMD_TRACE_HEAD(head); \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ QMD_TAILQ_CHECK_NEXT(listelm, field); \ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ TAILQ_NEXT((elm), field)->field.tqe_prev = \ &TAILQ_NEXT((elm), field); \ else { \ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ QMD_TRACE_HEAD(head); \ } \ TAILQ_NEXT((listelm), field) = (elm); \ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ QMD_TRACE_ELEM(&(elm)->field); \ QMD_TRACE_ELEM(&listelm->field); \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ QMD_TAILQ_CHECK_PREV(listelm, field); \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ TAILQ_NEXT((elm), field) = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ QMD_TRACE_ELEM(&(elm)->field); \ QMD_TRACE_ELEM(&listelm->field); \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ QMD_TAILQ_CHECK_HEAD(head, field); \ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ TAILQ_FIRST((head))->field.tqe_prev = \ &TAILQ_NEXT((elm), field); \ else \ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ TAILQ_FIRST((head)) = (elm); \ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ QMD_TRACE_HEAD(head); \ QMD_TRACE_ELEM(&(elm)->field); \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ QMD_TAILQ_CHECK_TAIL(head, field); \ TAILQ_NEXT((elm), field) = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ QMD_TRACE_HEAD(head); \ QMD_TRACE_ELEM(&(elm)->field); \ } while (0) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_REMOVE(head, elm, field) do { \ QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ QMD_TAILQ_CHECK_NEXT(elm, field); \ QMD_TAILQ_CHECK_PREV(elm, field); \ if ((TAILQ_NEXT((elm), field)) != NULL) \ TAILQ_NEXT((elm), field)->field.tqe_prev = \ (elm)->field.tqe_prev; \ else { \ (head)->tqh_last = (elm)->field.tqe_prev; \ QMD_TRACE_HEAD(head); \ } \ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ TRASHIT(*oldnext); \ TRASHIT(*oldprev); \ QMD_TRACE_ELEM(&(elm)->field); \ } while (0) #define TAILQ_SWAP(head1, head2, type, field) do { \ struct type *swap_first = (head1)->tqh_first; \ struct type **swap_last = (head1)->tqh_last; \ (head1)->tqh_first = (head2)->tqh_first; \ (head1)->tqh_last = (head2)->tqh_last; \ (head2)->tqh_first = swap_first; \ (head2)->tqh_last = swap_last; \ if ((swap_first = (head1)->tqh_first) != NULL) \ swap_first->field.tqe_prev = &(head1)->tqh_first; \ else \ (head1)->tqh_last = &(head1)->tqh_first; \ if ((swap_first = (head2)->tqh_first) != NULL) \ swap_first->field.tqe_prev = &(head2)->tqh_first; \ else \ (head2)->tqh_last = &(head2)->tqh_first; \ } while (0) #endif /* !_SYS_QUEUE_H_ */ quagga-1.2.4/lib/regex-gnu.h000066400000000000000000000502751325323223500156140ustar00rootroot00000000000000/* 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: */ quagga-1.2.4/lib/regex.c000066400000000000000000005610731325323223500150230ustar00rootroot00000000000000/* 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 #ifdef _WIN32 /* Windows does not provide unistd.h, which is required for abort() */ #include #endif /* _WIN32 */ #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; memset (re_syntax_table, 0, 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 "zassert.h" 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. */ memset (b, 0, (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 (); memset (fastmap, 0, 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 occurred 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 (err, preg, errbuf, errbuf_size) int err; const regex_t *preg; char *errbuf; size_t errbuf_size; { const char *msg; size_t msg_size; if (err < 0 || err >= (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[err]); 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 */ quagga-1.2.4/lib/route_types.h000066400000000000000000000337131325323223500162730ustar00rootroot00000000000000/* Auto-generated from route_types.txt by . */ /* Do not edit! */ #ifndef _QUAGGA_ROUTE_TYPES_H #define _QUAGGA_ROUTE_TYPES_H /* 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_ISIS 8 #define ZEBRA_ROUTE_BGP 9 #define ZEBRA_ROUTE_PIM 10 #define ZEBRA_ROUTE_HSLS 11 #define ZEBRA_ROUTE_OLSR 12 #define ZEBRA_ROUTE_BABEL 13 #define ZEBRA_ROUTE_NHRP 14 #define ZEBRA_ROUTE_MAX 15 #define SHOW_ROUTE_V4_HEADER \ "Codes: K - kernel route, C - connected, S - static, R - RIP,%s" \ " O - OSPF, I - IS-IS, B - BGP, P - PIM, A - Babel, N - NHRP,%s" \ " > - selected route, * - FIB route%s%s", \ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE #define SHOW_ROUTE_V6_HEADER \ "Codes: K - kernel route, C - connected, S - static, R - RIPng,%s" \ " O - OSPFv6, I - IS-IS, B - BGP, A - Babel, N - NHRP,%s" \ " > - selected route, * - FIB route%s%s", \ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE /* babeld */ #define QUAGGA_REDIST_STR_BABELD \ "(kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp|pim|nhrp)" #define QUAGGA_REDIST_HELP_STR_BABELD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #define QUAGGA_IP_REDIST_STR_BABELD \ "(kernel|connected|static|rip|ospf|isis|bgp|pim|nhrp)" #define QUAGGA_IP_REDIST_HELP_STR_BABELD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #define QUAGGA_IP6_REDIST_STR_BABELD \ "(kernel|connected|static|ripng|ospf6|isis|bgp|nhrp)" #define QUAGGA_IP6_REDIST_HELP_STR_BABELD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Next Hop Resolution Protocol (NHRP)\n" /* bgpd */ #define QUAGGA_REDIST_STR_BGPD \ "(kernel|connected|static|rip|ripng|ospf|ospf6|isis|pim|babel|nhrp)" #define QUAGGA_REDIST_HELP_STR_BGPD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #define QUAGGA_IP_REDIST_STR_BGPD \ "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" #define QUAGGA_IP_REDIST_HELP_STR_BGPD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #define QUAGGA_IP6_REDIST_STR_BGPD \ "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" #define QUAGGA_IP6_REDIST_HELP_STR_BGPD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" /* isisd */ #define QUAGGA_REDIST_STR_ISISD \ "(kernel|connected|static|rip|ripng|ospf|ospf6|bgp|pim|babel|nhrp)" #define QUAGGA_REDIST_HELP_STR_ISISD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #define QUAGGA_IP_REDIST_STR_ISISD \ "(kernel|connected|static|rip|ospf|bgp|pim|babel|nhrp)" #define QUAGGA_IP_REDIST_HELP_STR_ISISD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #define QUAGGA_IP6_REDIST_STR_ISISD \ "(kernel|connected|static|ripng|ospf6|bgp|babel|nhrp)" #define QUAGGA_IP6_REDIST_HELP_STR_ISISD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Border Gateway Protocol (BGP)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" /* nhrpd */ #define QUAGGA_REDIST_STR_NHRPD \ "(kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp|pim|babel)" #define QUAGGA_REDIST_HELP_STR_NHRPD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" #define QUAGGA_IP_REDIST_STR_NHRPD \ "(kernel|connected|static|rip|ospf|isis|bgp|pim|babel)" #define QUAGGA_IP_REDIST_HELP_STR_NHRPD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" #define QUAGGA_IP6_REDIST_STR_NHRPD \ "(kernel|connected|static|ripng|ospf6|isis|bgp|babel)" #define QUAGGA_IP6_REDIST_HELP_STR_NHRPD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Babel routing protocol (Babel)\n" /* ospf6d */ #define QUAGGA_REDIST_STR_OSPF6D \ "(kernel|connected|static|ripng|isis|bgp|babel|nhrp)" #define QUAGGA_REDIST_HELP_STR_OSPF6D \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" /* ospfd */ #define QUAGGA_REDIST_STR_OSPFD \ "(kernel|connected|static|rip|isis|bgp|pim|babel|nhrp)" #define QUAGGA_REDIST_HELP_STR_OSPFD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" /* pimd */ #define QUAGGA_REDIST_STR_PIMD \ "(kernel|connected|static|rip|ospf|isis|bgp|babel|nhrp)" #define QUAGGA_REDIST_HELP_STR_PIMD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" /* ripd */ #define QUAGGA_REDIST_STR_RIPD \ "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)" #define QUAGGA_REDIST_HELP_STR_RIPD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" /* ripngd */ #define QUAGGA_REDIST_STR_RIPNGD \ "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)" #define QUAGGA_REDIST_HELP_STR_RIPNGD \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" /* zebra */ #define QUAGGA_REDIST_STR_ZEBRA \ "(kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp|pim|babel|nhrp)" #define QUAGGA_REDIST_HELP_STR_ZEBRA \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #define QUAGGA_IP_REDIST_STR_ZEBRA \ "(kernel|connected|static|rip|ospf|isis|bgp|pim|babel|nhrp)" #define QUAGGA_IP_REDIST_HELP_STR_ZEBRA \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol (RIP)\n" \ "Open Shortest Path First (OSPFv2)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Protocol Independent Multicast (PIM)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #define QUAGGA_IP6_REDIST_STR_ZEBRA \ "(kernel|connected|static|ripng|ospf6|isis|bgp|babel|nhrp)" #define QUAGGA_IP6_REDIST_HELP_STR_ZEBRA \ "Kernel routes (not installed via the zebra RIB)\n" \ "Connected routes (directly attached subnet or host)\n" \ "Statically configured routes\n" \ "Routing Information Protocol next-generation (IPv6) (RIPng)\n" \ "Open Shortest Path First (IPv6) (OSPFv3)\n" \ "Intermediate System to Intermediate System (IS-IS)\n" \ "Border Gateway Protocol (BGP)\n" \ "Babel routing protocol (Babel)\n" \ "Next Hop Resolution Protocol (NHRP)\n" #ifdef QUAGGA_DEFINE_DESC_TABLE struct zebra_desc_table { unsigned int type; const char *string; char chr; }; #define DESC_ENTRY(T,S,C) [(T)] = { (T), (S), (C) } static const struct zebra_desc_table route_types[] = { DESC_ENTRY (ZEBRA_ROUTE_SYSTEM, "system", 'X' ), DESC_ENTRY (ZEBRA_ROUTE_KERNEL, "kernel", 'K' ), DESC_ENTRY (ZEBRA_ROUTE_CONNECT, "connected", 'C' ), DESC_ENTRY (ZEBRA_ROUTE_STATIC, "static", 'S' ), DESC_ENTRY (ZEBRA_ROUTE_RIP, "rip", 'R' ), DESC_ENTRY (ZEBRA_ROUTE_RIPNG, "ripng", 'R' ), DESC_ENTRY (ZEBRA_ROUTE_OSPF, "ospf", 'O' ), DESC_ENTRY (ZEBRA_ROUTE_OSPF6, "ospf6", 'O' ), DESC_ENTRY (ZEBRA_ROUTE_ISIS, "isis", 'I' ), DESC_ENTRY (ZEBRA_ROUTE_BGP, "bgp", 'B' ), DESC_ENTRY (ZEBRA_ROUTE_PIM, "pim", 'P' ), DESC_ENTRY (ZEBRA_ROUTE_HSLS, "hsls", 'H' ), DESC_ENTRY (ZEBRA_ROUTE_OLSR, "olsr", 'o' ), DESC_ENTRY (ZEBRA_ROUTE_BABEL, "babel", 'A' ), DESC_ENTRY (ZEBRA_ROUTE_NHRP, "nhrp", 'N' ), }; #undef DESC_ENTRY #endif /* QUAGGA_DEFINE_DESC_TABLE */ #endif /* _QUAGGA_ROUTE_TYPES_H */ quagga-1.2.4/lib/route_types.pl000077500000000000000000000122651325323223500164610ustar00rootroot00000000000000#!/usr/bin/perl ## ## Scan a file of route-type definitions (see eg route_types.txt) and ## generate a corresponding header file with: ## ## - enum of Zserv route-types ## - redistribute strings for the various Quagga daemons ## ## See route_types.txt for the format. ## ## ## Copyright (C) 2009 David Lamparter. ## This file is part of GNU Zebra. ## ## GNU Zebra is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by the ## Free Software Foundation; either version 2, or (at your option) any ## later version. ## ## GNU Zebra is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with GNU 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 strict; # input processing # my @protos; my %protodetail; my %daemons; while () { # skip comments and empty lines next if (/^\s*(#|$)/); # strip whitespace chomp; $_ =~ s/^\s*//; $_ =~ s/\s*$//; # match help strings if (/^(ZEBRA_ROUTE_[^\s]+)\s*,\s*"(.*)"$/) { $protodetail{$1}->{'longhelp'} = $2; next; } $_ =~ s/\s*,\s*/,/g; # else: 7-field line my @f = split(/,/, $_); unless (@f == 7) { die "invalid input on route_types line $.\n"; } my $proto = $f[0]; $f[3] = $1 if ($f[3] =~ /^'(.*)'$/); $f[6] = $1 if ($f[6] =~ /^"(.*)"$/); $protodetail{$proto} = { "number" => scalar @protos, "type" => $f[0], "cname" => $f[1], "daemon" => $f[2], "char" => $f[3], "ipv4" => int($f[4]), "ipv6" => int($f[5]), "shorthelp" => $f[6], }; push @protos, $proto; $daemons{$f[2]} = { "ipv4" => int($f[4]), "ipv6" => int($f[5]) } unless ($f[2] eq "NULL"); } # output printf <{"ipv4"}); push @protosv6, $p if ($protodetail{$p}->{"ipv6"}); } pop @protos; sub codelist { my (@protos) = @_; my (@lines) = (); my $str = " \"Codes: "; for my $p (@protos) { my $s = sprintf("%s - %s, ", $protodetail{$p}->{"char"}, $protodetail{$p}->{"shorthelp"}); if (length($str . $s) > 70) { $str =~ s/ $//; push @lines, $str . "%s\" \\\n"; $str = " \" "; } $str .= $s; } $str =~ s/ $//; push @lines, $str . "%s\" \\\n"; push @lines, " \" > - selected route, * - FIB route%s%s\", \\\n"; my @nl = (); for (my $c = 0; $c < @lines + 1; $c++) { push @nl, "VTY_NEWLINE" } return join("", @lines) ." ". join(", ", @nl); } print "\n"; printf "#define SHOW_ROUTE_V4_HEADER \\\n%s\n", codelist(@protosv4); printf "#define SHOW_ROUTE_V6_HEADER \\\n%s\n", codelist(@protosv6); print "\n"; sub collect { my ($daemon, $ipv4, $ipv6) = @_; my (@names, @help) = ((), ()); for my $p (@protos) { next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra"); next unless (($ipv4 && $protodetail{$p}->{"ipv4"}) || ($ipv6 && $protodetail{$p}->{"ipv6"})); push @names, $protodetail{$p}->{"cname"}; push @help, " \"".$protodetail{$p}->{"longhelp"}."\\n\""; } return ("\"(" . join("|", @names) . ")\"", join(" \\\n", @help)); } for my $daemon (sort keys %daemons) { next unless ($daemons{$daemon}->{"ipv4"} || $daemons{$daemon}->{"ipv6"}); printf "/* %s */\n", $daemon; if ($daemons{$daemon}->{"ipv4"} && $daemons{$daemon}->{"ipv6"}) { my ($names, $help) = collect($daemon, 1, 1); printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; ($names, $help) = collect($daemon, 1, 0); printf "#define QUAGGA_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; printf "#define QUAGGA_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; ($names, $help) = collect($daemon, 0, 1); printf "#define QUAGGA_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; printf "#define QUAGGA_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; } else { my ($names, $help) = collect($daemon, $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"}); printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; } print "\n"; } print <{"cname"}, $protodetail{$p}->{"char"}; } print < #include "linklist.h" #include "memory.h" #include "vector.h" #include "prefix.h" #include "routemap.h" #include "command.h" #include "vty.h" #include "log.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) (const char *); void (*delete_hook) (const char *); void (*event_hook) (route_map_event_t, const 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 (const 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 (const 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 (const 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. */ static struct route_map * route_map_get (const 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 const 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; } } static int route_map_empty (struct route_map *map) { if (map->head == NULL && map->tail == NULL) return 1; else return 0; } /* show route-map */ static void vty_show_route_map_entry (struct vty *vty, struct route_map *map) { struct route_map_index *index; struct route_map_rule *rule; /* Print the name of the protocol */ if (zlog_default) vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol], VTY_NEWLINE); 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); /* Description */ if (index->description) vty_out (vty, " Description:%s %s%s", VTY_NEWLINE, index->description, 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); 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); /* Call clause */ vty_out (vty, " Call clause:%s", VTY_NEWLINE); if (index->nextrm) vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE); /* Exit Policy */ vty_out (vty, " Action:%s", VTY_NEWLINE); if (index->exitpolicy == RMAP_GOTO) vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE); else if (index->exitpolicy == RMAP_NEXT) vty_out (vty, " Continue to next entry%s", VTY_NEWLINE); else if (index->exitpolicy == RMAP_EXIT) vty_out (vty, " Exit routemap%s", VTY_NEWLINE); } } static int vty_show_route_map (struct vty *vty, const 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; } } else { 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. */ static struct route_map_index * route_map_index_new (void) { 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; /* Free 'char *nextrm' if not NULL */ if (index->nextrm) XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm); /* 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. */ static 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. */ static 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. */ static 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 */ static struct route_map_rule * route_map_rule_new (void) { 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. */ static struct route_map_rule_cmd * route_map_lookup_match (const char *name) { unsigned int i; struct route_map_rule_cmd *rule; for (i = 0; i < vector_active (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. */ static struct route_map_rule_cmd * route_map_lookup_set (const char *name) { unsigned int i; struct route_map_rule_cmd *rule; for (i = 0; i < vector_active (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. */ static int rulecmp (const char *dst, const 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, const char *match_name, const 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, const char *match_name, const 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, const char *set_name, const 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, const char *set_name, const 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 action | cont | ------------------+--------------- | deny deny | cont | action) -Apply Set statements, accept route -If Call statement is present jump to the specified route-map, if it denies the route we finish. -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 deny) -Route is denied by route-map. cont) -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 "CALL", "NEXT" and "GOTO" call WORD - If this clause is matched, then the set statements are executed and then we jump to route-map 'WORD'. If this route-map denies the route, we finish, in other case we do whatever the exit policy (EXIT, NEXT or GOTO) tells. on-match next - If this clause is matched, then the set statements are executed and then we drop through to the next clause on-match goto 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 */ static route_map_result_t route_map_apply_match (struct route_map_rule_list *match_list, struct prefix *prefix, route_map_object_t type, void *object) { route_map_result_t ret = RMAP_NOMATCH; struct route_map_rule *match; /* Check all match rule and if there is no match rule, go to the set statement. */ if (!match_list->head) ret = RMAP_MATCH; else { for (match = match_list->head; match; match = match->next) { /* Try each match statement in turn, If any do not return RMAP_MATCH, return, otherwise continue on to next match statement. All match statements must match for end-result to be a match. */ ret = (*match->cmd->func_apply) (match->value, prefix, type, object); if (ret != RMAP_MATCH) return ret; } } return ret; } /* 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) { static int recursion = 0; int ret = 0; struct route_map_index *index; struct route_map_rule *set; if (recursion > RMAP_RECURSION_LIMIT) { zlog (NULL, LOG_WARNING, "route-map recursion limit (%d) reached, discarding route", RMAP_RECURSION_LIMIT); recursion = 0; return RMAP_DENYMATCH; } if (map == NULL) return RMAP_DENYMATCH; for (index = map->head; index; index = index->next) { /* Apply this index. */ ret = route_map_apply_match (&index->match_list, prefix, type, object); /* Now we apply the matrix from above */ if (ret == RMAP_NOMATCH) /* 'cont' from matrix - continue to next route-map sequence */ continue; else if (ret == RMAP_MATCH) { if (index->type == RMAP_PERMIT) /* 'action' */ { /* permit+match must execute sets */ for (set = index->set_list.head; set; set = set->next) ret = (*set->cmd->func_apply) (set->value, prefix, type, object); /* Call another route-map if available */ if (index->nextrm) { struct route_map *nextrm = route_map_lookup_by_name (index->nextrm); if (nextrm) /* Target route-map found, jump to it */ { recursion++; ret = route_map_apply (nextrm, prefix, type, object); recursion--; } /* If nextrm returned 'deny', finish. */ if (ret == RMAP_DENYMATCH) return ret; } switch (index->exitpolicy) { case RMAP_EXIT: return ret; case RMAP_NEXT: continue; case RMAP_GOTO: { /* Find the next clause to jump to */ struct route_map_index *next = index->next; int nextpref = index->nextpref; while (next && next->pref < nextpref) { index = next; next = next->next; } if (next == NULL) { /* No clauses match! */ return ret; } } } } else if (index->type == RMAP_DENY) /* 'deny' */ { return RMAP_DENYMATCH; } } } /* Finally route-map does not match at all. */ return RMAP_DENYMATCH; } void route_map_add_hook (void (*func) (const char *)) { route_map_master.add_hook = func; } void route_map_delete_hook (void (*func) (const char *)) { route_map_master.delete_hook = func; } void route_map_event_hook (void (*func) (route_map_event_t, const char *)) { route_map_master.event_hook = func; } void route_map_init (void) { /* Make vector for match and set. */ route_match_vec = vector_init (1); route_set_vec = vector_init (1); } void route_map_finish (void) { vector_free (route_match_vec); route_match_vec = NULL; vector_free (route_set_vec); route_set_vec = NULL; /* cleanup route_map */ while (route_map_master.head) route_map_delete (route_map_master.head); } /* 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_onmatch_next, rmap_onmatch_next_cmd, "on-match next", "Exit policy on matches\n" "Next clause\n") { struct route_map_index *index; index = vty->index; if (index) index->exitpolicy = RMAP_NEXT; return CMD_SUCCESS; } DEFUN (no_rmap_onmatch_next, no_rmap_onmatch_next_cmd, "no on-match next", NO_STR "Exit policy on matches\n" "Next clause\n") { struct route_map_index *index; index = vty->index; if (index) index->exitpolicy = RMAP_EXIT; return CMD_SUCCESS; } DEFUN (rmap_onmatch_goto, rmap_onmatch_goto_cmd, "on-match goto <1-65535>", "Exit policy on matches\n" "Goto Clause number\n" "Number\n") { struct route_map_index *index = vty->index; int d = 0; if (index) { if (argc == 1 && argv[0]) VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536); else d = index->pref + 1; if (d <= index->pref) { /* Can't allow you to do that, Dave */ vty_out (vty, "can't jump backwards in route-maps%s", VTY_NEWLINE); return CMD_WARNING; } else { index->exitpolicy = RMAP_GOTO; index->nextpref = d; } } return CMD_SUCCESS; } DEFUN (no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd, "no on-match goto", NO_STR "Exit policy on matches\n" "Goto Clause number\n") { struct route_map_index *index; index = vty->index; if (index) index->exitpolicy = RMAP_EXIT; return CMD_SUCCESS; } /* Cisco/GNU Zebra compatible ALIASes for on-match next */ ALIAS (rmap_onmatch_goto, rmap_continue_cmd, "continue", "Continue on a different entry within the route-map\n") ALIAS (no_rmap_onmatch_goto, no_rmap_continue_cmd, "no continue", NO_STR "Continue on a different entry within the route-map\n") /* GNU Zebra compatible */ ALIAS (rmap_onmatch_goto, rmap_continue_seq_cmd, "continue <1-65535>", "Continue on a different entry within the route-map\n" "Route-map entry sequence number\n") ALIAS (no_rmap_onmatch_goto, no_rmap_continue_seq, "no continue <1-65535>", NO_STR "Continue on a different entry within the route-map\n" "Route-map entry sequence number\n") DEFUN (rmap_show_name, rmap_show_name_cmd, "show route-map [WORD]", SHOW_STR "route-map information\n" "route-map name\n") { const char *name = NULL; if (argc) name = argv[0]; return vty_show_route_map (vty, name); } ALIAS (rmap_onmatch_goto, rmap_continue_index_cmd, "continue <1-65536>", "Exit policy on matches\n" "Goto Clause number\n") DEFUN (rmap_call, rmap_call_cmd, "call WORD", "Jump to another Route-Map after match+set\n" "Target route-map name\n") { struct route_map_index *index; index = vty->index; if (index) { if (index->nextrm) XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm); index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]); } return CMD_SUCCESS; } DEFUN (no_rmap_call, no_rmap_call_cmd, "no call", NO_STR "Jump to another Route-Map after match+set\n") { struct route_map_index *index; index = vty->index; if (index->nextrm) { XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm); index->nextrm = NULL; } return CMD_SUCCESS; } DEFUN (rmap_description, rmap_description_cmd, "description .LINE", "Route-map comment\n" "Comment describing this route-map rule\n") { struct route_map_index *index; index = vty->index; if (index) { if (index->description) XFREE (MTYPE_TMP, index->description); index->description = argv_concat (argv, argc, 0); } return CMD_SUCCESS; } DEFUN (no_rmap_description, no_rmap_description_cmd, "no description", NO_STR "Route-map comment\n") { struct route_map_index *index; index = vty->index; if (index) { if (index->description) XFREE (MTYPE_TMP, index->description); index->description = NULL; } return CMD_SUCCESS; } /* Configuration write function. */ static 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); if (index->description) vty_out (vty, " description %s%s", index->description, 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); 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); if (index->nextrm) vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE); if (index->exitpolicy == RMAP_GOTO) vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE); if (index->exitpolicy == RMAP_NEXT) vty_out (vty," on-match next%s", VTY_NEWLINE); write++; } return write; } /* Route map node structure. */ static struct cmd_node rmap_node = { RMAP_NODE, "%s(config-route-map)# ", 1 }; /* Common route map rules */ void * route_map_rule_tag_compile (const char *arg) { unsigned long int tmp; char *endptr; route_tag_t *tag; errno = 0; tmp = strtoul(arg, &endptr, 0); if (arg[0] == '\0' || *endptr != '\0' || errno || tmp > ROUTE_TAG_MAX) return NULL; tag = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*tag)); *tag = tmp; return tag; } void route_map_rule_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Initialization of route map vector. */ void route_map_init_vty (void) { /* 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_onmatch_next_cmd); install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd); install_element (RMAP_NODE, &rmap_onmatch_goto_cmd); install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd); /* Install the continue stuff (ALIAS of on-match). */ install_element (RMAP_NODE, &rmap_continue_cmd); install_element (RMAP_NODE, &no_rmap_continue_cmd); install_element (RMAP_NODE, &rmap_continue_index_cmd); /* Install the call stuff. */ install_element (RMAP_NODE, &rmap_call_cmd); install_element (RMAP_NODE, &no_rmap_call_cmd); /* Install description commands. */ install_element (RMAP_NODE, &rmap_description_cmd); install_element (RMAP_NODE, &no_rmap_description_cmd); /* Install show command */ install_element (ENABLE_NODE, &rmap_show_name_cmd); } quagga-1.2.4/lib/routemap.h000066400000000000000000000121451325323223500155410ustar00rootroot00000000000000/* 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 #include "prefix.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_BABEL, RMAP_OSPF, RMAP_OSPF6, RMAP_BGP, RMAP_ZEBRA, RMAP_ISIS, } 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; /* Depth limit in RMAP recursion using RMAP_CALL. */ #define RMAP_RECURSION_LIMIT 10 /* Route map rule structure for matching and setting. */ struct route_map_rule_cmd { /* Route map rule name (e.g. as-path, metric) */ const 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)(const 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; char *description; /* 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; /* If we're using "CALL", to which route-map do ew go? */ char *nextrm; /* 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. */ extern void route_map_init (void); extern void route_map_init_vty (void); extern void route_map_finish (void); /* Add match statement to route map. */ extern int route_map_add_match (struct route_map_index *index, const char *match_name, const char *match_arg); /* Delete specified route match rule. */ extern int route_map_delete_match (struct route_map_index *index, const char *match_name, const char *match_arg); /* Add route-map set statement to the route map. */ extern int route_map_add_set (struct route_map_index *index, const char *set_name, const char *set_arg); /* Delete route map set rule. */ extern int route_map_delete_set (struct route_map_index *index, const char *set_name, const char *set_arg); /* Install rule command to the match list. */ extern void route_map_install_match (struct route_map_rule_cmd *cmd); /* Install rule command to the set list. */ extern void route_map_install_set (struct route_map_rule_cmd *cmd); /* Lookup route map by name. */ extern struct route_map * route_map_lookup_by_name (const char *name); /* Apply route map to the object. */ extern route_map_result_t route_map_apply (struct route_map *map, struct prefix *, route_map_object_t object_type, void *object); extern void route_map_add_hook (void (*func) (const char *)); extern void route_map_delete_hook (void (*func) (const char *)); extern void route_map_event_hook (void (*func) (route_map_event_t, const char *)); extern void *route_map_rule_tag_compile (const char *arg); extern void route_map_rule_tag_free (void *rule); #endif /* _ZEBRA_ROUTEMAP_H */ quagga-1.2.4/lib/sigevent.c000066400000000000000000000201411325323223500155170ustar00rootroot00000000000000/* Quagga signal handling functions. * Copyright (C) 2004 Paul Jakma, * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 #ifdef SA_SIGINFO #ifdef HAVE_UCONTEXT_H #ifdef GNU_LINUX /* get REG_EIP from ucontext.h */ #ifndef __USE_GNU #define __USE_GNU #endif /* __USE_GNU */ #endif /* GNU_LINUX */ #include #endif /* HAVE_UCONTEXT_H */ #endif /* SA_SIGINFO */ /* master signals descriptor struct */ struct quagga_sigevent_master_t { struct thread *t; struct quagga_signal_t *signals; int sigc; volatile sig_atomic_t caught; } sigmaster; /* Generic signal handler * Schedules signal event thread */ static void quagga_signal_handler (int signo) { int i; struct quagga_signal_t *sig; for (i = 0; i < sigmaster.sigc; i++) { sig = &(sigmaster.signals[i]); if (sig->signal == signo) sig->caught = 1; } sigmaster.caught = 1; } /* check if signals have been caught and run appropriate handlers */ int quagga_sigevent_process (void) { struct quagga_signal_t *sig; int i; #ifdef SIGEVENT_BLOCK_SIGNALS /* shouldnt need to block signals, but potentially may be needed */ sigset_t newmask, oldmask; /* * Block most signals, but be careful not to defer SIGTRAP because * doing so breaks gdb, at least on NetBSD 2.0. Avoid asking to * block SIGKILL, just because we shouldn't be able to do so. */ sigfillset (&newmask); sigdelset (&newmask, SIGTRAP); sigdelset (&newmask, SIGKILL); if ( (sigprocmask (SIG_BLOCK, &newmask, &oldmask)) < 0) { zlog_err ("quagga_signal_timer: couldnt block signals!"); return -1; } #endif /* SIGEVENT_BLOCK_SIGNALS */ if (sigmaster.caught > 0) { sigmaster.caught = 0; /* must not read or set sigmaster.caught after here, * race condition with per-sig caught flags if one does */ for (i = 0; i < sigmaster.sigc; i++) { sig = &(sigmaster.signals[i]); if (sig->caught > 0) { sig->caught = 0; sig->handler (); } } } #ifdef SIGEVENT_BLOCK_SIGNALS if ( sigprocmask (SIG_UNBLOCK, &oldmask, NULL) < 0 ); return -1; #endif /* SIGEVENT_BLOCK_SIGNALS */ return 0; } #ifdef SIGEVENT_SCHEDULE_THREAD /* timer thread to check signals. Shouldnt be needed */ int quagga_signal_timer (struct thread *t) { struct quagga_sigevent_master_t *sigm; struct quagga_signal_t *sig; int i; sigm = THREAD_ARG (t); sigm->t = thread_add_timer (sigm->t->master, quagga_signal_timer, &sigmaster, QUAGGA_SIGNAL_TIMER_INTERVAL); return quagga_sigevent_process (); } #endif /* SIGEVENT_SCHEDULE_THREAD */ /* Initialization of signal handles. */ /* Signal wrapper. */ static int signal_set (int signo) { int ret; struct sigaction sig; struct sigaction osig; sig.sa_handler = &quagga_signal_handler; sigfillset (&sig.sa_mask); sig.sa_flags = 0; if (signo == SIGALRM) { #ifdef SA_INTERRUPT sig.sa_flags |= SA_INTERRUPT; /* SunOS */ #endif } else { #ifdef SA_RESTART sig.sa_flags |= SA_RESTART; #endif /* SA_RESTART */ } ret = sigaction (signo, &sig, &osig); if (ret < 0) return ret; else return 0; } #ifdef SA_SIGINFO /* XXX This function should be enhanced to support more platforms (it currently works only on Linux/x86). */ static void * program_counter(void *context) { #ifdef HAVE_UCONTEXT_H #ifdef GNU_LINUX /* these are from GNU libc, rather than Linux, strictly speaking */ # if defined(REG_EIP) # define REG_INDEX REG_EIP # elif defined(REG_RIP) # define REG_INDEX REG_RIP # elif defined(__powerpc__) # define REG_INDEX 32 # endif #elif defined(SUNOS_5) /* !GNU_LINUX */ # define REG_INDEX REG_PC #endif /* GNU_LINUX */ #ifdef REG_INDEX # ifdef HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS # define REGS gregs[REG_INDEX] # elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_UC_REGS) # define REGS uc_regs->gregs[REG_INDEX] # endif /* HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS */ #endif /* REG_INDEX */ #ifdef REGS if (context) return (void *)(((ucontext_t *)context)->uc_mcontext.REGS); #elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_REGS__NIP) /* older Linux / struct pt_regs ? */ if (context) return (void *)(((ucontext_t *)context)->uc_mcontext.regs->nip); #endif /* REGS */ #endif /* HAVE_UCONTEXT_H */ return NULL; } #endif /* SA_SIGINFO */ static void __attribute__ ((noreturn)) exit_handler(int signo #ifdef SA_SIGINFO , siginfo_t *siginfo, void *context #endif ) { zlog_signal(signo, "exiting..." #ifdef SA_SIGINFO , siginfo, program_counter(context) #endif ); _exit(128+signo); } static void __attribute__ ((noreturn)) core_handler(int signo #ifdef SA_SIGINFO , siginfo_t *siginfo, void *context #endif ) { zlog_signal(signo, "aborting..." #ifdef SA_SIGINFO , siginfo, program_counter(context) #endif ); /* dump memory stats on core */ log_memstats_stderr ("core_handler"); abort(); } static void trap_default_signals(void) { static const int core_signals[] = { SIGQUIT, SIGILL, #ifdef SIGEMT SIGEMT, #endif SIGFPE, SIGBUS, SIGSEGV, #ifdef SIGSYS SIGSYS, #endif #ifdef SIGXCPU SIGXCPU, #endif #ifdef SIGXFSZ SIGXFSZ, #endif }; static const int exit_signals[] = { SIGHUP, SIGINT, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2, #ifdef SIGPOLL SIGPOLL, #endif #ifdef SIGVTALRM SIGVTALRM, #endif #ifdef SIGSTKFLT SIGSTKFLT, #endif }; static const int ignore_signals[] = { SIGPIPE, }; static const struct { const int *sigs; u_int nsigs; void (*handler)(int signo #ifdef SA_SIGINFO , siginfo_t *info, void *context #endif ); } sigmap[] = { { core_signals, array_size(core_signals), core_handler}, { exit_signals, array_size(exit_signals), exit_handler}, { ignore_signals, array_size(ignore_signals), NULL}, }; u_int i; for (i = 0; i < array_size(sigmap); i++) { u_int j; for (j = 0; j < sigmap[i].nsigs; j++) { struct sigaction oact; if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) && (oact.sa_handler == SIG_DFL)) { struct sigaction act; sigfillset (&act.sa_mask); if (sigmap[i].handler == NULL) { act.sa_handler = SIG_IGN; act.sa_flags = 0; } else { #ifdef SA_SIGINFO /* Request extra arguments to signal handler. */ act.sa_sigaction = sigmap[i].handler; act.sa_flags = SA_SIGINFO; #else act.sa_handler = sigmap[i].handler; act.sa_flags = 0; #endif } if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0) zlog_warn("Unable to set signal handler for signal %d: %s", sigmap[i].sigs[j],safe_strerror(errno)); } } } } void signal_init (struct thread_master *m, int sigc, struct quagga_signal_t signals[]) { int i = 0; struct quagga_signal_t *sig; /* First establish some default handlers that can be overridden by the application. */ trap_default_signals(); while (i < sigc) { sig = &signals[i]; if ( signal_set (sig->signal) < 0 ) exit (-1); i++; } sigmaster.sigc = sigc; sigmaster.signals = signals; #ifdef SIGEVENT_SCHEDULE_THREAD sigmaster.t = thread_add_timer (m, quagga_signal_timer, &sigmaster, QUAGGA_SIGNAL_TIMER_INTERVAL); #endif /* SIGEVENT_SCHEDULE_THREAD */ } quagga-1.2.4/lib/sigevent.h000066400000000000000000000031531325323223500155300ustar00rootroot00000000000000/* * Quagga Signal handling header. * * Copyright (C) 2004 Paul Jakma. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_SIGNAL_H #define _QUAGGA_SIGNAL_H #include #define QUAGGA_SIGNAL_TIMER_INTERVAL 2L struct quagga_signal_t { int signal; /* signal number */ void (*handler) (void); /* handler to call */ volatile sig_atomic_t caught; /* private member */ }; /* initialise sigevent system * takes: * - pointer to valid struct thread_master * - number of elements in passed in signals array * - array of quagga_signal_t's describing signals to handle * and handlers to use for each signal */ extern void signal_init (struct thread_master *m, int sigc, struct quagga_signal_t *signals); /* check whether there are signals to handle, process any found */ extern int quagga_sigevent_process (void); #endif /* _QUAGGA_SIGNAL_H */ quagga-1.2.4/lib/smux.c000066400000000000000000001075041325323223500147000ustar00rootroot00000000000000/* 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 #if defined HAVE_SNMP && defined SNMP_SMUX #include #include #include "log.h" #include "thread.h" #include "linklist.h" #include "command.h" #include #include "memory.h" #include "sockunion.h" #include "smux.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 /* 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; }; #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 = NULL; size_t smux_oid_len; /* SMUX password. */ char *smux_passwd = NULL; /* 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. */ static struct cmd_node smux_node = { SMUX_NODE, "" /* SMUX has no interface. */ }; /* thread master */ static struct thread_master *smux_master; static 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; } static void smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len) { unsigned 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_debug ("%s: %s", prefix, buf); } static int smux_socket (void) { 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_STRUCT_SOCKADDR_IN_SIN_LEN serv.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_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; } static 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) { u_char buf[BUFSIZ]; u_char *ptr, *h1, *h1e, *h2, *h2e; size_t len, length; ptr = buf; len = BUFSIZ; length = len; if (debug_smux) { zlog_debug ("SMUX GETRSP send"); zlog_debug ("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_debug ("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_debug ("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_debug ("SMUX getresp send: %td", (ptr - buf)); send (smux_sock, buf, (ptr - buf), 0); } static u_char * smux_var (u_char *ptr, size_t 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_debug ("SMUX var parse: len %zd", len); /* Parse header. */ ptr = asn_parse_header (ptr, &len, &type); if (debug_smux) { zlog_debug ("SMUX var parse: type %d len %zd", type, len); zlog_debug ("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_debug ("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_debug ("ASN_NULL"); break; case ASN_INTEGER: zlog_debug ("ASN_INTEGER"); break; case ASN_COUNTER: case ASN_GAUGE: case ASN_TIMETICKS: case ASN_UINTEGER: zlog_debug ("ASN_COUNTER"); break; case ASN_COUNTER64: zlog_debug ("ASN_COUNTER64"); break; case ASN_IPADDRESS: zlog_debug ("ASN_IPADDRESS"); break; case ASN_OCTET_STR: zlog_debug ("ASN_OCTET_STR"); break; case ASN_OPAQUE: case ASN_NSAP: case ASN_OBJECT_ID: zlog_debug ("ASN_OPAQUE"); break; case SNMP_NOSUCHOBJECT: zlog_debug ("SNMP_NOSUCHOBJECT"); break; case SNMP_NOSUCHINSTANCE: zlog_debug ("SNMP_NOSUCHINSTANCE"); break; case SNMP_ENDOFMIBVIEW: zlog_debug ("SNMP_ENDOFMIBVIEW"); break; case ASN_BIT_STR: zlog_debug ("ASN_BIT_STR"); break; default: zlog_debug ("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. */ static 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; size_t suffix_len; int result; u_char *statP = NULL; WriteMethod *write_method = NULL; struct listnode *node, *nnode; /* Check */ for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree)) { 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_debug ("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); } 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; } static 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; size_t suffix_len; int result; WriteMethod *write_method=NULL; struct listnode *node, *nnode; /* Check */ for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree)) { 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_debug ("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; } static 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; size_t suffix_len; int result; WriteMethod *write_method=NULL; struct listnode *node, *nnode; /* Save incoming request. */ oid_copy (save, reqid, *reqid_len); savelen = *reqid_len; /* Check */ for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree)) { 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_debug ("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. */ static u_char * smux_parse_get_header (u_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_debug ("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_debug ("SMUX GET errstat %ld len: %zd", errstat, *len); /* Error index. */ ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex)); if (debug_smux) zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len); return ptr; } static void smux_parse_set (u_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_debug ("SMUX SET(%s) message parse: len %zd", (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_debug ("SMUX SET ret %d", ret); /* Return result. */ if (RESERVE1 == action) smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0); } static void smux_parse_get (u_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_debug ("SMUX GET message parse: len %zd", 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. */ static void smux_parse_close (u_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. */ static void smux_parse_rrsp (u_char *ptr, size_t len) { u_char val; long errstat; ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat)); if (debug_smux) zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat); } /* Parse SMUX message. */ static int smux_parse (u_char *ptr, size_t 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_debug ("SMUX message received type: %d rest len: %zd", 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_debug ("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_debug ("SMUX_CLOSE"); smux_parse_close (ptr, len); return -1; break; case SMUX_RRSP: /* This is response for register message. */ if (debug_smux) zlog_debug ("SMUX_RRSP"); smux_parse_rrsp (ptr, len); break; case SMUX_GET: /* Exact request for object id. */ if (debug_smux) zlog_debug ("SMUX_GET"); smux_parse_get (ptr, len, 1); break; case SMUX_GETNEXT: /* Next request for object id. */ if (debug_smux) zlog_debug ("SMUX_GETNEXT"); smux_parse_get (ptr, len, 0); break; case SMUX_SET: /* SMUX_SET is supported with some limitations. */ if (debug_smux) zlog_debug ("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. */ static 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_debug ("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", safe_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_debug ("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; } static int smux_open (int sock) { u_char buf[BUFSIZ]; u_char *ptr; size_t len; long version; const char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION; if (debug_smux) { smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len); zlog_debug ("SMUX open progname: %s", progname); zlog_debug ("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 (version)); /* 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), (const u_char *) progname, strlen (progname)); /* SMUX connection password. */ ptr = asn_build_string (ptr, &len, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), (u_char *)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); } /* `ename` is ignored. Instead of using the provided enterprise OID, the SMUX peer is used. This keep compatibility with the previous versions of Quagga. All other fields are used as they are intended. */ int smux_trap (struct variable *vp, size_t vp_len, const oid *ename, size_t enamelen, const oid *name, size_t namelen, const oid *iname, size_t inamelen, const struct trap_object *trapobj, size_t trapobjlen, u_char sptrap) { unsigned int i; u_char buf[BUFSIZ]; u_char *ptr; size_t 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 (addr)); /* Generic trap integer. */ val = SNMP_TRAP_ENTERPRISESPECIFIC; ptr = asn_build_int (ptr, &len, (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), (long *)&val, sizeof (val)); /* Specific trap integer. */ val = sptrap; ptr = asn_build_int (ptr, &len, (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), (long *)&val, sizeof (val)); /* Timeticks timestamp. */ val = 0; ptr = asn_build_unsigned_int (ptr, &len, (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS), &val, sizeof (val)); /* 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. */ if (trapobj[i].namelen > 0) { 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; } else { oid_copy (oid, name, namelen); oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1)); oid_len = namelen + trapobj[i].namelen * (-1) ; } if (debug_smux) { smux_oid_dump ("Trap", name, namelen); if (trapobj[i].namelen < 0) smux_oid_dump ("Trap", trapobj[i].name, (- 1) * (trapobj[i].namelen)); else { smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen)); smux_oid_dump ("Trap", iname, inamelen); } smux_oid_dump ("Trap", oid, oid_len); zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len); } ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len); if (debug_smux) zlog_debug ("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); } static int smux_register (int sock) { u_char buf[BUFSIZ]; u_char *ptr; int ret; size_t len; long priority; long operation; struct subtree *subtree; struct listnode *node, *nnode; ret = 0; for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree)) { ptr = buf; len = BUFSIZ; /* 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 (priority)); /* Operation. */ operation = 2; /* Register R/W */ ptr = asn_build_int (ptr, &len, (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), &operation, sizeof (operation)); if (debug_smux) { smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len); zlog_debug ("SMUX register priority: %ld", priority); zlog_debug ("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. */ static int smux_connect (struct thread *t) { int ret; if (debug_smux) zlog_debug ("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", safe_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", safe_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. */ static void smux_stop (void) { if (smux_read_thread) { thread_cancel (smux_read_thread); smux_read_thread = NULL; } if (smux_connect_thread) { thread_cancel (smux_connect_thread); smux_connect_thread = NULL; } if (smux_sock >= 0) { close (smux_sock); smux_sock = -1; } } void smux_event (enum smux_event event, int sock) { switch (event) { case SMUX_SCHEDULE: smux_connect_thread = thread_add_event (smux_master, smux_connect, NULL, 0); break; case SMUX_CONNECT: smux_connect_thread = thread_add_timer (smux_master, smux_connect, NULL, 10); break; case SMUX_READ: smux_read_thread = thread_add_read (smux_master, smux_read, NULL, sock); break; default: break; } } static int smux_str2oid (const 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; } static 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; } static int smux_peer_oid (struct vty *vty, const char *oid_str, const 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) { free (smux_oid); smux_oid = NULL; } /* careful, smux_passwd might point to string constant */ if (smux_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); else smux_passwd = strdup (""); return 0; } static int smux_peer_default (void) { if (smux_oid) { free (smux_oid); smux_oid = NULL; } /* careful, smux_passwd might be pointing at string constant */ if (smux_passwd) { free (smux_passwd); smux_passwd = NULL; } 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") { if (smux_peer_oid (vty, argv[0], NULL) == 0) { smux_start(); return CMD_SUCCESS; } else return CMD_WARNING; } 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") { if (smux_peer_oid (vty, argv[0], argv[1]) == 0) { smux_start(); return CMD_SUCCESS; } else return CMD_WARNING; } DEFUN (no_smux_peer, no_smux_peer_cmd, "no smux peer", NO_STR "SNMP MUX protocol settings\n" "SNMP MUX peer settings\n") { smux_stop(); return smux_peer_default (); } ALIAS (no_smux_peer, no_smux_peer_oid_cmd, "no smux peer OID", NO_STR "SNMP MUX protocol settings\n" "SNMP MUX peer settings\n" "SMUX peering object ID\n") ALIAS (no_smux_peer, no_smux_peer_oid_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") static int config_write_smux (struct vty *vty) { int first = 1; unsigned int i; if (smux_oid) { 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 (const 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); } /* 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 (struct thread_master *tm) { /* copy callers thread master */ smux_master = tm; /* 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_oid_cmd); install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd); } void smux_start(void) { /* Close any existing connections. */ smux_stop(); /* Schedule first connection. */ smux_event (SMUX_SCHEDULE, 0); } #endif /* HAVE_SNMP */ quagga-1.2.4/lib/smux.h000066400000000000000000000072361325323223500147060ustar00rootroot00000000000000/* 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 #include #include #include "thread.h" /* 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) #undef REGISTER_MIB #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)) struct trap_object { int namelen; /* Negative if the object is not indexed */ oid name[MAX_OID_LEN]; }; /* Declare SMUX return value. */ #define SNMP_LOCAL_VARIABLES \ static long snmp_int_val __attribute__ ((unused)); \ static struct in_addr snmp_in_addr_val __attribute__ ((unused)); #define SNMP_INTEGER(V) \ ( \ *var_len = sizeof (snmp_int_val), \ 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 \ ) extern void smux_init (struct thread_master *tm); extern void smux_register_mib(const char *, struct variable *, size_t, int, oid [], size_t); extern int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); extern int smux_header_table (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); /* For traps, three OID are provided: 1. The enterprise OID to use (the last argument will be appended to it to form the SNMP trap OID) 2. The base OID for objects to be sent in traps. 3. The index OID for objects to be sent in traps. This index is used to designate a particular instance of a column. The provided trap object contains the bindings to be sent with the trap. The base OID will be prefixed to the provided OID and, if the length is positive, the requested OID is assumed to be a columnar object and the index OID will be appended. The two first arguments are the MIB registry used to locate the trap objects. The use of the arguments may differ depending on the implementation used. */ extern int smux_trap (struct variable *, size_t, const oid *, size_t, const oid *, size_t, const oid *, size_t, const struct trap_object *, size_t, u_char); extern int oid_compare (const oid *, int, const oid *, int); extern void oid2in_addr (oid [], int, struct in_addr *); extern void *oid_copy (void *, const void *, size_t); extern void oid_copy_addr (oid [], struct in_addr *, int); #endif /* _ZEBRA_SNMP_H */ quagga-1.2.4/lib/snmp.c000066400000000000000000000057641325323223500146660ustar00rootroot00000000000000/* 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 #include #include #include "smux.h" #define min(A,B) ((A) < (B) ? (A) : (B)) int oid_compare (const oid *o1, int o1_len, const 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; } void * oid_copy (void *dest, const 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 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_header_table (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { /* If the requested OID name is less than OID prefix we handle, adjust it to our prefix. */ if ((oid_compare (name, *length, v->name, v->namelen)) < 0) { if (exact) return MATCH_FAILED; oid_copy(name, v->name, v->namelen); *length = v->namelen; } *write_method = 0; *var_len = sizeof(long); return MATCH_SUCCEEDED; } #endif /* HAVE_SNMP */ quagga-1.2.4/lib/sockopt.c000066400000000000000000000450371325323223500153700ustar00rootroot00000000000000/* 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 #ifdef SUNOS_5 #include #endif #include "log.h" #include "sockopt.h" #include "sockunion.h" int setsockopt_so_recvbuf (int sock, int size) { int ret; if ( (ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (int))) < 0) zlog_err ("fd %d: can't setsockopt SO_RCVBUF to %d: %s", sock,size,safe_strerror(errno)); return ret; } int setsockopt_so_sendbuf (const int sock, int size) { int ret = setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof (int)); if (ret < 0) zlog_err ("fd %d: can't setsockopt SO_SNDBUF to %d: %s", sock, size, safe_strerror (errno)); return ret; } int getsockopt_so_sendbuf (const int sock) { u_int32_t optval; socklen_t optlen = sizeof (optval); int ret = getsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *)&optval, &optlen); if (ret < 0) { zlog_err ("fd %d: can't getsockopt SO_SNDBUF: %d (%s)", sock, errno, safe_strerror (errno)); return ret; } return optval; } static void * getsockopt_cmsg_data (struct msghdr *msgh, int level, int type) { struct cmsghdr *cmsg; void *ptr = NULL; for (cmsg = ZCMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(msgh, cmsg)) if (cmsg->cmsg_level == level && cmsg->cmsg_type) return (ptr = CMSG_DATA(cmsg)); return NULL; } #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", safe_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", safe_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; } static int getsockopt_ipv6_ifindex (struct msghdr *msgh) { struct in6_pktinfo *pktinfo; pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO); return pktinfo->ipi6_ifindex; } int setsockopt_ipv6_tclass(int sock, int tclass) { int ret = 0; #ifdef IPV6_TCLASS /* RFC3542 */ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof (tclass)); if (ret < 0) zlog_warn ("Can't set IPV6_TCLASS option for fd %d to %#x: %s", sock, tclass, safe_strerror(errno)); #endif return ret; } #endif /* HAVE_IPV6 */ /* * Process multicast socket options for IPv4 in an OS-dependent manner. * Supported options are IP_{ADD,DROP}_MEMBERSHIP. * * Many operating systems have a limit on the number of groups that * can be joined per socket (where each group and local address * counts). This impacts OSPF, which joins groups on each interface * using a single socket. The limit is typically 20, derived from the * original BSD multicast implementation. Some systems have * mechanisms for increasing this limit. * * In many 4.4BSD-derived systems, multicast group operations are not * allowed on interfaces that are not UP. Thus, a previous attempt to * leave the group may have failed, leaving it still joined, and we * drop/join quietly to recover. This may not be necessary, but aims to * defend against unknown behavior in that we will still return an error * if the second join fails. It is not clear how other systems * (e.g. Linux, Solaris) behave when leaving groups on down interfaces, * but this behavior should not be harmful if they behave the same way, * allow leaves, or implicitly leave all groups joined to down interfaces. */ int setsockopt_ipv4_multicast(int sock, int optname, unsigned int mcast_addr, ifindex_t ifindex) { #ifdef HAVE_RFC3678 struct group_req gr; struct sockaddr_in *si; int ret; memset (&gr, 0, sizeof(gr)); si = (struct sockaddr_in *)&gr.gr_group; gr.gr_interface = ifindex; si->sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN si->sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ si->sin_addr.s_addr = mcast_addr; ret = setsockopt(sock, IPPROTO_IP, (optname == IP_ADD_MEMBERSHIP) ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr)); if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) { setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr)); ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr)); } return ret; #elif defined(HAVE_STRUCT_IP_MREQN_IMR_IFINDEX) && !defined(__FreeBSD__) struct ip_mreqn mreqn; int ret; assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP); memset (&mreqn, 0, sizeof(mreqn)); mreqn.imr_multiaddr.s_addr = mcast_addr; mreqn.imr_ifindex = ifindex; ret = setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn)); if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) { /* see above: handle possible problem when interface comes back up */ char buf[1][INET_ADDRSTRLEN]; zlog_info("setsockopt_ipv4_multicast attempting to drop and " "re-add (fd %d, mcast %s, ifindex %u)", sock, inet_ntop(AF_INET, &mreqn.imr_multiaddr, buf[0], sizeof(buf[0])), ifindex); setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreqn, sizeof(mreqn)); ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreqn, sizeof(mreqn)); } return ret; /* 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! */ #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */ /* standard BSD API */ struct in_addr m; struct ip_mreq mreq; int ret; assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP); m.s_addr = htonl(ifindex); memset (&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr.s_addr = mcast_addr; mreq.imr_interface = m; ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq)); if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) { /* see above: handle possible problem when interface comes back up */ char buf[1][INET_ADDRSTRLEN]; zlog_info("setsockopt_ipv4_multicast attempting to drop and " "re-add (fd %d, mcast %s, ifindex %u)", sock, inet_ntop(AF_INET, &mreq.imr_multiaddr, buf[0], sizeof(buf[0])), ifindex); setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)); ret = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)); } return ret; #else #error "Unsupported multicast API" #endif /* #if OS_TYPE */ } /* * Set IP_MULTICAST_IF socket option in an OS-dependent manner. */ int setsockopt_ipv4_multicast_if(int sock, ifindex_t ifindex) { #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX struct ip_mreqn mreqn; memset (&mreqn, 0, sizeof(mreqn)); mreqn.imr_ifindex = ifindex; return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn)); /* Example defines for another OS, boilerplate off other code in this function */ /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */ /* Add your favourite OS here! */ #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) struct in_addr m; m.s_addr = htonl(ifindex); return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m)); #elif defined(SUNOS_5) char ifname[IF_NAMESIZE]; struct ifaddrs *ifa, *ifap; struct in_addr ifaddr; if (if_indextoname(ifindex, ifname) == NULL) return -1; if (getifaddrs(&ifa) != 0) return -1; for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { struct sockaddr_in *sa; if (strcmp(ifap->ifa_name, ifname) != 0) continue; if (ifap->ifa_addr->sa_family != AF_INET) continue; sa = (struct sockaddr_in*)ifap->ifa_addr; memcpy(&ifaddr, &sa->sin_addr, sizeof(ifaddr)); break; } freeifaddrs(ifa); if (!ifap) /* This means we did not find an IP */ return -1; return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&ifaddr, sizeof(ifaddr)); #else #error "Unsupported multicast API" #endif } static int setsockopt_ipv4_ifindex (int sock, ifindex_t val) { int ret; #if defined (IP_PKTINFO) if ((ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val))) < 0) zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s", sock,val,safe_strerror(errno)); #elif defined (IP_RECVIF) if ((ret = setsockopt (sock, IPPROTO_IP, IP_RECVIF, &val, sizeof (val))) < 0) zlog_warn ("Can't set IP_RECVIF option for fd %d to %d: %s", sock,val,safe_strerror(errno)); #else #warning "Neither IP_PKTINFO nor IP_RECVIF is available." #warning "Will not be able to receive link info." #warning "Things might be seriously broken.." /* XXX Does this ever happen? Should there be a zlog_warn message here? */ ret = -1; #endif return ret; } int setsockopt_ipv4_tos(int sock, int tos) { int ret; ret = setsockopt (sock, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)); if (ret < 0) zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s", sock, tos, safe_strerror(errno)); return ret; } int setsockopt_ifindex (int af, int sock, ifindex_t val) { int ret = -1; switch (af) { case AF_INET: ret = setsockopt_ipv4_ifindex (sock, val); break; #ifdef HAVE_IPV6 case AF_INET6: ret = setsockopt_ipv6_pktinfo (sock, val); break; #endif default: zlog_warn ("setsockopt_ifindex: unknown address family %d", af); } return ret; } /* * Requires: msgh is not NULL and points to a valid struct msghdr, which * may or may not have control data about the incoming interface. * * Returns the interface index (small integer >= 1) if it can be * determined, or else 0. */ static ifindex_t getsockopt_ipv4_ifindex (struct msghdr *msgh) { /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */ ifindex_t ifindex = -1; #if defined(IP_PKTINFO) /* Linux pktinfo based ifindex retrieval */ struct in_pktinfo *pktinfo; pktinfo = (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO); /* XXX Can pktinfo be NULL? Clean up post 0.98. */ ifindex = pktinfo->ipi_ifindex; #elif defined(IP_RECVIF) /* retrieval based on IP_RECVIF */ #ifndef SUNOS_5 /* BSD systems use a sockaddr_dl as the control message payload. */ struct sockaddr_dl *sdl; #else /* SUNOS_5 uses an integer with the index. */ ifindex_t *ifindex_p; #endif /* SUNOS_5 */ #ifndef SUNOS_5 /* BSD */ sdl = (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); if (sdl != NULL) ifindex = sdl->sdl_index; else ifindex = 0; #else /* * Solaris. On Solaris 8, IP_RECVIF is defined, but the call to * enable it fails with errno=99, and the struct msghdr has * controllen 0. */ ifindex_p = (uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); if (ifindex_p != NULL) ifindex = *ifindex_p; else ifindex = 0; #endif /* SUNOS_5 */ #else /* * Neither IP_PKTINFO nor IP_RECVIF defined - warn at compile time. * XXX Decide if this is a core service, or if daemons have to cope. * Since Solaris 8 and OpenBSD seem not to provide it, it seems that * daemons have to cope. */ #warning "getsockopt_ipv4_ifindex: Neither IP_PKTINFO nor IP_RECVIF defined." #warning "Some daemons may fail to operate correctly!" ifindex = 0; #endif /* IP_PKTINFO */ return ifindex; } /* return ifindex, 0 if none found */ ifindex_t getsockopt_ifindex (int af, struct msghdr *msgh) { switch (af) { case AF_INET: return (getsockopt_ipv4_ifindex (msgh)); break; #ifdef HAVE_IPV6 case AF_INET6: return (getsockopt_ipv6_ifindex (msgh)); break; #endif default: zlog_warn ("getsockopt_ifindex: unknown address family %d", af); return 0; } } /* swab iph between order system uses for IP_HDRINCL and host order */ void sockopt_iphdrincl_swab_htosys (struct ip *iph) { /* BSD and derived take iph in network order, except for * ip_len and ip_off */ #ifndef HAVE_IP_HDRINCL_BSD_ORDER iph->ip_len = htons(iph->ip_len); iph->ip_off = htons(iph->ip_off); #endif /* HAVE_IP_HDRINCL_BSD_ORDER */ iph->ip_id = htons(iph->ip_id); } void sockopt_iphdrincl_swab_systoh (struct ip *iph) { #ifndef HAVE_IP_HDRINCL_BSD_ORDER iph->ip_len = ntohs(iph->ip_len); iph->ip_off = ntohs(iph->ip_off); #endif /* HAVE_IP_HDRINCL_BSD_ORDER */ iph->ip_id = ntohs(iph->ip_id); } int sockopt_tcp_rtt (int sock) { #ifdef TCP_INFO struct tcp_info ti; socklen_t len = sizeof(ti); if (getsockopt (sock, IPPROTO_TCP, TCP_INFO, &ti, &len) != 0) return 0; return ti.tcpi_rtt / 1000; #else return 0; #endif } int sockopt_tcp_signature (int sock, union sockunion *su, const char *password) { #if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX) /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's * version of the Quagga patch (based on work by Rick Payne, and Bruce * Simpson) */ #define TCP_MD5_AUTH 13 #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 */ } cmd; struct in_addr *addr = &su->sin.sin_addr; cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL); cmd.address = addr->s_addr; cmd.keylen = (password != NULL ? strlen (password) : 0); cmd.key = password; return setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd); #elif HAVE_DECL_TCP_MD5SIG int ret; #ifndef GNU_LINUX /* * XXX Need to do PF_KEY operation here to add/remove an SA entry, * and add/remove an SP entry for this peer's packet flows also. */ int md5sig = password && *password ? 1 : 0; #else int keylen = password ? strlen (password) : 0; struct tcp_md5sig md5sig; union sockunion *su2, *susock; /* Figure out whether the socket and the sockunion are the same family.. * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think.. */ if (!(susock = sockunion_getsockname (sock))) return -1; if (susock->sa.sa_family == su->sa.sa_family) su2 = su; else { /* oops.. */ su2 = susock; if (su2->sa.sa_family == AF_INET) { sockunion_free (susock); return 0; } #ifdef HAVE_IPV6 /* If this does not work, then all users of this sockopt will need to * differentiate between IPv4 and IPv6, and keep seperate sockets for * each. * * Sadly, it doesn't seem to work at present. It's unknown whether * this is a bug or not. */ if (su2->sa.sa_family == AF_INET6 && su->sa.sa_family == AF_INET) { su2->sin6.sin6_family = AF_INET6; /* V4Map the address */ memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr)); su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4); } #endif } memset (&md5sig, 0, sizeof (md5sig)); memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2)); md5sig.tcpm_keylen = keylen; if (keylen) memcpy (md5sig.tcpm_key, password, keylen); sockunion_free (susock); #endif /* GNU_LINUX */ if ((ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0) { /* ENOENT is harmless. It is returned when we clear a password for which one was not previously set. */ if (ENOENT == errno) ret = 0; else zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s", sock, safe_strerror(errno)); } return ret; #else /* HAVE_TCP_MD5SIG */ return -2; #endif /* !HAVE_TCP_MD5SIG */ } quagga-1.2.4/lib/sockopt.h000066400000000000000000000076211325323223500153720ustar00rootroot00000000000000/* 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 #include "sockunion.h" extern int setsockopt_so_recvbuf (int sock, int size); extern int setsockopt_so_sendbuf (const int sock, int size); extern int getsockopt_so_sendbuf (const int sock); #ifdef HAVE_IPV6 extern int setsockopt_ipv6_pktinfo (int, int); extern int setsockopt_ipv6_checksum (int, int); extern int setsockopt_ipv6_multicast_hops (int, int); extern int setsockopt_ipv6_unicast_hops (int, int); extern int setsockopt_ipv6_hoplimit (int, int); extern int setsockopt_ipv6_multicast_loop (int, int); extern int setsockopt_ipv6_tclass (int, int); #endif /* HAVE_IPV6 */ /* * It is OK to reference in6_pktinfo here without a protecting #if * because this macro will only be used #if HAVE_IPV6, and in6_pktinfo * is not optional for HAVE_IPV6. */ #define SOPT_SIZE_CMSG_PKTINFO_IPV6() (sizeof (struct in6_pktinfo)); /* * Size defines for control messages used to get ifindex. We define * values for each method, and define a macro that can be used by code * that is unaware of which method is in use. * These values are without any alignment needed (see CMSG_SPACE in RFC3542). */ #if defined (IP_PKTINFO) /* Linux in_pktinfo. */ #define SOPT_SIZE_CMSG_PKTINFO_IPV4() (CMSG_SPACE(sizeof (struct in_pktinfo))) /* XXX This should perhaps be defined even if IP_PKTINFO is not. */ #define SOPT_SIZE_CMSG_PKTINFO(af) \ ((af == AF_INET) ? SOPT_SIZE_CMSG_PKTINFO_IPV4() \ : SOPT_SIZE_CMSG_PKTINFO_IPV6() #endif /* IP_PKTINFO */ #if defined (IP_RECVIF) /* BSD/Solaris */ #if defined (SUNOS_5) #define SOPT_SIZE_CMSG_RECVIF_IPV4() (sizeof (uint_t)) #else #define SOPT_SIZE_CMSG_RECVIF_IPV4() (sizeof (struct sockaddr_dl)) #endif /* SUNOS_5 */ #endif /* IP_RECVIF */ /* SOPT_SIZE_CMSG_IFINDEX_IPV4 - portable type */ #if defined (SOPT_SIZE_CMSG_PKTINFO) #define SOPT_SIZE_CMSG_IFINDEX_IPV4() SOPT_SIZE_CMSG_PKTINFO_IPV4() #elif defined (SOPT_SIZE_CMSG_RECVIF_IPV4) #define SOPT_SIZE_CMSG_IFINDEX_IPV4() SOPT_SIZE_CMSG_RECVIF_IPV4() #else /* Nothing available */ #define SOPT_SIZE_CMSG_IFINDEX_IPV4() (sizeof (char *)) #endif /* SOPT_SIZE_CMSG_IFINDEX_IPV4 */ #define SOPT_SIZE_CMSG_IFINDEX(af) \ (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \ ? SOPT_SIZE_CMSG_PKTINFO_IPV6()) extern int setsockopt_ipv4_multicast_if(int sock, ifindex_t ifindex); extern int setsockopt_ipv4_multicast(int sock, int optname, unsigned int mcast_addr, ifindex_t ifindex); extern int setsockopt_ipv4_tos(int sock, int tos); /* Ask for, and get, ifindex, by whatever method is supported. */ extern int setsockopt_ifindex (int, int, ifindex_t); extern ifindex_t getsockopt_ifindex (int, struct msghdr *); /* swab the fields in iph between the host order and system order expected * for IP_HDRINCL. */ extern void sockopt_iphdrincl_swab_htosys (struct ip *iph); extern void sockopt_iphdrincl_swab_systoh (struct ip *iph); extern int sockopt_tcp_rtt (int); extern int sockopt_tcp_signature(int sock, union sockunion *su, const char *password); #endif /*_ZEBRA_SOCKOPT_H */ quagga-1.2.4/lib/sockunion.c000066400000000000000000000440511325323223500157110ustar00rootroot00000000000000/* 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" #include "jhash.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 (const 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 (const 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_STRUCT_SOCKADDR_IN_SIN_LEN su->sin.sin_len = sizeof(struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_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 (const union sockunion *su, char *buf, size_t len) { switch (sockunion_family(su)) { case AF_UNSPEC: snprintf (buf, len, "(unspec)"); return buf; case AF_INET: return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len); #ifdef HAVE_IPV6 case AF_INET6: return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len); #endif /* HAVE_IPV6 */ } snprintf (buf, len, "(af %d)", sockunion_family(su)); return buf; } union sockunion * sockunion_str2su (const char *str) { union sockunion *su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); if (!str2sockunion (str, su)) return su; XFREE (MTYPE_SOCKUNION, su); return NULL; } /* Convert IPv4 compatible IPv6 address to IPv4 address. */ static void sockunion_normalise_mapped (union sockunion *su) { struct sockaddr_in sin; #ifdef HAVE_IPV6 if (su->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) { memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = su->sin6.sin6_port; memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); memcpy (su, &sin, sizeof (struct sockaddr_in)); } #endif /* HAVE_IPV6 */ } /* Return socket of sockunion. */ int sockunion_socket (const 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", safe_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); sockunion_normalise_mapped (su); return client_sock; } /* Return sizeof union sockunion. */ static int sockunion_sizeof (const 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. */ static const char * sockunion_log (const union sockunion *su, char *buf, size_t len) { switch (su->sa.sa_family) { case AF_INET: return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len); #ifdef HAVE_IPV6 case AF_INET6: return inet_ntop(AF_INET6, &(su->sin6.sin6_addr), buf, len); break; #endif /* HAVE_IPV6 */ default: snprintf (buf, len, "af_unknown %d ", su->sa.sa_family); return buf; } } /* sockunion_connect returns -1 : error occurred 0 : connect success 1 : connect is in progress */ enum connect_result sockunion_connect (int fd, const union sockunion *peersu, unsigned short port, ifindex_t 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_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID /* su.sin6.sin6_scope_id = ifindex; */ #endif /* HAVE_STRUCT_SOCKADDR_IN6_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) { char str[SU_ADDRSTRLEN]; zlog_info ("can't connect to %s fd %d : %s", sockunion_log (&su, str, sizeof str), fd, safe_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_STRUCT_SOCKADDR_IN_SIN_LEN su->sin.sin_len = size; #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ if (su_addr == NULL) sockunion2ip (su) = 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) { #ifdef LINUX_IPV6 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", safe_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_REUSEPORT 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; } int sockopt_cork (int sock, int onoff) { #ifdef TCP_CORK return setsockopt (sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff)); #else return 0; #endif } int sockopt_minttl (int family, int sock, int minttl) { #ifdef IP_MINTTL if (family == AF_INET) { int ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl)); if (ret < 0) zlog (NULL, LOG_WARNING, "can't set sockopt IP_MINTTL to %d on socket %d: %s", minttl, sock, safe_strerror (errno)); return ret; } #endif /* IP_MINTTL */ #ifdef IPV6_MINHOPCNT if (family == AF_INET6) { int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl)); if (ret < 0) zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s", minttl, sock, safe_strerror (errno)); return ret; } #endif errno = EOPNOTSUPP; return -1; } int sockopt_v6only (int family, int sock) { int ret, on = 1; #ifdef HAVE_IPV6 #ifdef IPV6_V6ONLY if (family == AF_INET6) { ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &on, sizeof (int)); if (ret < 0) { zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_V6ONLY " "to socket %d", sock); return -1; } return 0; } #endif /* IPV6_V6ONLY */ #endif /* HAVE_IPV6 */ return 0; } /* If same family and same prefix return 1. */ int sockunion_same (const union sockunion *su1, const 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; } unsigned int sockunion_hash (const union sockunion *su) { switch (sockunion_family(su)) { case AF_INET: return jhash_1word(su->sin.sin_addr.s_addr, 0); #ifdef HAVE_IPV6 case AF_INET6: return jhash2(su->sin6.sin6_addr.s6_addr32, ZEBRA_NUM_OF(su->sin6.sin6_addr.s6_addr32), 0); #endif /* HAVE_IPV6 */ } return 0; } size_t family2addrsize(int family) { switch (family) { case AF_INET: return sizeof(struct in_addr); #ifdef HAVE_IPV6 case AF_INET6: return sizeof(struct in6_addr); #endif /* HAVE_IPV6 */ } return 0; } size_t sockunion_get_addrlen(const union sockunion *su) { return family2addrsize(sockunion_family(su)); } const u_char * sockunion_get_addr(const union sockunion *su) { switch (sockunion_family(su)) { case AF_INET: return (const u_char *) &su->sin.sin_addr.s_addr; #ifdef HAVE_IPV6 case AF_INET6: return (const u_char *) &su->sin6.sin6_addr; #endif /* HAVE_IPV6 */ } return NULL; } unsigned short sockunion_get_port (const union sockunion *su) { switch (sockunion_family (su)) { case AF_INET: return ntohs(su->sin.sin_port); #ifdef HAVE_IPV6 case AF_INET6: return ntohs(su->sin6.sin6_port); #endif /* HAVE_IPV6 */ } return 0; } void sockunion_set(union sockunion *su, int family, const u_char *addr, size_t bytes) { if (family2addrsize(family) != bytes) return; sockunion_family(su) = family; switch (family) { case AF_INET: memcpy(&su->sin.sin_addr.s_addr, addr, bytes); break; #ifdef HAVE_IPV6 case AF_INET6: memcpy(&su->sin6.sin6_addr, addr, bytes); break; #endif /* HAVE_IPV6 */ } } /* After TCP connection is established. Get local address and port. */ union sockunion * sockunion_getsockname (int fd) { int ret; socklen_t 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", safe_strerror (errno)); return NULL; } if (name.sa.sa_family == AF_INET) { su = XCALLOC (MTYPE_SOCKUNION, 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_SOCKUNION, sizeof (union sockunion)); memcpy (su, &name, sizeof (struct sockaddr_in6)); sockunion_normalise_mapped (su); 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; socklen_t 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", safe_strerror (errno)); return NULL; } if (name.sa.sa_family == AF_INET) { su = XCALLOC (MTYPE_SOCKUNION, 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_SOCKUNION, sizeof (union sockunion)); memcpy (su, &name, sizeof (struct sockaddr_in6)); sockunion_normalise_mapped (su); return su; } #endif /* HAVE_IPV6 */ return NULL; } /* Print sockunion structure */ static void __attribute__ ((unused)) sockunion_print (const 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 [SU_ADDRSTRLEN]; 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 static int in6addr_cmp (const struct in6_addr *addr1, const struct in6_addr *addr2) { unsigned 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 (const union sockunion *su1, const 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 (sockunion2ip (su1)) == ntohl (sockunion2ip (su2))) return 0; if (ntohl (sockunion2ip (su1)) > ntohl (sockunion2ip (su2))) 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 (const 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); } quagga-1.2.4/lib/sockunion.h000066400000000000000000000105221325323223500157120ustar00rootroot00000000000000/* * 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 #include "if.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 */ #define sockunion_family(X) (X)->sa.sa_family #define sockunion2ip(X) (X)->sin.sin_addr.s_addr /* Prototypes. */ extern int str2sockunion (const char *, union sockunion *); extern const char *sockunion2str (const union sockunion *, char *, size_t); extern int sockunion_cmp (const union sockunion *, const union sockunion *); extern int sockunion_same (const union sockunion *, const union sockunion *); extern unsigned int sockunion_hash (const union sockunion *); extern size_t family2addrsize(int family); extern size_t sockunion_get_addrlen(const union sockunion *); extern const u_char *sockunion_get_addr(const union sockunion *); extern unsigned short sockunion_get_port (const union sockunion *); extern void sockunion_set(union sockunion *, int family, const u_char *addr, size_t bytes); extern union sockunion *sockunion_str2su (const char *str); extern int sockunion_accept (int sock, union sockunion *); extern int sockunion_stream_socket (union sockunion *); extern int sockopt_reuseaddr (int); extern int sockopt_reuseport (int); extern int sockopt_v6only (int family, int sock); extern int sockunion_bind (int sock, union sockunion *, unsigned short, union sockunion *); extern int sockopt_ttl (int family, int sock, int ttl); extern int sockopt_minttl (int family, int sock, int minttl); extern int sockopt_cork (int sock, int onoff); extern int sockunion_socket (const union sockunion *su); extern const char *inet_sutop (const union sockunion *su, char *str); extern enum connect_result sockunion_connect (int fd, const union sockunion *su, unsigned short port, ifindex_t); extern union sockunion *sockunion_getsockname (int); extern union sockunion *sockunion_getpeername (int); extern union sockunion *sockunion_dup (const union sockunion *); extern void sockunion_free (union sockunion *); #ifndef HAVE_INET_NTOP extern const char * inet_ntop (int family, const void *addrptr, char *strptr, size_t len); #endif /* HAVE_INET_NTOP */ #ifndef HAVE_INET_PTON extern int inet_pton (int family, const char *strptr, void *addrptr); #endif /* HAVE_INET_PTON */ #ifndef HAVE_INET_ATON extern int inet_aton (const char *cp, struct in_addr *inaddr); #endif #endif /* _ZEBRA_SOCKUNION_H */ quagga-1.2.4/lib/str.c000066400000000000000000000056611325323223500145150ustar00rootroot00000000000000/* * zebra string function * * XXX This version of snprintf does not check bounds! */ /* The implementations of strlcpy and strlcat are copied from rsync (GPL): Copyright (C) Andrew Tridgell 1998 Copyright (C) 2002 by Martin Pool Note that these are not terribly efficient, since they make more than one pass over the argument strings. At some point, they should be optimized. The implementation of strndup is copied from glibc-2.3.5: Copyright (C) 1996, 1997, 1998, 2001, 2002 Free Software Foundation, Inc. */ /* * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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_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 /** * Like strncpy but does not 0 fill the buffer and always null * terminates. * * @param bufsize is the size of the destination buffer. * * @return index of the terminating byte. **/ size_t strlcpy(char *d, const char *s, size_t bufsize) { size_t len = strlen(s); size_t ret = len; if (bufsize > 0) { if (len >= bufsize) len = bufsize-1; memcpy(d, s, len); d[len] = 0; } return ret; } #endif #ifndef HAVE_STRLCAT /** * Like strncat() but does not 0 fill the buffer and always null * terminates. * * @param bufsize length of the buffer, which should be one more than * the maximum resulting string length. **/ size_t strlcat(char *d, const char *s, size_t bufsize) { size_t len1 = strlen(d); size_t len2 = strlen(s); size_t ret = len1 + len2; if (len1 < bufsize - 1) { if (len2 >= bufsize - len1) len2 = bufsize - len1 - 1; memcpy(d+len1, s, len2); d[len1+len2] = 0; } return ret; } #endif #ifndef HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen) { const char *p; return (p = (const char *)memchr(s, '\0', maxlen)) ? (size_t)(p-s) : maxlen; } #endif #ifndef HAVE_STRNDUP char * strndup (const char *s, size_t maxlen) { size_t len = strnlen (s, maxlen); char *new = (char *) malloc (len + 1); if (new == NULL) return NULL; new[len] = '\0'; return (char *) memcpy (new, s, len); } #endif quagga-1.2.4/lib/str.h000066400000000000000000000011771325323223500145200ustar00rootroot00000000000000/* * $Id: str.h,v 1.4 2005/09/19 09:53:21 hasso Exp $ */ #ifndef _ZEBRA_STR_H #define _ZEBRA_STR_H #ifndef HAVE_SNPRINTF extern 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 extern size_t strlcpy(char *, const char *, size_t); #endif #ifndef HAVE_STRLCAT extern size_t strlcat(char *, const char *, size_t); #endif #ifndef HAVE_STRNLEN extern size_t strnlen(const char *s, size_t maxlen); #endif #ifndef HAVE_STRNDUP extern char * strndup (const char *, size_t); #endif #endif /* _ZEBRA_STR_H */ quagga-1.2.4/lib/stream.c000066400000000000000000000516001325323223500151720ustar00rootroot00000000000000 /* * 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 #include "stream.h" #include "memory.h" #include "network.h" #include "prefix.h" #include "log.h" /* Tests whether a position is valid */ #define GETP_VALID(S,G) \ ((G) <= (S)->endp) #define PUT_AT_VALID(S,G) GETP_VALID(S,G) #define ENDP_VALID(S,E) \ ((E) <= (S)->size) /* asserting sanity checks. Following must be true before * stream functions are called: * * Following must always be true of stream elements * before and after calls to stream functions: * * getp <= endp <= size * * Note that after a stream function is called following may be true: * if (getp == endp) then stream is no longer readable * if (endp == size) then stream is no longer writeable * * It is valid to put to anywhere within the size of the stream, but only * using stream_put..._at() functions. */ #define STREAM_WARN_OFFSETS(S) \ zlog_warn ("&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \ (void *)(S), \ (unsigned long) (S)->size, \ (unsigned long) (S)->getp, \ (unsigned long) (S)->endp)\ #define STREAM_VERIFY_SANE(S) \ do { \ if ( !(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp)) ) \ STREAM_WARN_OFFSETS(S); \ assert ( GETP_VALID(S, (S)->getp) ); \ assert ( ENDP_VALID(S, (S)->endp) ); \ } while (0) #define STREAM_BOUND_WARN(S, WHAT) \ do { \ zlog_warn ("%s: Attempt to %s out of bounds", __func__, (WHAT)); \ STREAM_WARN_OFFSETS(S); \ assert (0); \ } while (0) /* XXX: Deprecated macro: do not use */ #define CHECK_SIZE(S, Z) \ do { \ if (((S)->endp + (Z)) > (S)->size) \ { \ zlog_warn ("CHECK_SIZE: truncating requested size %lu\n", \ (unsigned long) (Z)); \ STREAM_WARN_OFFSETS(S); \ (Z) = (S)->size - (S)->endp; \ } \ } while (0); /* Make stream buffer. */ struct stream * stream_new (size_t size) { struct stream *s; assert (size > 0); if (size == 0) { zlog_warn ("stream_new(): called with 0 size!"); return NULL; } s = XCALLOC (MTYPE_STREAM, sizeof (struct stream)); if (s == NULL) return s; if ( (s->data = XMALLOC (MTYPE_STREAM_DATA, size)) == NULL) { XFREE (MTYPE_STREAM, s); return NULL; } s->size = size; return s; } /* Free it now. */ void stream_free (struct stream *s) { if (!s) return; XFREE (MTYPE_STREAM_DATA, s->data); XFREE (MTYPE_STREAM, s); } struct stream * stream_copy (struct stream *new, struct stream *src) { STREAM_VERIFY_SANE (src); assert (new != NULL); assert (STREAM_SIZE(new) >= src->endp); new->endp = src->endp; new->getp = src->getp; memcpy (new->data, src->data, src->endp); return new; } struct stream * stream_dup (struct stream *s) { struct stream *new; STREAM_VERIFY_SANE (s); if ( (new = stream_new (s->endp)) == NULL) return NULL; return (stream_copy (new, s)); } struct stream * stream_dupcat (struct stream *s1, struct stream *s2, size_t offset) { struct stream *new; STREAM_VERIFY_SANE (s1); STREAM_VERIFY_SANE (s2); if ( (new = stream_new (s1->endp + s2->endp)) == NULL) return NULL; memcpy (new->data, s1->data, offset); memcpy (new->data + offset, s2->data, s2->endp); memcpy (new->data + offset + s2->endp, s1->data + offset, (s1->endp - offset)); new->endp = s1->endp + s2->endp; return new; } size_t stream_resize (struct stream *s, size_t newsize) { u_char *newdata; STREAM_VERIFY_SANE (s); newdata = XREALLOC (MTYPE_STREAM_DATA, s->data, newsize); if (newdata == NULL) return s->size; s->data = newdata; s->size = newsize; if (s->endp > s->size) s->endp = s->size; if (s->getp > s->endp) s->getp = s->endp; STREAM_VERIFY_SANE (s); return s->size; } size_t stream_get_getp (struct stream *s) { STREAM_VERIFY_SANE(s); return s->getp; } size_t stream_get_endp (struct stream *s) { STREAM_VERIFY_SANE(s); return s->endp; } size_t stream_get_size (struct stream *s) { STREAM_VERIFY_SANE(s); return s->size; } /* Stream structre' stream pointer related functions. */ void stream_set_getp (struct stream *s, size_t pos) { STREAM_VERIFY_SANE(s); if (!GETP_VALID (s, pos)) { STREAM_BOUND_WARN (s, "set getp"); pos = s->endp; } s->getp = pos; } void stream_set_endp (struct stream *s, size_t pos) { STREAM_VERIFY_SANE(s); if (!ENDP_VALID(s, pos)) { STREAM_BOUND_WARN (s, "set endp"); return; } /* * Make sure the current read pointer is not beyond the new endp. */ if (s->getp > pos) { STREAM_BOUND_WARN(s, "set endp"); return; } s->endp = pos; STREAM_VERIFY_SANE(s); } /* Forward pointer. */ void stream_forward_getp (struct stream *s, size_t size) { STREAM_VERIFY_SANE(s); if (!GETP_VALID (s, s->getp + size)) { STREAM_BOUND_WARN (s, "seek getp"); return; } s->getp += size; } void stream_forward_endp (struct stream *s, size_t size) { STREAM_VERIFY_SANE(s); if (!ENDP_VALID (s, s->endp + size)) { STREAM_BOUND_WARN (s, "seek endp"); return; } s->endp += size; } /* Copy from stream to destination. */ void stream_get (void *dst, struct stream *s, size_t size) { STREAM_VERIFY_SANE(s); if (STREAM_READABLE(s) < size) { STREAM_BOUND_WARN (s, "get"); return; } 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; STREAM_VERIFY_SANE (s); if (STREAM_READABLE(s) < sizeof (u_char)) { STREAM_BOUND_WARN (s, "get char"); return 0; } c = s->data[s->getp++]; return c; } /* Get next character from the stream. */ u_char stream_getc_from (struct stream *s, size_t from) { u_char c; STREAM_VERIFY_SANE(s); if (!GETP_VALID (s, from + sizeof (u_char))) { STREAM_BOUND_WARN (s, "get char"); return 0; } c = s->data[from]; return c; } /* Get next word from the stream. */ u_int16_t stream_getw (struct stream *s) { u_int16_t w; STREAM_VERIFY_SANE (s); if (STREAM_READABLE (s) < sizeof (u_int16_t)) { STREAM_BOUND_WARN (s, "get "); return 0; } 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, size_t from) { u_int16_t w; STREAM_VERIFY_SANE(s); if (!GETP_VALID (s, from + sizeof (u_int16_t))) { STREAM_BOUND_WARN (s, "get "); return 0; } w = s->data[from++] << 8; w |= s->data[from]; return w; } /* Get next long word from the stream. */ u_int32_t stream_getl_from (struct stream *s, size_t from) { u_int32_t l; STREAM_VERIFY_SANE(s); if (!GETP_VALID (s, from + sizeof (u_int32_t))) { STREAM_BOUND_WARN (s, "get long"); return 0; } l = s->data[from++] << 24; l |= s->data[from++] << 16; l |= s->data[from++] << 8; l |= s->data[from]; return l; } u_int32_t stream_getl (struct stream *s) { u_int32_t l; STREAM_VERIFY_SANE(s); if (STREAM_READABLE (s) < sizeof (u_int32_t)) { STREAM_BOUND_WARN (s, "get long"); return 0; } 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 quad word from the stream. */ uint64_t stream_getq_from (struct stream *s, size_t from) { uint64_t q; STREAM_VERIFY_SANE(s); if (!GETP_VALID (s, from + sizeof (uint64_t))) { STREAM_BOUND_WARN (s, "get quad"); return 0; } q = ((uint64_t) s->data[from++]) << 56; q |= ((uint64_t) s->data[from++]) << 48; q |= ((uint64_t) s->data[from++]) << 40; q |= ((uint64_t) s->data[from++]) << 32; q |= ((uint64_t) s->data[from++]) << 24; q |= ((uint64_t) s->data[from++]) << 16; q |= ((uint64_t) s->data[from++]) << 8; q |= ((uint64_t) s->data[from++]); return q; } uint64_t stream_getq (struct stream *s) { uint64_t q; STREAM_VERIFY_SANE(s); if (STREAM_READABLE (s) < sizeof (uint64_t)) { STREAM_BOUND_WARN (s, "get quad"); return 0; } q = ((uint64_t) s->data[s->getp++]) << 56; q |= ((uint64_t) s->data[s->getp++]) << 48; q |= ((uint64_t) s->data[s->getp++]) << 40; q |= ((uint64_t) s->data[s->getp++]) << 32; q |= ((uint64_t) s->data[s->getp++]) << 24; q |= ((uint64_t) s->data[s->getp++]) << 16; q |= ((uint64_t) s->data[s->getp++]) << 8; q |= ((uint64_t) s->data[s->getp++]); return q; } /* Get next long word from the stream. */ u_int32_t stream_get_ipv4 (struct stream *s) { u_int32_t l; STREAM_VERIFY_SANE(s); if (STREAM_READABLE (s) < sizeof(u_int32_t)) { STREAM_BOUND_WARN (s, "get ipv4"); return 0; } memcpy (&l, s->data + s->getp, sizeof(u_int32_t)); s->getp += sizeof(u_int32_t); return l; } float stream_getf (struct stream *s) { #if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1 #warning "Unknown floating-point format, __func__ may be wrong" #endif /* we assume 'float' is in the single precision IEC 60559 binary format, in host byte order */ union { float r; uint32_t d; } u; u.d = stream_getl (s); return u.r; } double stream_getd (struct stream *s) { #if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1 #warning "Unknown floating-point format, __func__ may be wrong" #endif union { double r; uint64_t d; } u; u.d = stream_getq (s); return u.r; } /* Copy to source to stream. * * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap * around. This should be fixed once the stream updates are working. * * stream_write() is saner */ void stream_put (struct stream *s, const void *src, size_t size) { /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */ CHECK_SIZE(s, size); STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); return; } if (src) memcpy (s->data + s->endp, src, size); else memset (s->data + s->endp, 0, size); s->endp += size; } /* Put character to the stream. */ int stream_putc (struct stream *s, u_char c) { STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE (s) < sizeof(u_char)) { STREAM_BOUND_WARN (s, "put"); return 0; } s->data[s->endp++] = c; return sizeof (u_char); } /* Put word to the stream. */ int stream_putw (struct stream *s, u_int16_t w) { STREAM_VERIFY_SANE (s); if (STREAM_WRITEABLE (s) < sizeof (u_int16_t)) { STREAM_BOUND_WARN (s, "put"); return 0; } s->data[s->endp++] = (u_char)(w >> 8); s->data[s->endp++] = (u_char) w; return 2; } /* Put long word to the stream. */ int stream_putl (struct stream *s, u_int32_t l) { STREAM_VERIFY_SANE (s); if (STREAM_WRITEABLE (s) < sizeof (u_int32_t)) { STREAM_BOUND_WARN (s, "put"); return 0; } s->data[s->endp++] = (u_char)(l >> 24); s->data[s->endp++] = (u_char)(l >> 16); s->data[s->endp++] = (u_char)(l >> 8); s->data[s->endp++] = (u_char)l; return 4; } /* Put quad word to the stream. */ int stream_putq (struct stream *s, uint64_t q) { STREAM_VERIFY_SANE (s); if (STREAM_WRITEABLE (s) < sizeof (uint64_t)) { STREAM_BOUND_WARN (s, "put quad"); return 0; } s->data[s->endp++] = (u_char)(q >> 56); s->data[s->endp++] = (u_char)(q >> 48); s->data[s->endp++] = (u_char)(q >> 40); s->data[s->endp++] = (u_char)(q >> 32); s->data[s->endp++] = (u_char)(q >> 24); s->data[s->endp++] = (u_char)(q >> 16); s->data[s->endp++] = (u_char)(q >> 8); s->data[s->endp++] = (u_char)q; return 8; } int stream_putf (struct stream *s, float f) { #if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1 #warning "Unknown floating-point format, __func__ may be wrong" #endif /* we can safely assume 'float' is in the single precision IEC 60559 binary format in host order */ union { float i; uint32_t o; } u; u.i = f; return stream_putl (s, u.o); } int stream_putd (struct stream *s, double d) { #if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1 #warning "Unknown floating-point format, __func__ may be wrong" #endif union { double i; uint64_t o; } u; u.i = d; return stream_putq (s, u.o); } int stream_putc_at (struct stream *s, size_t putp, u_char c) { STREAM_VERIFY_SANE(s); if (!PUT_AT_VALID (s, putp + sizeof (u_char))) { STREAM_BOUND_WARN (s, "put"); return 0; } s->data[putp] = c; return 1; } int stream_putw_at (struct stream *s, size_t putp, u_int16_t w) { STREAM_VERIFY_SANE(s); if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t))) { STREAM_BOUND_WARN (s, "put"); return 0; } s->data[putp] = (u_char)(w >> 8); s->data[putp + 1] = (u_char) w; return 2; } int stream_putl_at (struct stream *s, size_t putp, u_int32_t l) { STREAM_VERIFY_SANE(s); if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t))) { STREAM_BOUND_WARN (s, "put"); return 0; } 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; } int stream_putq_at (struct stream *s, size_t putp, uint64_t q) { STREAM_VERIFY_SANE(s); if (!PUT_AT_VALID (s, putp + sizeof (uint64_t))) { STREAM_BOUND_WARN (s, "put"); return 0; } s->data[putp] = (u_char)(q >> 56); s->data[putp + 1] = (u_char)(q >> 48); s->data[putp + 2] = (u_char)(q >> 40); s->data[putp + 3] = (u_char)(q >> 32); s->data[putp + 4] = (u_char)(q >> 24); s->data[putp + 5] = (u_char)(q >> 16); s->data[putp + 6] = (u_char)(q >> 8); s->data[putp + 7] = (u_char)q; return 8; } /* Put long word to the stream. */ int stream_put_ipv4 (struct stream *s, u_int32_t l) { STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE (s) < sizeof (u_int32_t)) { STREAM_BOUND_WARN (s, "put"); return 0; } memcpy (s->data + s->endp, &l, sizeof (u_int32_t)); s->endp += sizeof (u_int32_t); return sizeof (u_int32_t); } /* Put long word to the stream. */ int stream_put_in_addr (struct stream *s, struct in_addr *addr) { STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE (s) < sizeof (u_int32_t)) { STREAM_BOUND_WARN (s, "put"); return 0; } memcpy (s->data + s->endp, addr, sizeof (u_int32_t)); s->endp += sizeof (u_int32_t); return sizeof (u_int32_t); } /* Put prefix by nlri type format. */ int stream_put_prefix (struct stream *s, struct prefix *p) { size_t psize; STREAM_VERIFY_SANE(s); psize = PSIZE (p->prefixlen); if (STREAM_WRITEABLE (s) < (psize + sizeof (u_char))) { STREAM_BOUND_WARN (s, "put"); return 0; } s->data[s->endp++] = p->prefixlen; memcpy (s->data + s->endp, &p->u.prefix, psize); s->endp += psize; return psize; } /* Read size from fd. */ int stream_read (struct stream *s, int fd, size_t size) { int nbytes; STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); return 0; } nbytes = readn (fd, s->data + s->endp, size); if (nbytes > 0) s->endp += nbytes; return nbytes; } ssize_t stream_read_try(struct stream *s, int fd, size_t size) { ssize_t nbytes; STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE(s) < size) { STREAM_BOUND_WARN (s, "put"); /* Fatal (not transient) error, since retrying will not help (stream is too small to contain the desired data). */ return -1; } if ((nbytes = read(fd, s->data + s->endp, size)) >= 0) { s->endp += nbytes; return nbytes; } /* Error: was it transient (return -2) or fatal (return -1)? */ if (ERRNO_IO_RETRY(errno)) return -2; zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno)); return -1; } /* Read up to size bytes into the stream from the fd, using recvmsgfrom * whose arguments match the remaining arguments to this function */ ssize_t stream_recvfrom (struct stream *s, int fd, size_t size, int flags, struct sockaddr *from, socklen_t *fromlen) { ssize_t nbytes; STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE(s) < size) { STREAM_BOUND_WARN (s, "put"); /* Fatal (not transient) error, since retrying will not help (stream is too small to contain the desired data). */ return -1; } if ((nbytes = recvfrom (fd, s->data + s->endp, size, flags, from, fromlen)) >= 0) { s->endp += nbytes; return nbytes; } /* Error: was it transient (return -2) or fatal (return -1)? */ if (ERRNO_IO_RETRY(errno)) return -2; zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno)); return -1; } /* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting * from endp. * First iovec will be used to receive the data. * Stream need not be empty. */ ssize_t stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags, size_t size) { int nbytes; struct iovec *iov; STREAM_VERIFY_SANE(s); assert (msgh->msg_iovlen > 0); if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); /* This is a logic error in the calling code: the stream is too small to hold the desired data! */ return -1; } iov = &(msgh->msg_iov[0]); iov->iov_base = (s->data + s->endp); iov->iov_len = size; nbytes = recvmsg (fd, msgh, flags); if (nbytes > 0) s->endp += nbytes; return nbytes; } /* Write data to buffer. */ size_t stream_write (struct stream *s, const void *ptr, size_t size) { CHECK_SIZE(s, size); STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); return 0; } memcpy (s->data + s->endp, ptr, size); s->endp += size; return size; } /* Return current read pointer. * DEPRECATED! * Use stream_get_pnt_to if you must, but decoding streams properly * is preferred */ u_char * stream_pnt (struct stream *s) { STREAM_VERIFY_SANE(s); return s->data + s->getp; } /* Check does this stream empty? */ int stream_empty (struct stream *s) { STREAM_VERIFY_SANE(s); return (s->endp == 0); } /* Reset stream. */ void stream_reset (struct stream *s) { STREAM_VERIFY_SANE (s); s->getp = s->endp = 0; } /* Discard read data (prior to the getp), and move the unread data * to the beginning of the stream. * * See also stream_fifo_* functions, for another approach to managing * streams. */ void stream_discard (struct stream *s) { STREAM_VERIFY_SANE (s); if (s->getp == 0) return; if (s->getp == s->endp) { stream_reset (s); return; } s->data = memmove (s->data, s->data + s->getp, s->endp - s->getp); s->endp -= s->getp; s->getp = 0; } /* Write stream contens to the file discriptor. */ int stream_flush (struct stream *s, int fd) { int nbytes; STREAM_VERIFY_SANE(s); 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 (void) { 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); } quagga-1.2.4/lib/stream.h000066400000000000000000000213561325323223500152040ustar00rootroot00000000000000/* * 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 #include "prefix.h" /* * A stream is an arbitrary buffer, whose contents generally are assumed to * be in network order. * * A stream has the following attributes associated with it: * * - size: the allocated, invariant size of the buffer. * * - getp: the get position marker, denoting the offset in the stream where * the next read (or 'get') will be from. This getp marker is * automatically adjusted when data is read from the stream, the * user may also manipulate this offset as they wish, within limits * (see below) * * - endp: the end position marker, denoting the offset in the stream where * valid data ends, and if the user attempted to write (or * 'put') data where that data would be written (or 'put') to. * * These attributes are all size_t values. * * Constraints: * * 1. getp can never exceed endp * * - hence if getp is equal to endp, there is no more valid data that can be * gotten from the stream (though, the user may reposition getp to earlier in * the stream, if they wish). * * 2. endp can never exceed size * * - hence, if endp is equal to size, then the stream is full, and no more * data can be written to the stream. * * In other words the following must always be true, and the stream * abstraction is allowed internally to assert that the following property * holds true for a stream, as and when it wishes: * * getp <= endp <= size * * It is the users responsibility to ensure this property is never violated. * * A stream therefore can be thought of like this: * * --------------------------------------------------- * |XXXXXXXXXXXXXXXXXXXXXXXX | * --------------------------------------------------- * ^ ^ ^ * getp endp size * * This shows a stream containing data (shown as 'X') up to the endp offset. * The stream is empty from endp to size. Without adjusting getp, there are * still endp-getp bytes of valid data to be read from the stream. * * Methods are provided to get and put to/from the stream, as well as * retrieve the values of the 3 markers and manipulate the getp marker. * * Note: * At the moment, newly allocated streams are zero filled. Hence, one can * use stream_forward_endp() to effectively create arbitrary zero-fill * padding. However, note that stream_reset() does *not* zero-out the * stream. This property should **not** be relied upon. * * Best practice is to use stream_put (, NULL, ) to zero out * any part of a stream which isn't otherwise written to. */ /* Stream buffer. */ struct stream { struct stream *next; /* Remainder is ***private*** to stream * direct access is frowned upon! * Use the appropriate functions/macros */ size_t getp; /* next get position */ size_t endp; /* last valid data position */ size_t size; /* size of data segment */ unsigned char *data; /* data pointer */ }; /* First in first out queue structure. */ struct stream_fifo { size_t count; struct stream *head; struct stream *tail; }; /* Utility macros. */ #define STREAM_SIZE(S) ((S)->size) /* number of bytes which can still be written */ #define STREAM_WRITEABLE(S) ((S)->size - (S)->endp) /* number of bytes still to be read */ #define STREAM_READABLE(S) ((S)->endp - (S)->getp) #define STREAM_CONCAT_REMAIN(S1, S2, size) \ ((size) - (S1)->endp - (S2)->endp) /* deprecated macros - do not use in new code */ #define STREAM_PNT(S) stream_pnt((S)) #define STREAM_DATA(S) ((S)->data) #define STREAM_REMAIN(S) STREAM_WRITEABLE((S)) /* Stream prototypes. * For stream_{put,get}S, the S suffix mean: * * c: character (unsigned byte) * w: word (two bytes) * l: long (two words) * q: quad (four words) */ extern struct stream *stream_new (size_t); extern void stream_free (struct stream *); extern struct stream * stream_copy (struct stream *, struct stream *src); extern struct stream *stream_dup (struct stream *); extern size_t stream_resize (struct stream *, size_t); extern size_t stream_get_getp (struct stream *); extern size_t stream_get_endp (struct stream *); extern size_t stream_get_size (struct stream *); extern u_char *stream_get_data (struct stream *); /** * Create a new stream structure; copy offset bytes from s1 to the new * stream; copy s2 data to the new stream; copy rest of s1 data to the * new stream. */ extern struct stream *stream_dupcat(struct stream *s1, struct stream *s2, size_t offset); extern void stream_set_getp (struct stream *, size_t); extern void stream_set_endp (struct stream *, size_t); extern void stream_forward_getp (struct stream *, size_t); extern void stream_forward_endp (struct stream *, size_t); /* steam_put: NULL source zeroes out size_t bytes of stream */ extern void stream_put (struct stream *, const void *, size_t); extern int stream_putc (struct stream *, u_char); extern int stream_putc_at (struct stream *, size_t, u_char); extern int stream_putw (struct stream *, u_int16_t); extern int stream_putw_at (struct stream *, size_t, u_int16_t); extern int stream_putl (struct stream *, u_int32_t); extern int stream_putl_at (struct stream *, size_t, u_int32_t); extern int stream_putq (struct stream *, uint64_t); extern int stream_putq_at (struct stream *, size_t, uint64_t); extern int stream_put_ipv4 (struct stream *, u_int32_t); extern int stream_put_in_addr (struct stream *, struct in_addr *); extern int stream_put_prefix (struct stream *, struct prefix *); extern void stream_get (void *, struct stream *, size_t); extern u_char stream_getc (struct stream *); extern u_char stream_getc_from (struct stream *, size_t); extern u_int16_t stream_getw (struct stream *); extern u_int16_t stream_getw_from (struct stream *, size_t); extern u_int32_t stream_getl (struct stream *); extern u_int32_t stream_getl_from (struct stream *, size_t); extern uint64_t stream_getq (struct stream *); extern uint64_t stream_getq_from (struct stream *, size_t); extern u_int32_t stream_get_ipv4 (struct stream *); /* IEEE-754 floats */ extern float stream_getf (struct stream *); extern double stream_getd (struct stream *); extern int stream_putf (struct stream *, float); extern int stream_putd (struct stream *, double); #undef stream_read #undef stream_write /* Deprecated: assumes blocking I/O. Will be removed. Use stream_read_try instead. */ extern int stream_read (struct stream *, int, size_t); /* Read up to size bytes into the stream. Return code: >0: number of bytes read 0: end-of-file -1: fatal error -2: transient error, should retry later (i.e. EAGAIN or EINTR) This is suitable for use with non-blocking file descriptors. */ extern ssize_t stream_read_try(struct stream *s, int fd, size_t size); extern ssize_t stream_recvmsg (struct stream *s, int fd, struct msghdr *, int flags, size_t size); extern ssize_t stream_recvfrom (struct stream *s, int fd, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); extern size_t stream_write (struct stream *, const void *, size_t); /* reset the stream. See Note above */ extern void stream_reset (struct stream *); /* move unread data to start of stream, discarding read data */ extern void stream_discard (struct stream *); extern int stream_flush (struct stream *, int); extern int stream_empty (struct stream *); /* is the stream empty? */ /* deprecated */ extern u_char *stream_pnt (struct stream *); /* Stream fifo. */ extern struct stream_fifo *stream_fifo_new (void); extern void stream_fifo_push (struct stream_fifo *fifo, struct stream *s); extern struct stream *stream_fifo_pop (struct stream_fifo *fifo); extern struct stream *stream_fifo_head (struct stream_fifo *fifo); extern void stream_fifo_clean (struct stream_fifo *fifo); extern void stream_fifo_free (struct stream_fifo *fifo); #endif /* _ZEBRA_STREAM_H */ quagga-1.2.4/lib/table.c000066400000000000000000000416741325323223500150000ustar00rootroot00000000000000/* * 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" static void route_node_delete (struct route_node *); static void route_table_free (struct route_table *); /* * route_table_init_with_delegate */ struct route_table * route_table_init_with_delegate (route_table_delegate_t *delegate) { struct route_table *rt; rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table)); rt->delegate = delegate; return rt; } void route_table_finish (struct route_table *rt) { route_table_free (rt); } /* Allocate new route node. */ static struct route_node * route_node_new (struct route_table *table) { return table->delegate->create_node (table->delegate, table); } /* Allocate new route node with prefix set. */ static struct route_node * route_node_set (struct route_table *table, const struct prefix *prefix) { struct route_node *node; node = route_node_new (table); prefix_copy (&node->p, prefix); node->table = table; return node; } /* Free route node. */ static void route_node_free (struct route_table *table, struct route_node *node) { table->delegate->destroy_node (table->delegate, table, node); } /* Free route table. */ static void route_table_free (struct route_table *rt) { struct route_node *tmp_node; struct route_node *node; if (rt == NULL) return; node = rt->top; /* Bulk deletion of nodes remaining in this table. This function is not called until workers have completed their dependency on this table. A final route_unlock_node() will not be called for these nodes. */ 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; tmp_node->table->count--; tmp_node->lock = 0; /* to cause assert if unlocked after this */ route_node_free (rt, tmp_node); if (node != NULL) { if (node->l_left == tmp_node) node->l_left = NULL; else node->l_right = NULL; } else { break; } } assert (rt->count == 0); XFREE (MTYPE_ROUTE_TABLE, rt); return; } /* Utility mask array. */ static const u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; /* Common prefix route genaration. */ static void route_common (const struct prefix *n, const struct prefix *p, struct prefix *new) { int i; u_char diff; u_char mask; const u_char *np = (const u_char *)&n->u.prefix; const u_char *pp = (const 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]; } } static void set_link (struct route_node *node, struct route_node *new) { unsigned int bit = prefix_bit (&new->p.u.prefix, node->p.prefixlen); 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) { assert (node->lock > 0); node->lock--; if (node->lock == 0) route_node_delete (node); } /* Find matched prefix. */ struct route_node * route_node_match (const struct route_table *table, const 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; if (node->p.prefixlen == p->prefixlen) break; node = node->link[prefix_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 (const struct route_table *table, const 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 (const struct route_table *table, const 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 (const struct route_table *table, const struct prefix *p) { struct route_node *node; u_char prefixlen = p->prefixlen; const u_char *prefix = &p->u.prefix; node = table->top; while (node && node->p.prefixlen <= prefixlen && prefix_match (&node->p, p)) { if (node->p.prefixlen == prefixlen) return node->info ? route_lock_node (node) : NULL; node = node->link[prefix_bit(prefix, node->p.prefixlen)]; } return NULL; } /* Add node to routing table. */ struct route_node * route_node_get (struct route_table *const table, const struct prefix *p) { struct route_node *new; struct route_node *node; struct route_node *match; u_char prefixlen = p->prefixlen; const u_char *prefix = &p->u.prefix; match = NULL; node = table->top; while (node && node->p.prefixlen <= prefixlen && prefix_match (&node->p, p)) { if (node->p.prefixlen == prefixlen) return route_lock_node (node); match = node; node = node->link[prefix_bit(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 (table); 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); table->count++; } } table->count++; route_lock_node (new); return new; } /* Delete node from the routing table. */ static 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; node->table->count--; route_node_free (node->table, 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; } unsigned long route_table_count (const struct route_table *table) { return table->count; } /** * route_node_create * * Default function for creating a route node. */ static struct route_node * route_node_create (route_table_delegate_t *delegate, struct route_table *table) { struct route_node *node; node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node)); return node; } /** * route_node_destroy * * Default function for destroying a route node. */ static void route_node_destroy (route_table_delegate_t *delegate, struct route_table *table, struct route_node *node) { XFREE (MTYPE_ROUTE_NODE, node); } /* * Default delegate. */ static route_table_delegate_t default_delegate = { .create_node = route_node_create, .destroy_node = route_node_destroy }; /* * route_table_init */ struct route_table * route_table_init (void) { return route_table_init_with_delegate (&default_delegate); } /** * route_table_prefix_iter_cmp * * Compare two prefixes according to the order in which they appear in * an iteration over a tree. * * @return -1 if p1 occurs before p2 (p1 < p2) * 0 if the prefixes are identical (p1 == p2) * +1 if p1 occurs after p2 (p1 > p2) */ int route_table_prefix_iter_cmp (struct prefix *p1, struct prefix *p2) { struct prefix common_space; struct prefix *common = &common_space; if (p1->prefixlen <= p2->prefixlen) { if (prefix_match (p1, p2)) { /* * p1 contains p2, or is equal to it. */ return (p1->prefixlen == p2->prefixlen) ? 0 : -1; } } else { /* * Check if p2 contains p1. */ if (prefix_match (p2, p1)) return 1; } route_common (p1, p2, common); assert (common->prefixlen < p1->prefixlen); assert (common->prefixlen < p2->prefixlen); /* * Both prefixes are longer than the common prefix. * * We need to check the bit after the common prefixlen to determine * which one comes later. */ if (prefix_bit (&p1->u.prefix, common->prefixlen)) { /* * We branch to the right to get to p1 from the common prefix. */ assert (!prefix_bit (&p2->u.prefix, common->prefixlen)); return 1; } /* * We branch to the right to get to p2 from the common prefix. */ assert (prefix_bit (&p2->u.prefix, common->prefixlen)); return -1; } /* * route_get_subtree_next * * Helper function that returns the first node that follows the nodes * in the sub-tree under 'node' in iteration order. */ static struct route_node * route_get_subtree_next (struct route_node *node) { while (node->parent) { if (node->parent->l_left == node && node->parent->l_right) return node->parent->l_right; node = node->parent; } return NULL; } /** * route_table_get_next_internal * * Helper function to find the node that occurs after the given prefix in * order of iteration. * * @see route_table_get_next */ static struct route_node * route_table_get_next_internal (const struct route_table *table, struct prefix *p) { struct route_node *node, *tmp_node; int cmp; node = table->top; while (node) { int match; if (node->p.prefixlen < p->prefixlen) match = prefix_match (&node->p, p); else match = prefix_match (p, &node->p); if (match) { if (node->p.prefixlen == p->prefixlen) { /* * The prefix p exists in the tree, just return the next * node. */ route_lock_node (node); node = route_next (node); if (node) route_unlock_node (node); return (node); } if (node->p.prefixlen > p->prefixlen) { /* * Node is in the subtree of p, and hence greater than p. */ return node; } /* * p is in the sub-tree under node. */ tmp_node = node->link[prefix_bit (&p->u.prefix, node->p.prefixlen)]; if (tmp_node) { node = tmp_node; continue; } /* * There are no nodes in the direction where p should be. If * node has a right child, then it must be greater than p. */ if (node->l_right) return node->l_right; /* * No more children to follow, go upwards looking for the next * node. */ return route_get_subtree_next (node); } /* * Neither node prefix nor 'p' contains the other. */ cmp = route_table_prefix_iter_cmp (&node->p, p); if (cmp > 0) { /* * Node follows p in iteration order. Return it. */ return node; } assert (cmp < 0); /* * Node and the subtree under it come before prefix p in * iteration order. Prefix p and its sub-tree are not present in * the tree. Go upwards and find the first node that follows the * subtree. That node will also succeed p. */ return route_get_subtree_next (node); } return NULL; } /** * route_table_get_next * * Find the node that occurs after the given prefix in order of * iteration. */ struct route_node * route_table_get_next (const struct route_table *table, struct prefix *p) { struct route_node *node; node = route_table_get_next_internal (table, p); if (node) { assert (route_table_prefix_iter_cmp (&node->p, p) > 0); route_lock_node (node); } return node; } /* * route_table_iter_init */ void route_table_iter_init (route_table_iter_t * iter, struct route_table *table) { memset (iter, 0, sizeof (*iter)); iter->state = RT_ITER_STATE_INIT; iter->table = table; } /* * route_table_iter_pause * * Pause an iteration over the table. This allows the iteration to be * resumed point after arbitrary additions/deletions from the table. * An iteration can be resumed by just calling route_table_iter_next() * on the iterator. */ void route_table_iter_pause (route_table_iter_t * iter) { switch (iter->state) { case RT_ITER_STATE_INIT: case RT_ITER_STATE_PAUSED: case RT_ITER_STATE_DONE: return; case RT_ITER_STATE_ITERATING: /* * Save the prefix that we are currently at. The next call to * route_table_iter_next() will return the node after this prefix * in the tree. */ prefix_copy (&iter->pause_prefix, &iter->current->p); route_unlock_node (iter->current); iter->current = NULL; iter->state = RT_ITER_STATE_PAUSED; return; default: assert (0); } } /* * route_table_iter_cleanup * * Release any resources held by the iterator. */ void route_table_iter_cleanup (route_table_iter_t * iter) { if (iter->state == RT_ITER_STATE_ITERATING) { route_unlock_node (iter->current); iter->current = NULL; } assert (!iter->current); /* * Set the state to RT_ITER_STATE_DONE to make any * route_table_iter_next() calls on this iterator return NULL. */ iter->state = RT_ITER_STATE_DONE; } quagga-1.2.4/lib/table.h000066400000000000000000000141121325323223500147700ustar00rootroot00000000000000/* * 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 /* * Forward declarations. */ struct route_node; struct route_table; /* * route_table_delegate_t * * Function vector that can be used by a client to customize the * behavior of one or more route tables. */ typedef struct route_table_delegate_t_ route_table_delegate_t; typedef struct route_node * (*route_table_create_node_func_t) (route_table_delegate_t *, struct route_table *); typedef void (*route_table_destroy_node_func_t) (route_table_delegate_t *, struct route_table *, struct route_node *); struct route_table_delegate_t_ { route_table_create_node_func_t create_node; route_table_destroy_node_func_t destroy_node; }; /* Routing table top structure. */ struct route_table { struct route_node *top; /* * Delegate that performs certain functions for this table. */ route_table_delegate_t *delegate; unsigned long count; /* * User data. */ void *info; }; /* * Macro that defines all fields in a route node. */ #define ROUTE_NODE_FIELDS \ /* Actual prefix of this radix. */ \ struct prefix p; \ \ /* Tree link. */ \ struct route_table *table; \ struct route_node *parent; \ struct route_node *link[2]; \ \ /* Lock of this radix */ \ unsigned int lock; \ \ /* Each node of route. */ \ void *info; \ \ /* Aggregation. */ \ void *aggregate; /* Each routing entry. */ struct route_node { ROUTE_NODE_FIELDS #define l_left link[0] #define l_right link[1] }; typedef struct route_table_iter_t_ route_table_iter_t; typedef enum { RT_ITER_STATE_INIT, RT_ITER_STATE_ITERATING, RT_ITER_STATE_PAUSED, RT_ITER_STATE_DONE } route_table_iter_state_t; /* * route_table_iter_t * * Structure that holds state for iterating over a route table. */ struct route_table_iter_t_ { route_table_iter_state_t state; /* * Routing table that we are iterating over. The caller must ensure * that that table outlives the iterator. */ struct route_table *table; /* * The node that the iterator is currently on. */ struct route_node *current; /* * The last prefix that the iterator processed before it was paused. */ struct prefix pause_prefix; }; /* Prototypes. */ extern struct route_table *route_table_init (void); extern struct route_table * route_table_init_with_delegate (route_table_delegate_t *); extern void route_table_finish (struct route_table *); extern void route_unlock_node (struct route_node *node); extern struct route_node *route_top (struct route_table *); extern struct route_node *route_next (struct route_node *); extern struct route_node *route_next_until (struct route_node *, struct route_node *); extern struct route_node *route_node_get (struct route_table *const, const struct prefix *); extern struct route_node *route_node_lookup (const struct route_table *, const struct prefix *); extern struct route_node *route_lock_node (struct route_node *node); extern struct route_node *route_node_match (const struct route_table *, const struct prefix *); extern struct route_node *route_node_match_ipv4 (const struct route_table *, const struct in_addr *); #ifdef HAVE_IPV6 extern struct route_node *route_node_match_ipv6 (const struct route_table *, const struct in6_addr *); #endif /* HAVE_IPV6 */ extern unsigned long route_table_count (const struct route_table *); extern struct route_node * route_table_get_next (const struct route_table *table, struct prefix *p); extern int route_table_prefix_iter_cmp (struct prefix *p1, struct prefix *p2); /* * Iterator functions. */ extern void route_table_iter_init (route_table_iter_t *iter, struct route_table *table); extern void route_table_iter_pause (route_table_iter_t *iter); extern void route_table_iter_cleanup (route_table_iter_t *iter); /* * Inline functions. */ /* * route_table_iter_next * * Get the next node in the tree. */ static inline struct route_node * route_table_iter_next (route_table_iter_t * iter) { struct route_node *node; switch (iter->state) { case RT_ITER_STATE_INIT: /* * We're just starting the iteration. */ node = route_top (iter->table); break; case RT_ITER_STATE_ITERATING: node = route_next (iter->current); break; case RT_ITER_STATE_PAUSED: /* * Start with the node following pause_prefix. */ node = route_table_get_next (iter->table, &iter->pause_prefix); break; case RT_ITER_STATE_DONE: return NULL; default: assert (0); } iter->current = node; if (node) iter->state = RT_ITER_STATE_ITERATING; else iter->state = RT_ITER_STATE_DONE; return node; } /* * route_table_iter_is_done * * Returns TRUE if the iteration is complete. */ static inline int route_table_iter_is_done (route_table_iter_t *iter) { return iter->state == RT_ITER_STATE_DONE; } /* * route_table_iter_started * * Returns TRUE if this iterator has started iterating over the tree. */ static inline int route_table_iter_started (route_table_iter_t *iter) { return iter->state != RT_ITER_STATE_INIT; } #endif /* _ZEBRA_TABLE_H */ quagga-1.2.4/lib/thread.c000066400000000000000000001016231325323223500151470ustar00rootroot00000000000000/* 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 #include "thread.h" #include "memory.h" #include "log.h" #include "hash.h" #include "pqueue.h" #include "command.h" #include "sigevent.h" #if defined(__APPLE__) #include #include #endif /* Recent absolute time of day */ struct timeval recent_time; static struct timeval last_recent_time; /* Relative time, since startup */ static struct timeval relative_time; static struct timeval relative_time_base; /* init flag */ static unsigned short timers_inited; static struct hash *cpu_record = NULL; /* Struct timeval's tv_usec one second value. */ #define TIMER_SECOND_MICRO 1000000L /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO). And change negative values to 0. */ static 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) /* Change negative timeouts to 0. */ a.tv_sec = a.tv_usec = 0; 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 long 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); } 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)); } #if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__) static void quagga_gettimeofday_relative_adjust (void) { struct timeval diff; if (timeval_cmp (recent_time, last_recent_time) < 0) { relative_time.tv_sec++; relative_time.tv_usec = 0; } else { diff = timeval_subtract (recent_time, last_recent_time); relative_time.tv_sec += diff.tv_sec; relative_time.tv_usec += diff.tv_usec; relative_time = timeval_adjust (relative_time); } last_recent_time = recent_time; } #endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ /* gettimeofday wrapper, to keep recent_time updated */ static int quagga_gettimeofday (struct timeval *tv) { int ret; assert (tv); if (!(ret = gettimeofday (&recent_time, NULL))) { /* init... */ if (!timers_inited) { relative_time_base = last_recent_time = recent_time; timers_inited = 1; } /* avoid copy if user passed recent_time pointer.. */ if (tv != &recent_time) *tv = recent_time; return 0; } return ret; } static int quagga_get_relative (struct timeval *tv) { int ret; #ifdef HAVE_CLOCK_MONOTONIC { struct timespec tp; if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp))) { relative_time.tv_sec = tp.tv_sec; relative_time.tv_usec = tp.tv_nsec / 1000; } } #elif defined(__APPLE__) { uint64_t ticks; uint64_t useconds; static mach_timebase_info_data_t timebase_info; ticks = mach_absolute_time(); if (timebase_info.denom == 0) mach_timebase_info(&timebase_info); useconds = ticks * timebase_info.numer / timebase_info.denom / 1000; relative_time.tv_sec = useconds / 1000000; relative_time.tv_usec = useconds % 1000000; return 0; } #else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ if (!(ret = quagga_gettimeofday (&recent_time))) quagga_gettimeofday_relative_adjust(); #endif /* HAVE_CLOCK_MONOTONIC */ if (tv) *tv = relative_time; return ret; } /* Get absolute time stamp, but in terms of the internal timer * Could be wrong, but at least won't go back. */ static void quagga_real_stabilised (struct timeval *tv) { *tv = relative_time_base; tv->tv_sec += relative_time.tv_sec; tv->tv_usec += relative_time.tv_usec; *tv = timeval_adjust (*tv); } /* Exported Quagga timestamp function. * Modelled on POSIX clock_gettime. */ int quagga_gettime (enum quagga_clkid clkid, struct timeval *tv) { switch (clkid) { case QUAGGA_CLK_REALTIME: return quagga_gettimeofday (tv); case QUAGGA_CLK_MONOTONIC: return quagga_get_relative (tv); case QUAGGA_CLK_REALTIME_STABILISED: quagga_real_stabilised (tv); return 0; default: errno = EINVAL; return -1; } } /* time_t value in terms of stabilised absolute time. * replacement for POSIX time() */ time_t quagga_time (time_t *t) { struct timeval tv; quagga_real_stabilised (&tv); if (t) *t = tv.tv_sec; return tv.tv_sec; } /* Public export of recent_relative_time by value */ struct timeval recent_relative_time (void) { return relative_time; } static unsigned int cpu_record_hash_key (struct cpu_thread_history *a) { return (uintptr_t) a->func; } static int cpu_record_hash_cmp (const struct cpu_thread_history *a, const struct cpu_thread_history *b) { return a->func == b->func; } static void * cpu_record_hash_alloc (struct cpu_thread_history *a) { struct cpu_thread_history *new; new = XCALLOC (MTYPE_THREAD_STATS, sizeof (struct cpu_thread_history)); new->func = a->func; new->funcname = a->funcname; return new; } static void cpu_record_hash_free (void *a) { struct cpu_thread_history *hist = a; XFREE (MTYPE_THREAD_STATS, hist); } static void vty_out_cpu_thread_history(struct vty* vty, struct cpu_thread_history *a) { #ifdef HAVE_RUSAGE vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld", a->cpu.total/1000, a->cpu.total%1000, a->total_calls, a->cpu.total/a->total_calls, a->cpu.max, a->real.total/a->total_calls, a->real.max); #else vty_out(vty, "%7ld.%03ld %9d %8ld %9ld", a->real.total/1000, a->real.total%1000, a->total_calls, a->real.total/a->total_calls, a->real.max); #endif vty_out(vty, " %c%c%c%c%c%c %s%s", a->types & (1 << THREAD_READ) ? 'R':' ', a->types & (1 << THREAD_WRITE) ? 'W':' ', a->types & (1 << THREAD_TIMER) ? 'T':' ', a->types & (1 << THREAD_EVENT) ? 'E':' ', a->types & (1 << THREAD_EXECUTE) ? 'X':' ', a->types & (1 << THREAD_BACKGROUND) ? 'B' : ' ', a->funcname, VTY_NEWLINE); } static void cpu_record_hash_print(struct hash_backet *bucket, void *args[]) { struct cpu_thread_history *totals = args[0]; struct vty *vty = args[1]; thread_type *filter = args[2]; struct cpu_thread_history *a = bucket->data; a = bucket->data; if ( !(a->types & *filter) ) return; vty_out_cpu_thread_history(vty,a); totals->total_calls += a->total_calls; totals->real.total += a->real.total; if (totals->real.max < a->real.max) totals->real.max = a->real.max; #ifdef HAVE_RUSAGE totals->cpu.total += a->cpu.total; if (totals->cpu.max < a->cpu.max) totals->cpu.max = a->cpu.max; #endif } static void cpu_record_print(struct vty *vty, thread_type filter) { struct cpu_thread_history tmp; void *args[3] = {&tmp, vty, &filter}; memset(&tmp, 0, sizeof tmp); tmp.funcname = "TOTAL"; tmp.types = filter; #ifdef HAVE_RUSAGE vty_out(vty, "%21s %18s %18s%s", "", "CPU (user+system):", "Real (wall-clock):", VTY_NEWLINE); #endif vty_out(vty, "Runtime(ms) Invoked Avg uSec Max uSecs"); #ifdef HAVE_RUSAGE vty_out(vty, " Avg uSec Max uSecs"); #endif vty_out(vty, " Type Thread%s", VTY_NEWLINE); hash_iterate(cpu_record, (void(*)(struct hash_backet*,void*))cpu_record_hash_print, args); if (tmp.total_calls > 0) vty_out_cpu_thread_history(vty, &tmp); } DEFUN(show_thread_cpu, show_thread_cpu_cmd, "show thread cpu [FILTER]", SHOW_STR "Thread information\n" "Thread CPU usage\n" "Display filter (rwtexb)\n") { int i = 0; thread_type filter = (thread_type) -1U; if (argc > 0) { filter = 0; while (argv[0][i] != '\0') { switch ( argv[0][i] ) { case 'r': case 'R': filter |= (1 << THREAD_READ); break; case 'w': case 'W': filter |= (1 << THREAD_WRITE); break; case 't': case 'T': filter |= (1 << THREAD_TIMER); break; case 'e': case 'E': filter |= (1 << THREAD_EVENT); break; case 'x': case 'X': filter |= (1 << THREAD_EXECUTE); break; case 'b': case 'B': filter |= (1 << THREAD_BACKGROUND); break; default: break; } ++i; } if (filter == 0) { vty_out(vty, "Invalid filter \"%s\" specified," " must contain at least one of 'RWTEXB'%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } cpu_record_print(vty, filter); return CMD_SUCCESS; } static void cpu_record_hash_clear (struct hash_backet *bucket, void *args) { thread_type *filter = args; struct cpu_thread_history *a = bucket->data; a = bucket->data; if ( !(a->types & *filter) ) return; hash_release (cpu_record, bucket->data); } static void cpu_record_clear (thread_type filter) { thread_type *tmp = &filter; hash_iterate (cpu_record, (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear, tmp); } DEFUN(clear_thread_cpu, clear_thread_cpu_cmd, "clear thread cpu [FILTER]", "Clear stored data\n" "Thread information\n" "Thread CPU usage\n" "Display filter (rwtexb)\n") { int i = 0; thread_type filter = (thread_type) -1U; if (argc > 0) { filter = 0; while (argv[0][i] != '\0') { switch ( argv[0][i] ) { case 'r': case 'R': filter |= (1 << THREAD_READ); break; case 'w': case 'W': filter |= (1 << THREAD_WRITE); break; case 't': case 'T': filter |= (1 << THREAD_TIMER); break; case 'e': case 'E': filter |= (1 << THREAD_EVENT); break; case 'x': case 'X': filter |= (1 << THREAD_EXECUTE); break; case 'b': case 'B': filter |= (1 << THREAD_BACKGROUND); break; default: break; } ++i; } if (filter == 0) { vty_out(vty, "Invalid filter \"%s\" specified," " must contain at least one of 'RWTEXB'%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } cpu_record_clear (filter); return CMD_SUCCESS; } static int thread_timer_cmp(void *a, void *b) { struct thread *thread_a = a; struct thread *thread_b = b; long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands); if (cmp < 0) return -1; if (cmp > 0) return 1; return 0; } static void thread_timer_update(void *node, int actual_position) { struct thread *thread = node; thread->index = actual_position; } /* Allocate new thread master. */ struct thread_master * thread_master_create () { struct thread_master *rv; struct rlimit limit; getrlimit(RLIMIT_NOFILE, &limit); if (cpu_record == NULL) cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key, (int (*) (const void *, const void *))cpu_record_hash_cmp); rv = XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); if (rv == NULL) { return NULL; } rv->fd_limit = (int)limit.rlim_cur; rv->read = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit); if (rv->read == NULL) { XFREE (MTYPE_THREAD_MASTER, rv); return NULL; } rv->write = XCALLOC (MTYPE_THREAD, sizeof (struct thread *) * rv->fd_limit); if (rv->write == NULL) { XFREE (MTYPE_THREAD, rv->read); XFREE (MTYPE_THREAD_MASTER, rv); return NULL; } /* Initialize the timer queues */ rv->timer = pqueue_create(); rv->background = pqueue_create(); rv->timer->cmp = rv->background->cmp = thread_timer_cmp; rv->timer->update = rv->background->update = thread_timer_update; return rv; } /* 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++; } /* 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; } static void thread_delete_fd (struct thread **thread_array, struct thread *thread) { thread_array[thread->u.fd] = NULL; } static void thread_add_fd (struct thread **thread_array, struct thread *thread) { thread_array[thread->u.fd] = thread; } /* Move thread to unuse list. */ static void thread_add_unuse (struct thread *thread) { thread->type = THREAD_UNUSED; assert (thread->master != NULL && thread != NULL); assert (thread->next == NULL); assert (thread->prev == NULL); thread_list_add (&thread->master->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--; } } static void thread_array_free (struct thread_master *m, struct thread **thread_array) { struct thread *t; int index; for (index = 0; index < m->fd_limit; ++index) { t = thread_array[index]; if (t) { thread_array[index] = NULL; XFREE (MTYPE_THREAD, t); m->alloc--; } } XFREE (MTYPE_THREAD, thread_array); } static void thread_queue_free (struct thread_master *m, struct pqueue *queue) { int i; for (i = 0; i < queue->size; i++) XFREE(MTYPE_THREAD, queue->array[i]); m->alloc -= queue->size; pqueue_delete(queue); } /* Stop thread scheduler. */ void thread_master_free (struct thread_master *m) { thread_array_free (m, m->read); thread_array_free (m, m->write); thread_queue_free (m, m->timer); thread_list_free (m, &m->event); thread_list_free (m, &m->ready); thread_list_free (m, &m->unuse); thread_queue_free (m, m->background); XFREE (MTYPE_THREAD_MASTER, m); if (cpu_record) { hash_clean (cpu_record, cpu_record_hash_free); hash_free (cpu_record); cpu_record = NULL; } } /* Thread list is empty or not. */ static int thread_empty (struct thread_list *list) { return list->head ? 0 : 1; } /* Delete top of the list and return it. */ static struct thread * thread_trim_head (struct thread_list *list) { if (!thread_empty (list)) return thread_list_delete (list, list->head); return NULL; } /* Return remain time in second. */ unsigned long thread_timer_remain_second (struct thread *thread) { quagga_get_relative (NULL); if (thread->u.sands.tv_sec - relative_time.tv_sec > 0) return thread->u.sands.tv_sec - relative_time.tv_sec; else return 0; } struct timeval thread_timer_remain(struct thread *thread) { quagga_get_relative(NULL); return timeval_subtract(thread->u.sands, relative_time); } #define debugargdef const char *funcname, const char *schedfrom, int fromln #define debugargpass funcname, schedfrom, fromln /* Get new thread. */ static struct thread * thread_get (struct thread_master *m, u_char type, int (*func) (struct thread *), void *arg, debugargdef) { struct thread *thread = thread_trim_head (&m->unuse); if (! thread) { thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread)); m->alloc++; } thread->type = type; thread->add_type = type; thread->master = m; thread->func = func; thread->arg = arg; thread->index = -1; thread->funcname = funcname; thread->schedfrom = schedfrom; thread->schedfrom_line = fromln; return thread; } #define fd_copy_fd_set(X) (X) static int fd_select (int size, thread_fd_set *read, thread_fd_set *write, thread_fd_set *except, struct timeval *t) { return(select(size, read, write, except, t)); } static int fd_is_set (int fd, thread_fd_set *fdset) { return FD_ISSET (fd, fdset); } static int fd_clear_read_write (int fd, thread_fd_set *fdset) { if (!FD_ISSET (fd, fdset)) return 0; FD_CLR (fd, fdset); return 1; } static struct thread * funcname_thread_add_read_write (int dir, struct thread_master *m, int (*func) (struct thread *), void *arg, int fd, debugargdef) { struct thread *thread = NULL; thread_fd_set *fdset = NULL; if (dir == THREAD_READ) fdset = &m->readfd; else fdset = &m->writefd; if (FD_ISSET (fd, fdset)) { zlog (NULL, LOG_WARNING, "There is already %s fd [%d]", (dir = THREAD_READ) ? "read" : "write", fd); return NULL; } FD_SET (fd, fdset); thread = thread_get (m, dir, func, arg, debugargpass); thread->u.fd = fd; if (dir == THREAD_READ) thread_add_fd (m->read, thread); else thread_add_fd (m->write, thread); return thread; } /* Add new read thread. */ struct thread * funcname_thread_add_read (struct thread_master *m, int (*func) (struct thread *), void *arg, int fd, debugargdef) { return funcname_thread_add_read_write (THREAD_READ, m, func, arg, fd, debugargpass); } /* Add new write thread. */ struct thread * funcname_thread_add_write (struct thread_master *m, int (*func) (struct thread *), void *arg, int fd, debugargdef) { return funcname_thread_add_read_write (THREAD_WRITE, m, func, arg, fd, debugargpass); } static struct thread * funcname_thread_add_timer_timeval (struct thread_master *m, int (*func) (struct thread *), int type, void *arg, struct timeval *time_relative, debugargdef) { struct thread *thread; struct pqueue *queue; struct timeval alarm_time; assert (m != NULL); assert (type == THREAD_TIMER || type == THREAD_BACKGROUND); assert (time_relative); queue = ((type == THREAD_TIMER) ? m->timer : m->background); thread = thread_get (m, type, func, arg, debugargpass); /* Do we need jitter here? */ quagga_get_relative (NULL); alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec; alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec; thread->u.sands = timeval_adjust(alarm_time); pqueue_enqueue(thread, queue); return thread; } /* Add timer event thread. */ struct thread * funcname_thread_add_timer (struct thread_master *m, int (*func) (struct thread *), void *arg, long timer, debugargdef) { struct timeval trel; assert (m != NULL); trel.tv_sec = timer; trel.tv_usec = 0; return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, &trel, debugargpass); } /* Add timer event thread with "millisecond" resolution */ struct thread * funcname_thread_add_timer_msec (struct thread_master *m, int (*func) (struct thread *), void *arg, long timer, debugargdef) { struct timeval trel; assert (m != NULL); trel.tv_sec = timer / 1000; trel.tv_usec = 1000*(timer % 1000); return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, &trel, debugargpass); } /* Add timer event thread with "millisecond" resolution */ struct thread * funcname_thread_add_timer_tv (struct thread_master *m, int (*func) (struct thread *), void *arg, struct timeval *tv, debugargdef) { return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, arg, tv, debugargpass); } /* Add a background thread, with an optional millisec delay */ struct thread * funcname_thread_add_background (struct thread_master *m, int (*func) (struct thread *), void *arg, long delay, debugargdef) { struct timeval trel; assert (m != NULL); if (delay) { trel.tv_sec = delay / 1000; trel.tv_usec = 1000*(delay % 1000); } else { trel.tv_sec = 0; trel.tv_usec = 0; } return funcname_thread_add_timer_timeval (m, func, THREAD_BACKGROUND, arg, &trel, debugargpass); } /* Add simple event thread. */ struct thread * funcname_thread_add_event (struct thread_master *m, int (*func) (struct thread *), void *arg, int val, debugargdef) { struct thread *thread; assert (m != NULL); thread = thread_get (m, THREAD_EVENT, func, arg, debugargpass); thread->u.val = val; thread_list_add (&m->event, thread); return thread; } /* Cancel thread from scheduler. */ void thread_cancel (struct thread *thread) { struct thread_list *list = NULL; struct pqueue *queue = NULL; struct thread **thread_array = NULL; switch (thread->type) { case THREAD_READ: assert (fd_clear_read_write (thread->u.fd, &thread->master->readfd)); thread_array = thread->master->read; break; case THREAD_WRITE: assert (fd_clear_read_write (thread->u.fd, &thread->master->writefd)); thread_array = thread->master->write; break; case THREAD_TIMER: queue = thread->master->timer; break; case THREAD_EVENT: list = &thread->master->event; break; case THREAD_READY: list = &thread->master->ready; break; case THREAD_BACKGROUND: queue = thread->master->background; break; default: return; break; } if (queue) { assert(thread->index >= 0); assert(thread == queue->array[thread->index]); pqueue_remove_at(thread->index, queue); } else if (list) { thread_list_delete (list, thread); } else if (thread_array) { thread_delete_fd (thread_array, thread); } else { assert(!"Thread should be either in queue or list or array!"); } thread_add_unuse (thread); } /* Delete all events which has argument value arg. */ unsigned int thread_cancel_event (struct thread_master *m, void *arg) { unsigned int ret = 0; struct thread *thread; thread = m->event.head; while (thread) { struct thread *t; t = thread; thread = t->next; if (t->arg == arg) { ret++; thread_list_delete (&m->event, t); thread_add_unuse (t); } } /* thread can be on the ready list too */ thread = m->ready.head; while (thread) { struct thread *t; t = thread; thread = t->next; if (t->arg == arg) { ret++; thread_list_delete (&m->ready, t); thread_add_unuse (t); } } return ret; } static struct timeval * thread_timer_wait (struct pqueue *queue, struct timeval *timer_val) { if (queue->size) { struct thread *next_timer = queue->array[0]; *timer_val = timeval_subtract (next_timer->u.sands, relative_time); return timer_val; } return NULL; } static int thread_process_fds_helper (struct thread_master *m, struct thread *thread, thread_fd_set *fdset) { thread_fd_set *mfdset = NULL; struct thread **thread_array; if (!thread) return 0; if (thread->type == THREAD_READ) { mfdset = &m->readfd; thread_array = m->read; } else { mfdset = &m->writefd; thread_array = m->write; } if (fd_is_set (THREAD_FD (thread), fdset)) { fd_clear_read_write (THREAD_FD (thread), mfdset); thread_delete_fd (thread_array, thread); thread_list_add (&m->ready, thread); thread->type = THREAD_READY; return 1; } return 0; } static int thread_process_fds (struct thread_master *m, thread_fd_set *rset, thread_fd_set *wset, int num) { int ready = 0, index; for (index = 0; index < m->fd_limit && ready < num; ++index) { ready += thread_process_fds_helper (m, m->read[index], rset); ready += thread_process_fds_helper (m, m->write[index], wset); } return num - ready; } /* Add all timers that have popped to the ready list. */ static unsigned int thread_timer_process (struct pqueue *queue, struct timeval *timenow) { struct thread *thread; unsigned int ready = 0; while (queue->size) { thread = queue->array[0]; if (timeval_cmp (*timenow, thread->u.sands) < 0) return ready; pqueue_dequeue(queue); thread->type = THREAD_READY; thread_list_add (&thread->master->ready, thread); ready++; } return ready; } /* process a list en masse, e.g. for event thread lists */ static unsigned int thread_process (struct thread_list *list) { struct thread *thread; struct thread *next; unsigned int ready = 0; for (thread = list->head; thread; thread = next) { next = thread->next; thread_list_delete (list, thread); thread->type = THREAD_READY; thread_list_add (&thread->master->ready, thread); ready++; } return ready; } /* Fetch next ready thread. */ static struct thread * thread_fetch (struct thread_master *m) { struct thread *thread; thread_fd_set readfd; thread_fd_set writefd; thread_fd_set exceptfd; struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 }; struct timeval timer_val_bg; struct timeval *timer_wait = &timer_val; struct timeval *timer_wait_bg; while (1) { int num = 0; /* Signals pre-empt everything */ quagga_sigevent_process (); /* Drain the ready queue of already scheduled jobs, before scheduling * more. */ if ((thread = thread_trim_head (&m->ready)) != NULL) return thread; /* To be fair to all kinds of threads, and avoid starvation, we * need to be careful to consider all thread types for scheduling * in each quanta. I.e. we should not return early from here on. */ /* Normal event are the next highest priority. */ thread_process (&m->event); /* Structure copy. */ readfd = fd_copy_fd_set(m->readfd); writefd = fd_copy_fd_set(m->writefd); exceptfd = fd_copy_fd_set(m->exceptfd); /* Calculate select wait timer if nothing else to do */ if (m->ready.count == 0) { quagga_get_relative (NULL); timer_wait = thread_timer_wait (m->timer, &timer_val); timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg); if (timer_wait_bg && (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0))) timer_wait = timer_wait_bg; } num = fd_select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); /* Signals should get quick treatment */ if (num < 0) { if (errno == EINTR) continue; /* signal received - process it */ zlog_warn ("select() error: %s", safe_strerror (errno)); return NULL; } /* Check foreground timers. Historically, they have had higher priority than I/O threads, so let's push them onto the ready list in front of the I/O threads. */ quagga_get_relative (NULL); thread_timer_process (m->timer, &relative_time); /* Got IO, process it */ if (num > 0) thread_process_fds (m, &readfd, &writefd, num); #if 0 /* If any threads were made ready above (I/O or foreground timer), perhaps we should avoid adding background timers to the ready list at this time. If this is code is uncommented, then background timer threads will not run unless there is nothing else to do. */ if ((thread = thread_trim_head (&m->ready)) != NULL) return thread; #endif /* Background timer/events, lowest priority */ thread_timer_process (m->background, &relative_time); if ((thread = thread_trim_head (&m->ready)) != NULL) return thread; } } unsigned long thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime) { #ifdef HAVE_RUSAGE /* This is 'user + sys' time. */ *cputime = timeval_elapsed (now->cpu.ru_utime, start->cpu.ru_utime) + timeval_elapsed (now->cpu.ru_stime, start->cpu.ru_stime); #else *cputime = 0; #endif /* HAVE_RUSAGE */ return timeval_elapsed (now->real, start->real); } /* We should aim to yield after THREAD_YIELD_TIME_SLOT milliseconds. Note: we are using real (wall clock) time for this calculation. It could be argued that CPU time may make more sense in certain contexts. The things to consider are whether the thread may have blocked (in which case wall time increases, but CPU time does not), or whether the system is heavily loaded with other processes competing for CPU time. On balance, wall clock time seems to make sense. Plus it has the added benefit that gettimeofday should be faster than calling getrusage. */ int thread_should_yield (struct thread *thread) { quagga_get_relative (NULL); unsigned long t = timeval_elapsed(relative_time, thread->real); return ((t > THREAD_YIELD_TIME_SLOT) ? t : 0); } void thread_getrusage (RUSAGE_T *r) { quagga_get_relative (NULL); #ifdef HAVE_RUSAGE getrusage(RUSAGE_SELF, &(r->cpu)); #endif r->real = relative_time; #ifdef HAVE_CLOCK_MONOTONIC /* quagga_get_relative() only updates recent_time if gettimeofday * based, not when using CLOCK_MONOTONIC. As we export recent_time * and guarantee to update it before threads are run... */ quagga_gettimeofday(&recent_time); #endif /* HAVE_CLOCK_MONOTONIC */ } struct thread *thread_current = NULL; /* We check thread consumed time. If the system has getrusage, we'll use that to get in-depth stats on the performance of the thread in addition to wall clock time stats from gettimeofday. 'Dummy' threads (e.g. see funcname_thread_execute) must have thread->master == NULL. */ static void thread_call (struct thread *thread) { unsigned long realtime, cputime; RUSAGE_T before, after; /* Cache a pointer to the relevant cpu history thread, if the thread * does not have it yet. * * Callers submitting 'dummy threads' hence must take care that * thread->cpu is NULL */ if (!thread->hist) { struct cpu_thread_history tmp; tmp.func = thread->func; tmp.funcname = thread->funcname; thread->hist = hash_get (cpu_record, &tmp, (void * (*) (void *))cpu_record_hash_alloc); } GETRUSAGE (&before); thread->real = before.real; thread_current = thread; (*thread->func) (thread); thread_current = NULL; GETRUSAGE (&after); realtime = thread_consumed_time (&after, &before, &cputime); thread->hist->real.total += realtime; if (thread->hist->real.max < realtime) thread->hist->real.max = realtime; #ifdef HAVE_RUSAGE thread->hist->cpu.total += cputime; if (thread->hist->cpu.max < cputime) thread->hist->cpu.max = cputime; #endif ++(thread->hist->total_calls); thread->hist->types |= (1 << thread->add_type); #ifdef CONSUMED_TIME_CHECK if (realtime > CONSUMED_TIME_CHECK) { /* * We have a CPU Hog on our hands. * Whinge about it now, so we're aware this is yet another task * to fix. */ zlog_warn ("SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)", thread->funcname, (unsigned long) thread->func, realtime/1000, cputime/1000); } #endif /* CONSUMED_TIME_CHECK */ if (thread->master) thread_add_unuse (thread); } /* Execute thread */ struct thread * funcname_thread_execute (struct thread_master *m, int (*func)(struct thread *), void *arg, int val, debugargdef) { struct thread dummy; memset (&dummy, 0, sizeof (struct thread)); dummy.type = THREAD_EVENT; dummy.add_type = THREAD_EXECUTE; dummy.master = NULL; dummy.func = func; dummy.arg = arg; dummy.u.val = val; dummy.funcname = funcname; dummy.schedfrom = schedfrom; dummy.schedfrom_line = fromln; thread_call (&dummy); return NULL; } /* Co-operative thread main loop */ void thread_main (struct thread_master *master) { struct thread *t; while ((t = thread_fetch (master))) thread_call (t); } quagga-1.2.4/lib/thread.h000066400000000000000000000206421325323223500151550ustar00rootroot00000000000000/* 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 #include struct rusage_t { #ifdef HAVE_RUSAGE struct rusage cpu; #endif struct timeval real; }; #define RUSAGE_T struct rusage_t #define GETRUSAGE(X) thread_getrusage(X) /* Linked list of thread. */ struct thread_list { struct thread *head; struct thread *tail; int count; }; struct pqueue; /* * Abstract it so we can use different methodologies to * select on data. */ typedef fd_set thread_fd_set; /* Master of the theads. */ struct thread_master { struct thread **read; struct thread **write; struct pqueue *timer; struct thread_list event; struct thread_list ready; struct thread_list unuse; struct pqueue *background; int fd_limit; thread_fd_set readfd; thread_fd_set writefd; thread_fd_set exceptfd; unsigned long alloc; }; typedef unsigned char thread_type; /* Thread itself. */ struct thread { thread_type type; /* thread type */ thread_type add_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; int index; /* used for timers to store position in queue */ struct timeval real; struct cpu_thread_history *hist; /* cache pointer to cpu_history */ const char *funcname; const char *schedfrom; int schedfrom_line; }; struct cpu_thread_history { int (*func)(struct thread *); unsigned int total_calls; struct time_stats { unsigned long total, max; } real; #ifdef HAVE_RUSAGE struct time_stats cpu; #endif thread_type types; const char *funcname; }; /* Clocks supported by Quagga */ enum quagga_clkid { QUAGGA_CLK_REALTIME = 0, /* ala gettimeofday() */ QUAGGA_CLK_MONOTONIC, /* monotonic, against an indeterminate base */ QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */ }; /* Thread types. */ #define THREAD_READ 0 #define THREAD_WRITE 1 #define THREAD_TIMER 2 #define THREAD_EVENT 3 #define THREAD_READY 4 #define THREAD_BACKGROUND 5 #define THREAD_UNUSED 6 #define THREAD_EXECUTE 7 /* Thread yield time. */ #define THREAD_YIELD_TIME_SLOT 10 * 1000L /* 10ms */ /* 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_TIMER_MSEC_ON(master,thread,func,arg,time) \ do { \ if (! thread) \ thread = thread_add_timer_msec (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) #define debugargdef const char *funcname, const char *schedfrom, int fromln #define thread_add_read(m,f,a,v) funcname_thread_add_read(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_write(m,f,a,v) funcname_thread_add_write(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer(m,f,a,v) funcname_thread_add_timer(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer_msec(m,f,a,v) funcname_thread_add_timer_msec(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer_tv(m,f,a,v) funcname_thread_add_timer_tv(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_event(m,f,a,v) funcname_thread_add_event(m,f,a,v,#f,__FILE__,__LINE__) #define thread_execute(m,f,a,v) funcname_thread_execute(m,f,a,v,#f,__FILE__,__LINE__) /* The 4th arg to thread_add_background is the # of milliseconds to delay. */ #define thread_add_background(m,f,a,v) funcname_thread_add_background(m,f,a,v,#f,__FILE__,__LINE__) /* Prototypes. */ extern struct thread_master *thread_master_create (void); extern void thread_master_free (struct thread_master *); extern struct thread *funcname_thread_add_read (struct thread_master *, int (*)(struct thread *), void *, int, debugargdef); extern struct thread *funcname_thread_add_write (struct thread_master *, int (*)(struct thread *), void *, int, debugargdef); extern struct thread *funcname_thread_add_timer (struct thread_master *, int (*)(struct thread *), void *, long, debugargdef); extern struct thread *funcname_thread_add_timer_msec (struct thread_master *, int (*)(struct thread *), void *, long, debugargdef); extern struct thread *funcname_thread_add_timer_tv (struct thread_master *, int (*)(struct thread *), void *, struct timeval *, debugargdef); extern struct thread *funcname_thread_add_event (struct thread_master *, int (*)(struct thread *), void *, int, debugargdef); extern struct thread *funcname_thread_add_background (struct thread_master *, int (*func)(struct thread *), void *arg, long milliseconds_to_delay, debugargdef); extern struct thread *funcname_thread_execute (struct thread_master *, int (*)(struct thread *), void *, int, debugargdef); #undef debugargdef extern void thread_cancel (struct thread *); extern unsigned int thread_cancel_event (struct thread_master *, void *); extern void thread_main (struct thread_master *); extern unsigned long thread_timer_remain_second (struct thread *); extern struct timeval thread_timer_remain(struct thread*); extern int thread_should_yield (struct thread *); extern unsigned long timeval_elapsed (struct timeval a, struct timeval b); /* Internal libzebra exports */ extern void thread_getrusage (RUSAGE_T *); extern struct cmd_element show_thread_cpu_cmd; extern struct cmd_element clear_thread_cpu_cmd; /* replacements for the system gettimeofday(), clock_gettime() and * time() functions, providing support for non-decrementing clock on * all systems, and fully monotonic on /some/ systems. */ extern int quagga_gettime (enum quagga_clkid, struct timeval *); extern time_t quagga_time (time_t *); /* Returns elapsed real (wall clock) time. */ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, unsigned long *cpu_time_elapsed); /* Global variable containing a recent result from gettimeofday. This can be used instead of calling gettimeofday if a recent value is sufficient. This is guaranteed to be refreshed before a thread is called. */ extern struct timeval recent_time; /* Similar to recent_time, but a monotonically increasing time value */ extern struct timeval recent_relative_time (void); /* only for use in logging functions! */ extern struct thread *thread_current; #endif /* _ZEBRA_THREAD_H */ quagga-1.2.4/lib/vector.c000066400000000000000000000073701325323223500152060ustar00rootroot00000000000000/* 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->active = 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->active = v->active; 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->active == 0) return 0; for (i = 0; i < v->active; 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->active <= i) v->active = 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->active <= i) v->active = i + 1; return i; } /* Look up vector. */ void * vector_lookup (vector v, unsigned int i) { if (i >= v->active) 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->active) { v->active--; while (i && v->index[--i] == NULL && v->active--) ; /* 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->active; i++) if (v->index[i] != NULL) count++; return count; } quagga-1.2.4/lib/vector.h000066400000000000000000000042501325323223500152050ustar00rootroot00000000000000/* * 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 active; /* number of active slots */ 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. */ /* Reference slot at given index, caller must ensure slot is active */ #define vector_slot(V,I) ((V)->index[(I)]) /* Number of active slots. * Note that this differs from vector_count() as it the count returned * will include any empty slots */ #define vector_active(V) ((V)->active) /* Prototypes. */ extern vector vector_init (unsigned int size); extern void vector_ensure (vector v, unsigned int num); extern int vector_empty_slot (vector v); extern int vector_set (vector v, void *val); extern int vector_set_index (vector v, unsigned int i, void *val); extern void vector_unset (vector v, unsigned int i); extern unsigned int vector_count (vector v); extern void vector_only_wrapper_free (vector v); extern void vector_only_index_free (void *index); extern void vector_free (vector v); extern vector vector_copy (vector v); extern void *vector_lookup (vector, unsigned int); extern void *vector_lookup_ensure (vector, unsigned int); #endif /* _ZEBRA_VECTOR_H */ quagga-1.2.4/lib/version.h000066400000000000000000000027231325323223500153730ustar00rootroot00000000000000/* lib/version.h. Generated from version.h.in by configure. * * Quagga 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 #ifdef GIT_VERSION #include "gitversion.h" #endif #ifndef GIT_SUFFIX #define GIT_SUFFIX "" #endif #ifndef GIT_INFO #define GIT_INFO "" #endif #define QUAGGA_PROGNAME "Quagga" #define QUAGGA_VERSION "1.2.4" GIT_SUFFIX #define ZEBRA_BUG_ADDRESS "https://bugzilla.quagga.net" #define QUAGGA_URL "http://www.quagga.net" #define QUAGGA_COPYRIGHT "Copyright 1996-2005 Kunihiro Ishiguro, et al." #define QUAGGA_CONFIG_ARGS "" pid_t pid_output (const char *); #ifndef HAVE_DAEMON int daemon(int, int); #endif #endif /* _ZEBRA_VERSION_H */ quagga-1.2.4/lib/version.h.in000066400000000000000000000027041325323223500157770ustar00rootroot00000000000000/* @configure_input@ * * Quagga 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 #ifdef GIT_VERSION #include "gitversion.h" #endif #ifndef GIT_SUFFIX #define GIT_SUFFIX "" #endif #ifndef GIT_INFO #define GIT_INFO "" #endif #define QUAGGA_PROGNAME "@PACKAGE_NAME@" #define QUAGGA_VERSION "@PACKAGE_VERSION@" GIT_SUFFIX #define ZEBRA_BUG_ADDRESS "@PACKAGE_BUGREPORT@" #define QUAGGA_URL "http://www.quagga.net" #define QUAGGA_COPYRIGHT "Copyright 1996-2005 Kunihiro Ishiguro, et al." #define QUAGGA_CONFIG_ARGS "@CONFIG_ARGS@" pid_t pid_output (const char *); #ifndef HAVE_DAEMON int daemon(int, int); #endif #endif /* _ZEBRA_VERSION_H */ quagga-1.2.4/lib/vrf.c000066400000000000000000000402051325323223500144730ustar00rootroot00000000000000/* * VRF functions. * Copyright (C) 2014 6WIND S.A. * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_NETNS #undef _GNU_SOURCE #define _GNU_SOURCE #include #endif #include "if.h" #include "vrf.h" #include "prefix.h" #include "table.h" #include "log.h" #include "memory.h" #include "command.h" #include "vty.h" #ifndef CLONE_NEWNET #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ #endif #ifndef HAVE_SETNS static inline int setns(int fd, int nstype) { #ifdef __NR_setns return syscall(__NR_setns, fd, nstype); #else errno = ENOSYS; return -1; #endif } #endif /* HAVE_SETNS */ #define VRF_RUN_DIR "/var/run/netns" #ifdef HAVE_NETNS #define VRF_DEFAULT_NAME "/proc/self/ns/net" static int have_netns_enabled = -1; #else /* !HAVE_NETNS */ #define VRF_DEFAULT_NAME "Default-IP-Routing-Table" #endif /* HAVE_NETNS */ static int have_netns(void) { #ifdef HAVE_NETNS if (have_netns_enabled < 0) { int fd = open (VRF_DEFAULT_NAME, O_RDONLY); if (fd < 0) have_netns_enabled = 0; else { have_netns_enabled = 1; close(fd); } } return have_netns_enabled; #else return 0; #endif } struct vrf { /* Identifier, same as the vector index */ vrf_id_t vrf_id; /* Name */ char *name; /* File descriptor */ int fd; /* Master list of interfaces belonging to this VRF */ struct list *iflist; /* User data */ void *info; }; /* Holding VRF hooks */ struct vrf_master { int (*vrf_new_hook) (vrf_id_t, void **); int (*vrf_delete_hook) (vrf_id_t, void **); int (*vrf_enable_hook) (vrf_id_t, void **); int (*vrf_disable_hook) (vrf_id_t, void **); } vrf_master = {0,}; /* VRF table */ struct route_table *vrf_table = NULL; static int vrf_is_enabled (struct vrf *vrf); static int vrf_enable (struct vrf *vrf); static void vrf_disable (struct vrf *vrf); /* Build the table key */ static void vrf_build_key (vrf_id_t vrf_id, struct prefix *p) { p->family = AF_INET; p->prefixlen = IPV4_MAX_BITLEN; p->u.prefix4.s_addr = vrf_id; } /* Get a VRF. If not found, create one. */ static struct vrf * vrf_get (vrf_id_t vrf_id) { struct prefix p; struct route_node *rn; struct vrf *vrf; vrf_build_key (vrf_id, &p); rn = route_node_get (vrf_table, &p); if (rn->info) { vrf = (struct vrf *)rn->info; route_unlock_node (rn); /* get */ return vrf; } vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); vrf->vrf_id = vrf_id; vrf->fd = -1; rn->info = vrf; /* Initialize interfaces. */ if_init (vrf_id, &vrf->iflist); zlog_info ("VRF %u is created.", vrf_id); if (vrf_master.vrf_new_hook) (*vrf_master.vrf_new_hook) (vrf_id, &vrf->info); return vrf; } /* Delete a VRF. This is called in vrf_terminate(). */ static void vrf_delete (struct vrf *vrf) { zlog_info ("VRF %u is to be deleted.", vrf->vrf_id); vrf_disable (vrf); if (vrf_master.vrf_delete_hook) (*vrf_master.vrf_delete_hook) (vrf->vrf_id, &vrf->info); if_terminate (vrf->vrf_id, &vrf->iflist); if (vrf->name) XFREE (MTYPE_VRF_NAME, vrf->name); XFREE (MTYPE_VRF, vrf); } /* Look up a VRF by identifier. */ static struct vrf * vrf_lookup (vrf_id_t vrf_id) { struct prefix p; struct route_node *rn; struct vrf *vrf = NULL; vrf_build_key (vrf_id, &p); rn = route_node_lookup (vrf_table, &p); if (rn) { vrf = (struct vrf *)rn->info; route_unlock_node (rn); /* lookup */ } return vrf; } /* * Check whether the VRF is enabled - that is, whether the VRF * is ready to allocate resources. Currently there's only one * type of resource: socket. */ static int vrf_is_enabled (struct vrf *vrf) { if (have_netns()) return vrf && vrf->fd >= 0; else return vrf && vrf->fd == -2 && vrf->vrf_id == VRF_DEFAULT; } /* * Enable a VRF - that is, let the VRF be ready to use. * The VRF_ENABLE_HOOK callback will be called to inform * that they can allocate resources in this VRF. * * RETURN: 1 - enabled successfully; otherwise, 0. */ static int vrf_enable (struct vrf *vrf) { if (!vrf_is_enabled (vrf)) { if (have_netns()) { vrf->fd = open (vrf->name, O_RDONLY); } else { vrf->fd = -2; /* Remember that vrf_enable_hook has been called */ errno = -ENOTSUP; } if (!vrf_is_enabled (vrf)) { zlog_err ("Can not enable VRF %u: %s!", vrf->vrf_id, safe_strerror (errno)); return 0; } if (have_netns()) zlog_info ("VRF %u is associated with NETNS %s.", vrf->vrf_id, vrf->name); zlog_info ("VRF %u is enabled.", vrf->vrf_id); if (vrf_master.vrf_enable_hook) (*vrf_master.vrf_enable_hook) (vrf->vrf_id, &vrf->info); } return 1; } /* * Disable a VRF - that is, let the VRF be unusable. * The VRF_DELETE_HOOK callback will be called to inform * that they must release the resources in the VRF. */ static void vrf_disable (struct vrf *vrf) { if (vrf_is_enabled (vrf)) { zlog_info ("VRF %u is to be disabled.", vrf->vrf_id); if (vrf_master.vrf_disable_hook) (*vrf_master.vrf_disable_hook) (vrf->vrf_id, &vrf->info); if (have_netns()) close (vrf->fd); vrf->fd = -1; } } /* Add a VRF hook. Please add hooks before calling vrf_init(). */ void vrf_add_hook (int type, int (*func)(vrf_id_t, void **)) { switch (type) { case VRF_NEW_HOOK: vrf_master.vrf_new_hook = func; break; case VRF_DELETE_HOOK: vrf_master.vrf_delete_hook = func; break; case VRF_ENABLE_HOOK: vrf_master.vrf_enable_hook = func; break; case VRF_DISABLE_HOOK: vrf_master.vrf_disable_hook = func; break; default: break; } } /* Return the iterator of the first VRF. */ vrf_iter_t vrf_first (void) { struct route_node *rn; for (rn = route_top (vrf_table); rn; rn = route_next (rn)) if (rn->info) { route_unlock_node (rn); /* top/next */ return (vrf_iter_t)rn; } return VRF_ITER_INVALID; } /* Return the next VRF iterator to the given iterator. */ vrf_iter_t vrf_next (vrf_iter_t iter) { struct route_node *rn = NULL; /* Lock it first because route_next() will unlock it. */ if (iter != VRF_ITER_INVALID) rn = route_next (route_lock_node ((struct route_node *)iter)); for (; rn; rn = route_next (rn)) if (rn->info) { route_unlock_node (rn); /* next */ return (vrf_iter_t)rn; } return VRF_ITER_INVALID; } /* Return the VRF iterator of the given VRF ID. If it does not exist, * the iterator of the next existing VRF is returned. */ vrf_iter_t vrf_iterator (vrf_id_t vrf_id) { struct prefix p; struct route_node *rn; vrf_build_key (vrf_id, &p); rn = route_node_get (vrf_table, &p); if (rn->info) { /* OK, the VRF exists. */ route_unlock_node (rn); /* get */ return (vrf_iter_t)rn; } /* Find the next VRF. */ for (rn = route_next (rn); rn; rn = route_next (rn)) if (rn->info) { route_unlock_node (rn); /* next */ return (vrf_iter_t)rn; } return VRF_ITER_INVALID; } /* Obtain the VRF ID from the given VRF iterator. */ vrf_id_t vrf_iter2id (vrf_iter_t iter) { struct route_node *rn = (struct route_node *) iter; return (rn && rn->info) ? ((struct vrf *)rn->info)->vrf_id : VRF_DEFAULT; } /* Obtain the data pointer from the given VRF iterator. */ void * vrf_iter2info (vrf_iter_t iter) { struct route_node *rn = (struct route_node *) iter; return (rn && rn->info) ? ((struct vrf *)rn->info)->info : NULL; } /* Obtain the interface list from the given VRF iterator. */ struct list * vrf_iter2iflist (vrf_iter_t iter) { struct route_node *rn = (struct route_node *) iter; return (rn && rn->info) ? ((struct vrf *)rn->info)->iflist : NULL; } /* Get the data pointer of the specified VRF. If not found, create one. */ void * vrf_info_get (vrf_id_t vrf_id) { struct vrf *vrf = vrf_get (vrf_id); return vrf->info; } /* Look up the data pointer of the specified VRF. */ void * vrf_info_lookup (vrf_id_t vrf_id) { struct vrf *vrf = vrf_lookup (vrf_id); return vrf ? vrf->info : NULL; } /* Look up the interface list in a VRF. */ struct list * vrf_iflist (vrf_id_t vrf_id) { struct vrf * vrf = vrf_lookup (vrf_id); return vrf ? vrf->iflist : NULL; } /* Get the interface list of the specified VRF. Create one if not find. */ struct list * vrf_iflist_get (vrf_id_t vrf_id) { struct vrf * vrf = vrf_get (vrf_id); return vrf->iflist; } /* * VRF bit-map */ #define VRF_BITMAP_NUM_OF_GROUPS 8 #define VRF_BITMAP_NUM_OF_BITS_IN_GROUP \ (UINT16_MAX / VRF_BITMAP_NUM_OF_GROUPS) #define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \ (VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */ #define VRF_BITMAP_GROUP(_id) \ ((_id) / VRF_BITMAP_NUM_OF_BITS_IN_GROUP) #define VRF_BITMAP_BIT_OFFSET(_id) \ ((_id) % VRF_BITMAP_NUM_OF_BITS_IN_GROUP) #define VRF_BITMAP_INDEX_IN_GROUP(_bit_offset) \ ((_bit_offset) / CHAR_BIT) #define VRF_BITMAP_FLAG(_bit_offset) \ (((u_char)1) << ((_bit_offset) % CHAR_BIT)) struct vrf_bitmap { u_char *groups[VRF_BITMAP_NUM_OF_GROUPS]; }; vrf_bitmap_t vrf_bitmap_init (void) { return (vrf_bitmap_t) XCALLOC (MTYPE_VRF_BITMAP, sizeof (struct vrf_bitmap)); } void vrf_bitmap_free (vrf_bitmap_t bmap) { struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap; int i; if (bmap == VRF_BITMAP_NULL) return; for (i = 0; i < VRF_BITMAP_NUM_OF_GROUPS; i++) if (bm->groups[i]) XFREE (MTYPE_VRF_BITMAP, bm->groups[i]); XFREE (MTYPE_VRF_BITMAP, bm); } void vrf_bitmap_set (vrf_bitmap_t bmap, vrf_id_t vrf_id) { struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap; u_char group = VRF_BITMAP_GROUP (vrf_id); u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); if (bmap == VRF_BITMAP_NULL) return; if (bm->groups[group] == NULL) bm->groups[group] = XCALLOC (MTYPE_VRF_BITMAP, VRF_BITMAP_NUM_OF_BYTES_IN_GROUP); SET_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)], VRF_BITMAP_FLAG (offset)); } void vrf_bitmap_unset (vrf_bitmap_t bmap, vrf_id_t vrf_id) { struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap; u_char group = VRF_BITMAP_GROUP (vrf_id); u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); if (bmap == VRF_BITMAP_NULL || bm->groups[group] == NULL) return; UNSET_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)], VRF_BITMAP_FLAG (offset)); } int vrf_bitmap_check (vrf_bitmap_t bmap, vrf_id_t vrf_id) { struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap; u_char group = VRF_BITMAP_GROUP (vrf_id); u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); if (bmap == VRF_BITMAP_NULL || bm->groups[group] == NULL) return 0; return CHECK_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)], VRF_BITMAP_FLAG (offset)) ? 1 : 0; } /* * VRF realization with NETNS */ static char * vrf_netns_pathname (struct vty *vty, const char *name) { static char pathname[PATH_MAX]; char *result; if (name[0] == '/') /* absolute pathname */ result = realpath (name, pathname); else /* relevant pathname */ { char tmp_name[PATH_MAX]; snprintf (tmp_name, PATH_MAX, "%s/%s", VRF_RUN_DIR, name); result = realpath (tmp_name, pathname); } if (! result) { vty_out (vty, "Invalid pathname: %s%s", safe_strerror (errno), VTY_NEWLINE); return NULL; } return pathname; } DEFUN (vrf_netns, vrf_netns_cmd, "vrf <1-65535> netns NAME", "Enable a VRF\n" "Specify the VRF identifier\n" "Associate with a NETNS\n" "The file name in " VRF_RUN_DIR ", or a full pathname\n") { vrf_id_t vrf_id = VRF_DEFAULT; struct vrf *vrf = NULL; char *pathname = vrf_netns_pathname (vty, argv[1]); if (!pathname) return CMD_WARNING; VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); vrf = vrf_get (vrf_id); if (vrf->name && strcmp (vrf->name, pathname) != 0) { vty_out (vty, "VRF %u is already configured with NETNS %s%s", vrf->vrf_id, vrf->name, VTY_NEWLINE); return CMD_WARNING; } if (!vrf->name) vrf->name = XSTRDUP (MTYPE_VRF_NAME, pathname); if (!vrf_enable (vrf)) { vty_out (vty, "Can not associate VRF %u with NETNS %s%s", vrf->vrf_id, vrf->name, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (no_vrf_netns, no_vrf_netns_cmd, "no vrf <1-65535> netns NAME", NO_STR "Enable a VRF\n" "Specify the VRF identifier\n" "Associate with a NETNS\n" "The file name in " VRF_RUN_DIR ", or a full pathname\n") { vrf_id_t vrf_id = VRF_DEFAULT; struct vrf *vrf = NULL; char *pathname = vrf_netns_pathname (vty, argv[1]); if (!pathname) return CMD_WARNING; VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); vrf = vrf_lookup (vrf_id); if (!vrf) { vty_out (vty, "VRF %u is not found%s", vrf_id, VTY_NEWLINE); return CMD_SUCCESS; } if (vrf->name && strcmp (vrf->name, pathname) != 0) { vty_out (vty, "Incorrect NETNS file name%s", VTY_NEWLINE); return CMD_WARNING; } vrf_disable (vrf); if (vrf->name) { XFREE (MTYPE_VRF_NAME, vrf->name); vrf->name = NULL; } return CMD_SUCCESS; } /* VRF node. */ static struct cmd_node vrf_node = { VRF_NODE, "", /* VRF node has no interface. */ 1 }; /* VRF configuration write function. */ static int vrf_config_write (struct vty *vty) { struct route_node *rn; struct vrf *vrf; int write = 0; for (rn = route_top (vrf_table); rn; rn = route_next (rn)) if ((vrf = rn->info) != NULL && vrf->vrf_id != VRF_DEFAULT && vrf->name) { vty_out (vty, "vrf %u netns %s%s", vrf->vrf_id, vrf->name, VTY_NEWLINE); write++; } return write; } /* Initialize VRF module. */ void vrf_init (void) { struct vrf *default_vrf; /* Allocate VRF table. */ vrf_table = route_table_init (); /* The default VRF always exists. */ default_vrf = vrf_get (VRF_DEFAULT); if (!default_vrf) { zlog_err ("vrf_init: failed to create the default VRF!"); exit (1); } /* Set the default VRF name. */ default_vrf->name = XSTRDUP (MTYPE_VRF_NAME, VRF_DEFAULT_NAME); /* Enable the default VRF. */ if (!vrf_enable (default_vrf)) { zlog_err ("vrf_init: failed to enable the default VRF!"); exit (1); } if (have_netns()) { /* Install VRF commands. */ install_node (&vrf_node, vrf_config_write); install_element (CONFIG_NODE, &vrf_netns_cmd); install_element (CONFIG_NODE, &no_vrf_netns_cmd); } } /* Terminate VRF module. */ void vrf_terminate (void) { struct route_node *rn; struct vrf *vrf; for (rn = route_top (vrf_table); rn; rn = route_next (rn)) if ((vrf = rn->info) != NULL) vrf_delete (vrf); route_table_finish (vrf_table); vrf_table = NULL; } /* Create a socket for the VRF. */ int vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id) { struct vrf *vrf = vrf_lookup (vrf_id); int ret = -1; if (!vrf_is_enabled (vrf)) { errno = ENOSYS; return -1; } if (have_netns()) { ret = (vrf_id != VRF_DEFAULT) ? setns (vrf->fd, CLONE_NEWNET) : 0; if (ret >= 0) { ret = socket (domain, type, protocol); if (vrf_id != VRF_DEFAULT) setns (vrf_lookup (VRF_DEFAULT)->fd, CLONE_NEWNET); } } else ret = socket (domain, type, protocol); return ret; } quagga-1.2.4/lib/vrf.h000066400000000000000000000075421325323223500145070ustar00rootroot00000000000000/* * VRF related header. * Copyright (C) 2014 6WIND S.A. * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_VRF_H #define _ZEBRA_VRF_H #include "linklist.h" /* The default VRF ID */ #define VRF_DEFAULT 0 /* * The command strings */ #define VRF_CMD_STR "vrf <0-65535>" #define VRF_CMD_HELP_STR "Specify the VRF\nThe VRF ID\n" #define VRF_ALL_CMD_STR "vrf all" #define VRF_ALL_CMD_HELP_STR "Specify the VRF\nAll VRFs\n" /* * VRF hooks */ #define VRF_NEW_HOOK 0 /* a new VRF is just created */ #define VRF_DELETE_HOOK 1 /* a VRF is to be deleted */ #define VRF_ENABLE_HOOK 2 /* a VRF is ready to use */ #define VRF_DISABLE_HOOK 3 /* a VRF is to be unusable */ /* * Add a specific hook to VRF module. * @param1: hook type * @param2: the callback function * - param 1: the VRF ID * - param 2: the address of the user data pointer (the user data * can be stored in or freed from there) */ extern void vrf_add_hook (int, int (*)(vrf_id_t, void **)); /* * VRF iteration */ typedef void * vrf_iter_t; #define VRF_ITER_INVALID NULL /* invalid value of the iterator */ /* * VRF iteration utilities. Example for the usage: * * vrf_iter_t iter = vrf_first(); * for (; iter != VRF_ITER_INVALID; iter = vrf_next (iter)) * * or * * vrf_iter_t iter = vrf_iterator (); * for (; iter != VRF_ITER_INVALID; iter = vrf_next (iter)) */ /* Return the iterator of the first VRF. */ extern vrf_iter_t vrf_first (void); /* Return the next VRF iterator to the given iterator. */ extern vrf_iter_t vrf_next (vrf_iter_t); /* Return the VRF iterator of the given VRF ID. If it does not exist, * the iterator of the next existing VRF is returned. */ extern vrf_iter_t vrf_iterator (vrf_id_t); /* * VRF iterator to properties */ extern vrf_id_t vrf_iter2id (vrf_iter_t); extern void *vrf_iter2info (vrf_iter_t); extern struct list *vrf_iter2iflist (vrf_iter_t); /* * Utilities to obtain the user data */ /* Get the data pointer of the specified VRF. If not found, create one. */ extern void *vrf_info_get (vrf_id_t); /* Look up the data pointer of the specified VRF. */ extern void *vrf_info_lookup (vrf_id_t); /* * Utilities to obtain the interface list */ /* Look up the interface list of the specified VRF. */ extern struct list *vrf_iflist (vrf_id_t); /* Get the interface list of the specified VRF. Create one if not find. */ extern struct list *vrf_iflist_get (vrf_id_t); /* * VRF bit-map: maintaining flags, one bit per VRF ID */ typedef void * vrf_bitmap_t; #define VRF_BITMAP_NULL NULL extern vrf_bitmap_t vrf_bitmap_init (void); extern void vrf_bitmap_free (vrf_bitmap_t); extern void vrf_bitmap_set (vrf_bitmap_t, vrf_id_t); extern void vrf_bitmap_unset (vrf_bitmap_t, vrf_id_t); extern int vrf_bitmap_check (vrf_bitmap_t, vrf_id_t); /* * VRF initializer/destructor */ /* Please add hooks before calling vrf_init(). */ extern void vrf_init (void); extern void vrf_terminate (void); /* * VRF utilities */ /* Create a socket serving for the given VRF */ extern int vrf_socket (int, int, int, vrf_id_t); #endif /*_ZEBRA_VRF_H*/ quagga-1.2.4/lib/vty.c000066400000000000000000002140251325323223500145230ustar00rootroot00000000000000/* * 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 "thread.h" #include "buffer.h" #include #include "command.h" #include "sockunion.h" #include "memory.h" #include "str.h" #include "log.h" #include "prefix.h" #include "filter.h" #include "vty.h" #include "privs.h" #include "network.h" #include #include #define VTY_BUFSIZ 4096 /* Vty events */ enum event { VTY_SERV, VTY_READ, VTY_WRITE, VTY_TIMEOUT_RESET, #ifdef VTYSH VTYSH_SERV, VTYSH_READ, VTYSH_WRITE #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. */ static 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; /* Restrict unauthenticated logins? */ static const u_char restricted_mode_default = 0; static u_char restricted_mode = 0; /* Integrated configuration file path */ char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; static int do_log_commands = 0; static void vty_buf_assert (struct vty *vty) { assert (vty->cp <= vty->length); assert (vty->length < vty->max); assert (vty->buf[vty->length] == '\0'); } /* Sanity/safety wrappers around access to vty->buf */ static void vty_buf_put (struct vty *vty, char c) { vty_buf_assert (vty); vty->buf[vty->cp] = c; vty->buf[vty->max - 1] = '\0'; } /* 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; if (vty_shell (vty)) { va_start (args, format); vprintf (format, args); va_end (args); } else { /* Try to write to initial buffer. */ va_start (args, format); len = vsnprintf (buf, sizeof(buf), format, args); va_end (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; va_start (args, format); len = vsnprintf (p, size, format, args); va_end (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. */ buffer_put (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); } return len; } static int vty_log_out (struct vty *vty, const char *level, const char *proto_str, const char *format, struct timestamp_control *ctl, va_list va) { int ret; int len; char buf[1024]; if (!ctl->already_rendered) { ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); ctl->already_rendered = 1; } if (ctl->len+1 >= sizeof(buf)) return -1; memcpy(buf, ctl->buf, len = ctl->len); buf[len++] = ' '; buf[len] = '\0'; if (level) ret = snprintf(buf+len, sizeof(buf)-len, "%s: %s: ", level, proto_str); else ret = snprintf(buf+len, sizeof(buf)-len, "%s: ", proto_str); if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf))) return -1; if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) || ((size_t)((len += ret)+2) > sizeof(buf))) return -1; buf[len++] = '\r'; buf[len++] = '\n'; if (write(vty->wfd, buf, len) < 0) { if (ERRNO_IO_RETRY(errno)) /* Kernel buffer is full, probably too much debugging output, so just drop the data and ignore. */ return -1; /* Fatal I/O error. */ vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ zlog_warn("%s: write failed to vty client fd %d, closing: %s", __func__, vty->fd, safe_strerror(errno)); buffer_reset(vty->obuf); /* cannot call vty_close, because a parent routine may still try to access the vty struct */ vty->status = VTY_CLOSE; shutdown(vty->fd, SHUT_RDWR); return -1; } return 0; } /* Output current time to the vty. */ void vty_time_print (struct vty *vty, int cr) { char buf[QUAGGA_TIMESTAMP_LEN]; if (quagga_timestamp(0, buf, sizeof(buf)) == 0) { zlog (NULL, LOG_INFO, "quagga_timestamp 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.motdfile) { FILE *f; char buf[4096]; f = fopen (host.motdfile, "r"); if (f) { while (fgets (buf, sizeof (buf), f)) { char *s; /* work backwards to ignore trailling isspace() */ for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1)); s--); *s = '\0'; vty_out (vty, "%s%s", buf, VTY_NEWLINE); } fclose (f); } else vty_out (vty, "MOTD file not found%s", VTY_NEWLINE); } else if (host.motd) vty_out (vty, "%s", 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. */ static void vty_will_echo (struct vty *vty) { unsigned 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) { unsigned 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) { unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; vty_out (vty, "%s", cmd); } /* Use window size. */ static void vty_do_window_size (struct vty *vty) { unsigned 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) { unsigned 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 = buffer_new(0); /* Use default buffer size. */ new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); new->max = VTY_BUFSIZ; 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.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.encrypt) passwd = host.enable_encrypt; else passwd = host.enable; next_node = ENABLE_NODE; break; } if (passwd) { if (host.encrypt) fail = strcmp (crypt(buf, passwd), passwd); else fail = strcmp (buf, passwd); } 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 = restricted_mode ? RESTRICTED_NODE : VIEW_NODE; } } } } /* Command execution over the vty interface. */ static int vty_command (struct vty *vty, char *buf) { int ret; vector vline; const char *protocolname; char *cp = NULL; /* * Log non empty command lines */ if (do_log_commands) cp = buf; if (cp != NULL) { /* Skip white spaces. */ while (isspace ((int) *cp) && *cp != '\0') cp++; } if (cp != NULL && *cp != '\0') { unsigned i; char vty_str[VTY_BUFSIZ]; char prompt_str[VTY_BUFSIZ]; /* format the base vty info */ snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address); if (vty) for (i = 0; i < vector_active (vtyvec); i++) if (vty == vector_slot (vtyvec, i)) { snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s", i, vty->address); break; } /* format the prompt */ snprintf(prompt_str, sizeof(prompt_str), cmd_prompt (vty->node), vty_str); /* now log the command */ zlog(NULL, LOG_ERR, "%s%s", prompt_str, buf); } /* Split readline string up into the vector */ vline = cmd_make_strvec (buf); if (vline == NULL) return CMD_SUCCESS; #ifdef CONSUMED_TIME_CHECK { RUSAGE_T before; RUSAGE_T after; unsigned long realtime, cputime; GETRUSAGE(&before); #endif /* CONSUMED_TIME_CHECK */ ret = cmd_execute_command (vline, vty, NULL, 0); /* Get the name of the protocol if any */ if (zlog_default) protocolname = zlog_proto_names[zlog_default->protocol]; else protocolname = zlog_proto_names[ZLOG_NONE]; #ifdef CONSUMED_TIME_CHECK GETRUSAGE(&after); if ((realtime = thread_consumed_time(&after, &before, &cputime)) > CONSUMED_TIME_CHECK) /* Warn about CPU hog that must be fixed. */ zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s", realtime/1000, cputime/1000, buf); } #endif /* CONSUMED_TIME_CHECK */ 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, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE); break; case CMD_ERR_INCOMPLETE: vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); break; } cmd_free_strvec (vline); return ret; } static const char telnet_backward_char = 0x08; static const char telnet_space_char = ' '; /* Basic function to write buffer to vty. */ static void vty_write (struct vty *vty, const 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_put (vty->obuf, buf, nbytes); } /* Basic function to insert character into vty. */ static void vty_self_insert (struct vty *vty, char c) { int i; int length; vty_buf_assert (vty); /* length is sans nul, max is with */ if (vty->length + 1 >= vty->max) return; length = vty->length - vty->cp; memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); vty->length++; vty->buf[vty->length] = '\0'; vty_buf_put (vty, 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_buf_assert (vty); } /* Self insert character 'c' in overwrite mode. */ static void vty_self_insert_overwrite (struct vty *vty, char c) { vty_buf_assert (vty); if (vty->cp == vty->length) { vty_self_insert (vty, c); return; } vty_buf_put (vty, c); vty->cp++; vty_buf_assert (vty); vty_write (vty, &c, 1); } /** * Insert a string into vty->buf at the current cursor position. * * If the resultant string would be larger than VTY_BUFSIZ it is * truncated to fit. */ static void vty_insert_word_overwrite (struct vty *vty, char *str) { vty_buf_assert (vty); size_t nwrite = MIN ((int) strlen (str), vty->max - vty->cp - 1); memcpy (&vty->buf[vty->cp], str, nwrite); vty->cp += nwrite; vty->length = vty->cp; vty->buf[vty->length] = '\0'; vty_buf_assert (vty); vty_write (vty, str, nwrite); } /* Forward character. */ static void vty_forward_char (struct vty *vty) { vty_buf_assert (vty); if (vty->cp < vty->length) { vty_write (vty, &vty->buf[vty->cp], 1); vty->cp++; } vty_buf_assert (vty); } /* Backward character. */ static void vty_backward_char (struct vty *vty) { vty_buf_assert (vty); if (vty->cp > 0) { vty->cp--; vty_write (vty, &telnet_backward_char, 1); } vty_buf_assert (vty); } /* 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; vty->buf[vty->length] = '\0'; vty_buf_assert (vty); /* Redraw current line */ vty_redraw_line (vty); } /* Show next command line history. */ static 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. */ static 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; vty_buf_assert (vty); } /* 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_cmd.func)(NULL, vty, 0, NULL); vty_prompt (vty); vty->cp = 0; } /* When '^Z' is received from vty, move down to the enable mode. */ static void vty_end_config (struct vty *vty) { vty_out (vty, "%s", VTY_NEWLINE); switch (vty->node) { case VIEW_NODE: case ENABLE_NODE: case RESTRICTED_NODE: /* Nothing to do. */ break; case CONFIG_NODE: case INTERFACE_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: case BABEL_NODE: case BGP_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: case BGP_ENCAP_NODE: case BGP_ENCAPV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: case ISIS_NODE: case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: case PIM_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->length == 0) { vty_down_level (vty); return; } if (vty->cp == vty->length) return; /* completion need here? */ vty_buf_assert (vty); size = vty->length - vty->cp; vty->length--; memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1); vty->buf[vty->length] = '\0'; if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) return; 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; vty_buf_assert (vty); } /* 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, NULL); matched = cmd_complete_command_lib (vline, vty, &ret, 1); 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); } static void vty_describe_fold (struct vty *vty, int cmd_width, unsigned int desc_width, struct cmd_token *token) { char *buf; const char *cmd, *p; int pos; cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd; if (desc_width <= 0) { vty_out (vty, " %-*s %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE); return; } buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1); for (p = token->desc; 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; unsigned int i, width, desc_width; struct cmd_token *token, *token_cr = NULL; vline = cmd_make_strvec (vty->buf); /* In case of '> ?'. */ if (vline == NULL) { vline = vector_init (1); vector_set (vline, NULL); } else if (isspace ((int) vty->buf[vty->length - 1])) vector_set (vline, NULL); describe = cmd_describe_command (vline, vty, &ret); vty_out (vty, "%s", VTY_NEWLINE); /* Ambiguous error. */ switch (ret) { case CMD_ERR_AMBIGUOUS: vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); goto out; break; case CMD_ERR_NO_MATCH: vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); goto out; break; } /* Get width of command string. */ width = 0; for (i = 0; i < vector_active (describe); i++) if ((token = vector_slot (describe, i)) != NULL) { unsigned int len; if (token->cmd[0] == '\0') continue; len = strlen (token->cmd); if (token->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_active (describe); i++) if ((token = vector_slot (describe, i)) != NULL) { if (token->cmd[0] == '\0') continue; if (strcmp (token->cmd, command_cr) == 0) { token_cr = token; continue; } if (!token->desc) vty_out (vty, " %-s%s", token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, VTY_NEWLINE); else if (desc_width >= strlen (token->desc)) vty_out (vty, " %-*s %s%s", width, token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, token->desc, VTY_NEWLINE); else vty_describe_fold (vty, width, desc_width, token); #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 ((token = token_cr)) { if (!token->desc) vty_out (vty, " %-s%s", token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, VTY_NEWLINE); else if (desc_width >= strlen (token->desc)) vty_out (vty, " %-*s %s%s", width, token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, token->desc, VTY_NEWLINE); else vty_describe_fold (vty, width, desc_width, token); } out: cmd_free_strvec (vline); if (describe) vector_free (describe); vty_prompt (vty); vty_redraw_line (vty); } static 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: case RESTRICTED_NODE: /* Nothing to do. */ break; case CONFIG_NODE: case INTERFACE_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: case BABEL_NODE: case BGP_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: case ISIS_NODE: case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: case PIM_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: vty->sb_len = 0; vty->iac_sb_in_progress = 1; return 0; break; case SE: { if (!vty->iac_sb_in_progress) return 0; if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0')) { vty->iac_sb_in_progress = 0; return 0; } switch (vty->sb_buf[0]) { case TELOPT_NAWS: if (vty->sb_len != TELNET_NAWS_SB_LEN) zlog_warn("RFC 1073 violation detected: telnet NAWS option " "should send %d characters, but we received %lu", TELNET_NAWS_SB_LEN, (u_long)vty->sb_len); else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN) zlog_err("Bug detected: sizeof(vty->sb_buf) %lu < %d, " "too small to handle the telnet NAWS option", (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN); else { vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]); vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]); #ifdef TELNET_OPTION_DEBUG vty_out(vty, "TELNET NAWS window size negotiation completed: " "width %d, height %d%s", vty->width, vty->height, VTY_NEWLINE); #endif } 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_prompt (vty); return ret; } #define CONTROL(X) ((X) - '@') #define VTY_NORMAL 0 #define VTY_PRE_ESCAPE 1 /* Esc seen */ #define VTY_ESCAPE 2 /* ANSI terminal escape (Esc-[) seen */ #define VTY_LITERAL 3 /* Next char taken as literal */ /* 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 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 */ if ((nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) { if (nbytes < 0) { if (ERRNO_IO_RETRY(errno)) { vty_event (VTY_READ, vty_sock, vty); return 0; } vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ zlog_warn("%s: read error on vty client fd %d, closing: %s", __func__, vty->fd, safe_strerror(errno)); buffer_reset(vty->obuf); } 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) { if (vty->sb_len < sizeof(vty->sb_buf)) vty->sb_buf[vty->sb_len] = buf[i]; vty->sb_len++; continue; } if (vty->iac) { /* In case of telnet command */ int ret = 0; 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': vty_buffer_reset (vty); break; #if 0 /* More line does not work for "show ip bgp". */ case '\n': case '\r': vty->status = VTY_MORELINE; break; #endif default: break; } continue; } /* Escape character. */ if (vty->escape == VTY_ESCAPE) { vty_escape_map (buf[i], vty); continue; } if (vty->escape == VTY_LITERAL) { vty_self_insert (vty, buf[i]); vty->escape = VTY_NORMAL; 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('V'): vty->escape = VTY_LITERAL; 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->wfd, vty); vty_event (VTY_READ, vty_sock, vty); } return 0; } /* Flush buffer to the vty. */ static int vty_flush (struct thread *thread) { int erase; buffer_status_t flushrc; int vty_sock = THREAD_FD (thread); struct vty *vty = THREAD_ARG (thread); vty->t_write = NULL; /* Tempolary disable read thread. */ if ((vty->lines == 0) && vty->t_read) { thread_cancel (vty->t_read); vty->t_read = NULL; } /* Function execution continue. */ erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE)); /* N.B. if width is 0, that means we don't know the window size. */ if ((vty->lines == 0) || (vty->width == 0) || (vty->height == 0)) flushrc = buffer_flush_available(vty->obuf, vty_sock); else if (vty->status == VTY_MORELINE) flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width, 1, erase, 0); else flushrc = buffer_flush_window(vty->obuf, vty_sock, vty->width, vty->lines >= 0 ? vty->lines : vty->height, erase, 0); switch (flushrc) { case BUFFER_ERROR: vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ zlog_warn("buffer_flush failed on vty client fd %d, closing", vty->fd); buffer_reset(vty->obuf); vty_close(vty); return 0; case BUFFER_EMPTY: if (vty->status == VTY_CLOSE) vty_close (vty); else { vty->status = VTY_NORMAL; if (vty->lines == 0) vty_event (VTY_READ, vty_sock, vty); } break; case BUFFER_PENDING: /* There is more data waiting to be written. */ vty->status = VTY_MORE; if (vty->lines == 0) vty_event (VTY_WRITE, vty_sock, vty); break; } return 0; } /* allocate and initialise vty */ static struct vty * vty_new_init (int vty_sock) { struct vty *vty; vty = vty_new (); vty->fd = vty_sock; vty->wfd = vty_sock; vty->type = VTY_TERM; 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->lines = -1; vty->iac = 0; vty->iac_sb_in_progress = 0; vty->sb_len = 0; return vty; } /* Create new vty structure. */ static struct vty * vty_create (int vty_sock, union sockunion *su) { char buf[SU_ADDRSTRLEN]; struct vty *vty; sockunion2str(su, buf, SU_ADDRSTRLEN); /* Allocate new vty structure and set up default values. */ vty = vty_new_init (vty_sock); /* configurable parameters not part of basic init */ vty->v_timeout = vty_timeout_val; strcpy (vty->address, buf); if (no_password_check) { if (restricted_mode) vty->node = RESTRICTED_NODE; else if (host.advanced) vty->node = ENABLE_NODE; else vty->node = VIEW_NODE; } if (host.lines >= 0) vty->lines = host.lines; 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; } /* create vty for stdio */ static struct termios stdio_orig_termios; static struct vty *stdio_vty = NULL; static void (*stdio_vty_atclose)(void); static void vty_stdio_reset (void) { if (stdio_vty) { tcsetattr (0, TCSANOW, &stdio_orig_termios); stdio_vty = NULL; if (stdio_vty_atclose) stdio_vty_atclose (); stdio_vty_atclose = NULL; } } struct vty * vty_stdio (void (*atclose)()) { struct vty *vty; struct termios termios; /* refuse creating two vtys on stdio */ if (stdio_vty) return NULL; vty = stdio_vty = vty_new_init (0); stdio_vty_atclose = atclose; vty->wfd = 1; /* always have stdio vty in a known _unchangeable_ state, don't want config * to have any effect here to make sure scripting this works as intended */ vty->node = ENABLE_NODE; vty->v_timeout = 0; strcpy (vty->address, "console"); if (!tcgetattr (0, &stdio_orig_termios)) { termios = stdio_orig_termios; termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); termios.c_oflag &= ~OPOST; termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); termios.c_cflag &= ~(CSIZE | PARENB); termios.c_cflag |= CS8; tcsetattr (0, TCSANOW, &termios); } vty_prompt (vty); /* Add read/write thread. */ vty_event (VTY_WRITE, 1, vty); vty_event (VTY_READ, 0, vty); return vty; } /* Accept connection from the network. */ static int vty_accept (struct thread *thread) { int vty_sock; union sockunion su; int ret; unsigned int on; int accept_sock; struct prefix p; struct access_list *acl = NULL; char buf[SU_ADDRSTRLEN]; 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", safe_strerror (errno)); return -1; } set_nonblocking(vty_sock); sockunion2hostprefix (&su, &p); /* 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)) { zlog (NULL, LOG_INFO, "Vty connection refused from %s", sockunion2str (&su, buf, SU_ADDRSTRLEN)); close (vty_sock); /* continue accepting connections */ vty_event (VTY_SERV, accept_sock, NULL); 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)) { zlog (NULL, LOG_INFO, "Vty connection refused from %s", sockunion2str (&su, buf, SU_ADDRSTRLEN)); close (vty_sock); /* continue accepting connections */ vty_event (VTY_SERV, accept_sock, NULL); return 0; } } #endif /* HAVE_IPV6 */ 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", safe_strerror (errno)); zlog (NULL, LOG_INFO, "Vty connection from %s", sockunion2str (&su, buf, SU_ADDRSTRLEN)); vty_create (vty_sock, &su); return 0; } #ifdef HAVE_IPV6 static 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_v6only (ainfo->ai_family, sock); 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); } #else /* HAVE_IPV6 */ /* Make vty server socket. */ static void vty_serv_sock_family (const char* addr, unsigned short port, int family) { int ret; union sockunion su; int accept_sock; void* naddr=NULL; memset (&su, 0, sizeof (union sockunion)); su.sa.sa_family = family; if(addr) switch(family) { case AF_INET: naddr=&su.sin.sin_addr; break; #ifdef HAVE_IPV6 case AF_INET6: naddr=&su.sin6.sin6_addr; break; #endif } if(naddr) switch(inet_pton(family,addr,naddr)) { case -1: zlog_err("bad address %s",addr); naddr=NULL; break; case 0: zlog_err("error translating address %s: %s",addr,safe_strerror(errno)); naddr=NULL; } /* 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, naddr); if (ret < 0) { zlog_warn("can't bind socket"); 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); } #endif /* HAVE_IPV6 */ #ifdef VTYSH /* For sockaddr_un. */ #include /* VTY shell UNIX domain socket. */ static void vty_serv_un (const char *path) { int ret; int sock, len; struct sockaddr_un serv; mode_t old_mask; struct zprivs_ids_t ids; /* First of all, unlink existing socket */ unlink (path); /* Set umask */ old_mask = umask (0007); /* Make UNIX domain socket. */ sock = socket (AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { zlog_err("Cannot create unix stream socket: %s", safe_strerror(errno)); 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_STRUCT_SOCKADDR_UN_SUN_LEN len = serv.sun_len = SUN_LEN(&serv); #else len = sizeof (serv.sun_family) + strlen (serv.sun_path); #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ ret = bind (sock, (struct sockaddr *) &serv, len); if (ret < 0) { zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno)); close (sock); /* Avoid sd leak. */ return; } ret = listen (sock, 5); if (ret < 0) { zlog_err("listen(fd %d) failed: %s", sock, safe_strerror(errno)); close (sock); /* Avoid sd leak. */ return; } umask (old_mask); zprivs_get_ids(&ids); if (ids.gid_vty > 0) { /* set group of socket */ if ( chown (path, -1, ids.gid_vty) ) { zlog_err ("vty_serv_un: could chown socket, %s", safe_strerror (errno) ); } } 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, (socklen_t *) &client_len); if (sock < 0) { zlog_warn ("can't accept vty socket : %s", safe_strerror (errno)); return -1; } if (set_nonblocking(sock) < 0) { zlog_warn ("vtysh_accept: could not set vty socket %d to non-blocking," " %s, closing", sock, safe_strerror (errno)); close (sock); return -1; } #ifdef VTYSH_DEBUG printf ("VTY shell accept\n"); #endif /* VTYSH_DEBUG */ vty = vty_new (); vty->fd = sock; vty->wfd = sock; vty->type = VTY_SHELL_SERV; vty->node = VIEW_NODE; vty_event (VTYSH_READ, sock, vty); return 0; } static int vtysh_flush(struct vty *vty) { switch (buffer_flush_available(vty->obuf, vty->wfd)) { case BUFFER_PENDING: vty_event(VTYSH_WRITE, vty->wfd, vty); break; case BUFFER_ERROR: vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd); buffer_reset(vty->obuf); vty_close(vty); return -1; break; case BUFFER_EMPTY: break; } return 0; } static int vtysh_read (struct thread *thread) { int ret; int sock; int nbytes; struct vty *vty; unsigned char buf[VTY_READ_BUFSIZ]; unsigned char *p; u_char header[4] = {0, 0, 0, 0}; sock = THREAD_FD (thread); vty = THREAD_ARG (thread); vty->t_read = NULL; if ((nbytes = read (sock, buf, VTY_READ_BUFSIZ)) <= 0) { if (nbytes < 0) { if (ERRNO_IO_RETRY(errno)) { vty_event (VTYSH_READ, sock, vty); return 0; } vty->monitor = 0; /* disable monitoring to avoid infinite recursion */ zlog_warn("%s: read failed on vtysh client fd %d, closing: %s", __func__, sock, safe_strerror(errno)); } buffer_reset(vty->obuf); vty_close (vty); #ifdef VTYSH_DEBUG printf ("close vtysh\n"); #endif /* VTYSH_DEBUG */ return 0; } #ifdef VTYSH_DEBUG printf ("line: %.*s\n", nbytes, buf); #endif /* VTYSH_DEBUG */ if (vty->length + nbytes >= vty->max) { /* Clear command line buffer. */ vty->cp = vty->length = 0; vty_clear_buf (vty); vty_out (vty, "%% Command is too long.%s", VTY_NEWLINE); goto out; } for (p = buf; p < buf+nbytes; p++) { vty->buf[vty->length++] = *p; if (*p == '\0') { /* Pass this line to parser. */ ret = vty_execute (vty); /* Note that vty_execute clears the command buffer and resets vty->length to 0. */ /* Return result. */ #ifdef VTYSH_DEBUG printf ("result: %d\n", ret); printf ("vtysh node: %d\n", vty->node); #endif /* VTYSH_DEBUG */ header[3] = ret; buffer_put(vty->obuf, header, 4); if (!vty->t_write && (vtysh_flush(vty) < 0)) /* Try to flush results; exit if a write error occurs. */ return 0; } } out: vty_event (VTYSH_READ, sock, vty); return 0; } static int vtysh_write (struct thread *thread) { struct vty *vty = THREAD_ARG (thread); vty->t_write = NULL; vtysh_flush(vty); return 0; } #endif /* VTYSH */ /* Determine address family to bind. */ void vty_serv_sock (const char *addr, unsigned short port, const char *path) { /* If port is set to 0, do not listen on TCP/IP at all! */ if (port) { #ifdef HAVE_IPV6 vty_serv_sock_addrinfo (addr, port); #else /* ! HAVE_IPV6 */ vty_serv_sock_family (addr,port, AF_INET); #endif /* HAVE_IPV6 */ } #ifdef VTYSH vty_serv_un (path); #endif /* VTYSH */ } /* Close vty interface. Warning: call this only from functions that will be careful not to access the vty afterwards (since it has now been freed). This is safest from top-level functions (called directly by the thread dispatcher). */ 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); /* Flush buffer. */ buffer_flush_all (vty->obuf, vty->wfd); /* Free input buffer. */ buffer_free (vty->obuf); /* 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); else vty_stdio_reset (); /* Close output fd (except stdout/stderr) */ if (vty->wfd > 2) close (vty->wfd); 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; unsigned int line_num = 0; vty = vty_new (); vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */ if (vty->wfd < 0) { /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */ vty->wfd = STDOUT_FILENO; } vty->fd = STDIN_FILENO; vty->type = VTY_FILE; vty->node = CONFIG_NODE; /* Execute configuration file */ ret = config_from_file (vty, confp, &line_num); /* Flush any previous errors before printing messages below */ buffer_flush_all (vty->obuf, vty->fd); if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) { switch (ret) { case CMD_ERR_AMBIGUOUS: fprintf (stderr, "*** Error reading config: Ambiguous command.\n"); break; case CMD_ERR_NO_MATCH: fprintf (stderr, "*** Error reading config: There is no such command.\n"); break; } fprintf (stderr, "*** Error occurred processing line %u, below:\n%s\n", line_num, vty->buf); vty_close (vty); exit (1); } vty_close (vty); } static 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) { unlink (fullpath_tmp); free (fullpath_sav); free (fullpath_tmp); return NULL; } while((c = read (sav, buffer, 512)) > 0) write (tmp, buffer, c); close (sav); close (tmp); if (chmod(fullpath_tmp, CONFIGFILE_MASK) != 0) { unlink (fullpath_tmp); free (fullpath_sav); free (fullpath_tmp); return NULL; } if (link (fullpath_tmp, fullpath) == 0) ret = fopen (fullpath, "r"); unlink (fullpath_tmp); free (fullpath_sav); free (fullpath_tmp); return ret; } /* Read up configuration file from file_name. */ void vty_read_config (char *config_file, char *config_default_dir) { char cwd[MAXPATHLEN]; FILE *confp = NULL; char *fullpath; char *tmp = NULL; /* If -f flag specified. */ if (config_file != NULL) { if (! IS_DIRECTORY_SEP (config_file[0])) { getcwd (cwd, MAXPATHLEN); tmp = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (config_file) + 2); sprintf (tmp, "%s/%s", cwd, config_file); fullpath = tmp; } else fullpath = config_file; confp = fopen (fullpath, "r"); if (confp == NULL) { fprintf (stderr, "%s: failed to open configuration file %s: %s\n", __func__, fullpath, safe_strerror (errno)); 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 { #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) { fprintf (stderr, "%s: failed to open configuration file %s: %s\n", __func__, config_default_dir, safe_strerror (errno)); 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; } vty_read_file (confp); fclose (confp); host_config_set (fullpath); if (tmp) XFREE (MTYPE_TMP, fullpath); } /* Small utility function which output log to the VTY. */ void vty_log (const char *level, const char *proto_str, const char *format, struct timestamp_control *ctl, va_list va) { unsigned int i; struct vty *vty; if (!vtyvec) return; for (i = 0; i < vector_active (vtyvec); i++) if ((vty = vector_slot (vtyvec, i)) != NULL) if (vty->monitor) { va_list ac; va_copy(ac, va); vty_log_out (vty, level, proto_str, format, ctl, ac); va_end(ac); } } /* Async-signal-safe version of vty_log for fixed strings. */ void vty_log_fixed (char *buf, size_t len) { unsigned int i; struct iovec iov[2]; /* vty may not have been initialised */ if (!vtyvec) return; iov[0].iov_base = buf; iov[0].iov_len = len; iov[1].iov_base = (void *)"\r\n"; iov[1].iov_len = 2; for (i = 0; i < vector_active (vtyvec); i++) { struct vty *vty; if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor) /* N.B. We don't care about the return code, since process is most likely just about to die anyway. */ writev(vty->wfd, iov, 2); } } 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. */ static struct thread_master *vty_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 (vty_master, vty_accept, vty, sock); vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); break; #ifdef VTYSH case VTYSH_SERV: vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock); vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); break; case VTYSH_READ: vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock); break; case VTYSH_WRITE: vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock); break; #endif /* VTYSH */ case VTY_READ: vty->t_read = thread_add_read (vty_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 (vty_master, vty_timeout, vty, vty->v_timeout); } break; case VTY_WRITE: if (! vty->t_write) vty->t_write = thread_add_write (vty_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 (vty_master, vty_timeout, vty, vty->v_timeout); } break; } } DEFUN (who, who_cmd, "who", "Display who is on vty\n") { unsigned int i; struct vty *v; for (i = 0; i < vector_active (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. */ static int exec_timeout (struct vty *vty, const char *min_str, const 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; } /* initial mode. */ DEFUN (vty_restricted_mode, vty_restricted_mode_cmd, "anonymous restricted", "Restrict view commands available in anonymous, unauthenticated vty\n") { restricted_mode = 1; return CMD_SUCCESS; } DEFUN (vty_no_restricted_mode, vty_no_restricted_mode_cmd, "no anonymous restricted", NO_STR "Enable password checking\n") { restricted_mode = 0; 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; } ALIAS (terminal_no_monitor, no_terminal_monitor_cmd, "no terminal monitor", NO_STR "Set terminal line parameters\n" "Copy debug output to the current terminal line\n") 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; } /* vty login. */ DEFUN (log_commands, log_commands_cmd, "log commands", "Logging control\n" "Log all commands (can't be unset without restart)\n") { do_log_commands = 1; return CMD_SUCCESS; } /* Display current configuration. */ static 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); if (restricted_mode != restricted_mode_default) { if (restricted_mode_default) vty_out (vty, " no anonymous restricted%s", VTY_NEWLINE); else vty_out (vty, " anonymous restricted%s", VTY_NEWLINE); } if (do_log_commands) vty_out (vty, "log commands%s", VTY_NEWLINE); vty_out (vty, "!%s", VTY_NEWLINE); return CMD_SUCCESS; } struct cmd_node vty_node = { VTY_NODE, "%s(config-line)# ", 1, }; /* Reset all VTY status. */ void vty_reset () { unsigned int i; struct vty *vty; struct thread *vty_serv_thread; for (i = 0; i < vector_active (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_active (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; } } static void vty_save_cwd (void) { char cwd[MAXPATHLEN]; char *c; c = getcwd (cwd, MAXPATHLEN); if (!c) { chdir (SYSCONFDIR); getcwd (cwd, 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 (struct thread_master *master_thread) { /* For further configuration read, preserve current directory. */ vty_save_cwd (); vtyvec = vector_init (VECTOR_MIN_SIZE); vty_master = master_thread; atexit (vty_stdio_reset); /* 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 (RESTRICTED_NODE, &who_cmd); install_element (RESTRICTED_NODE, &show_history_cmd); install_element (VIEW_NODE, &who_cmd); install_element (VIEW_NODE, &show_history_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 (CONFIG_NODE, &log_commands_cmd); install_element (ENABLE_NODE, &terminal_monitor_cmd); install_element (ENABLE_NODE, &terminal_no_monitor_cmd); install_element (ENABLE_NODE, &no_terminal_monitor_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); install_element (VTY_NODE, &vty_restricted_mode_cmd); install_element (VTY_NODE, &vty_no_restricted_mode_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 */ } void vty_terminate (void) { if (vty_cwd) XFREE (MTYPE_TMP, vty_cwd); if (vtyvec && Vvty_serv_thread) { vty_reset (); vector_free (vtyvec); vector_free (Vvty_serv_thread); } } quagga-1.2.4/lib/vty.h000066400000000000000000000212621325323223500145270ustar00rootroot00000000000000/* 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 #include "thread.h" #include "log.h" #include "sockunion.h" #define VTY_MAXHIST 20 /* VTY struct. */ struct vty { /* File descripter of this vty. */ int fd; /* output FD, to support stdin/stdout combination */ int wfd; /* 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; /* 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} status; /* IAC handling: was the last character received the IAC (interpret-as-command) escape character (and therefore the next character will be the command code)? Refer to Telnet RFC 854. */ unsigned char iac; /* IAC SB (option subnegotiation) handling */ unsigned char iac_sb_in_progress; /* At the moment, we care only about the NAWS (window size) negotiation, and that requires just a 5-character buffer (RFC 1073): <16-bit width> <16-bit height> */ #define TELNET_NAWS_SB_LEN 5 unsigned char sb_buf[TELNET_NAWS_SB_LEN]; /* How many subnegotiation characters have we received? We just drop those that do not fit in the buffer. */ size_t sb_len; /* Window width/height. */ int width; int height; /* Configure lines. */ int lines; /* 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; /* What address is this vty comming from. */ char address[SU_ADDRSTRLEN]; }; /* Integrated configuration file. */ #define INTEGRATE_DEFAULT_CONFIG "Quagga.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 macros to convert VTY argument to unsigned long */ #define VTY_GET_ULONG(NAME,V,STR) \ do { \ char *endptr = NULL; \ errno = 0; \ (V) = strtoul ((STR), &endptr, 10); \ if (*(STR) == '-' || *endptr != '\0' || errno) \ { \ vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ return CMD_WARNING; \ } \ } while (0) /* * The logic below ((TMPL) <= ((MIN) && (TMPL) != (MIN)) is * done to circumvent the compiler complaining about * comparing unsigned numbers against zero, if MIN is zero. * NB: The compiler isn't smart enough to suprress the warning * if you write (MIN) != 0 && tmpl < (MIN). */ #define VTY_GET_INTEGER_RANGE_HEART(NAME,TMPL,STR,MIN,MAX) \ do { \ VTY_GET_ULONG(NAME, (TMPL), STR); \ if ( ((TMPL) <= (MIN) && (TMPL) != (MIN)) || (TMPL) > (MAX) ) \ { \ vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE);\ return CMD_WARNING; \ } \ } while (0) #define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX) \ do { \ unsigned long tmpl; \ VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX); \ (V) = tmpl; \ } while (0) #define VTY_CHECK_INTEGER_RANGE(NAME,STR,MIN,MAX) \ do { \ unsigned long tmpl; \ VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX); \ } while (0) #define VTY_GET_INTEGER(NAME,V,STR) \ VTY_GET_INTEGER_RANGE(NAME,V,STR,0U,UINT32_MAX) #define VTY_GET_IPV4_ADDRESS(NAME,V,STR) \ do { \ int retv; \ retv = inet_aton ((STR), &(V)); \ if (!retv) \ { \ vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ return CMD_WARNING; \ } \ } while (0) #define VTY_GET_IPV4_PREFIX(NAME,V,STR) \ do { \ int retv; \ retv = str2prefix_ipv4 ((STR), &(V)); \ if (retv <= 0) \ { \ vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \ return CMD_WARNING; \ } \ } while (0) #define VTY_WARN_EXPERIMENTAL() \ do { \ vty_out (vty, "%% WARNING: this command is experimental. Both its name and" \ " parameters may%s%% change in a future version of Quagga," \ " possibly breaking your configuration!%s", \ VTY_NEWLINE, VTY_NEWLINE); \ } while (0) /* Exported variables */ extern char integrate_default[]; /* Prototypes. */ extern void vty_init (struct thread_master *); extern void vty_init_vtysh (void); extern void vty_terminate (void); extern void vty_reset (void); extern struct vty *vty_new (void); extern struct vty *vty_stdio (void (*atclose)(void)); extern int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); extern void vty_read_config (char *, char *); extern void vty_time_print (struct vty *, int); extern void vty_serv_sock (const char *, unsigned short, const char *); extern void vty_close (struct vty *); extern char *vty_get_cwd (void); extern void vty_log (const char *level, const char *proto, const char *fmt, struct timestamp_control *, va_list); extern int vty_config_lock (struct vty *); extern int vty_config_unlock (struct vty *); extern int vty_shell (struct vty *); extern int vty_shell_serv (struct vty *); extern void vty_hello (struct vty *); /* Send a fixed-size message to all vty terminal monitors; this should be an async-signal-safe function. */ extern void vty_log_fixed (char *buf, size_t len); #endif /* _ZEBRA_VTY_H */ quagga-1.2.4/lib/workqueue.c000066400000000000000000000242621325323223500157320ustar00rootroot00000000000000/* * Quagga Work Queue Support. * * Copyright (C) 2005 Sun Microsystems, Inc. * * This file is part of GNU Zebra. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "workqueue.h" #include "linklist.h" #include "command.h" #include "log.h" /* master list of work_queues */ static struct list _work_queues; /* pointer primarily to avoid an otherwise harmless warning on * ALL_LIST_ELEMENTS_RO */ static struct list *work_queues = &_work_queues; #define WORK_QUEUE_MIN_GRANULARITY 1 static struct work_queue_item * work_queue_item_new (struct work_queue *wq) { struct work_queue_item *item; assert (wq); item = XCALLOC (MTYPE_WORK_QUEUE_ITEM, sizeof (struct work_queue_item)); return item; } static void work_queue_item_free (struct work_queue_item *item) { XFREE (MTYPE_WORK_QUEUE_ITEM, item); return; } /* create new work queue */ struct work_queue * work_queue_new (struct thread_master *m, const char *queue_name) { struct work_queue *new; new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct work_queue)); if (new == NULL) return new; new->name = XSTRDUP (MTYPE_WORK_QUEUE_NAME, queue_name); new->master = m; SET_FLAG (new->flags, WQ_UNPLUGGED); if ( (new->items = list_new ()) == NULL) { XFREE (MTYPE_WORK_QUEUE_NAME, new->name); XFREE (MTYPE_WORK_QUEUE, new); return NULL; } new->items->del = (void (*)(void *)) work_queue_item_free; listnode_add (work_queues, new); new->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY; new->cycles.worst = UINT_MAX; /* Default values, can be overriden by caller */ new->spec.hold = WORK_QUEUE_DEFAULT_HOLD; return new; } void work_queue_free (struct work_queue *wq) { if (wq->thread != NULL) thread_cancel(wq->thread); /* list_delete frees items via callback */ list_delete (wq->items); listnode_delete (work_queues, wq); XFREE (MTYPE_WORK_QUEUE_NAME, wq->name); XFREE (MTYPE_WORK_QUEUE, wq); return; } bool work_queue_is_scheduled (struct work_queue *wq) { return (wq->thread != NULL); } static int work_queue_schedule (struct work_queue *wq, unsigned int delay) { /* if appropriate, schedule work queue thread */ if ( CHECK_FLAG (wq->flags, WQ_UNPLUGGED) && (wq->thread == NULL) && (listcount (wq->items) > 0) ) { wq->thread = thread_add_background (wq->master, work_queue_run, wq, delay); return 1; } else return 0; } void work_queue_add (struct work_queue *wq, void *data) { struct work_queue_item *item; assert (wq); if (!(item = work_queue_item_new (wq))) { zlog_err ("%s: unable to get new queue item", __func__); return; } item->data = data; listnode_add (wq->items, item); work_queue_schedule (wq, wq->spec.hold); return; } static void work_queue_item_remove (struct work_queue *wq, struct listnode *ln) { struct work_queue_item *item = listgetdata (ln); assert (item && item->data); /* call private data deletion callback if needed */ if (wq->spec.del_item_data) wq->spec.del_item_data (wq, item->data); list_delete_node (wq->items, ln); work_queue_item_free (item); return; } static void work_queue_item_requeue (struct work_queue *wq, struct listnode *ln) { LISTNODE_DETACH (wq->items, ln); LISTNODE_ATTACH (wq->items, ln); /* attach to end of list */ } DEFUN(show_work_queues, show_work_queues_cmd, "show work-queues", SHOW_STR "Work Queue information\n") { struct listnode *node; struct work_queue *wq; vty_out (vty, "%c %8s %5s %8s %21s %6s %5s%s", ' ', "List","(ms) ","Q. Runs","Cycle Counts ", " ","Worst", VTY_NEWLINE); vty_out (vty, "%c %8s %5s %8s %7s %6s %6s %6s %5s %s%s", 'P', "Items", "Hold", "Total", "Best","Worst","Gran.","Avg.", "Lat.", "Name", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (work_queues, node, wq)) { vty_out (vty,"%c %8u %5u %8lu %7u %6u %6u %6u %5lu %s%s", (CHECK_FLAG (wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'), listcount (wq->items), wq->spec.hold, wq->runs, wq->cycles.best, MIN(wq->cycles.best, wq->cycles.worst), wq->cycles.granularity, (wq->runs) ? (unsigned int) (wq->cycles.total / wq->runs) : 0, wq->worst_usec, wq->name, VTY_NEWLINE); } return CMD_SUCCESS; } /* 'plug' a queue: Stop it from being scheduled, * ie: prevent the queue from draining. */ void work_queue_plug (struct work_queue *wq) { if (wq->thread) thread_cancel (wq->thread); wq->thread = NULL; UNSET_FLAG (wq->flags, WQ_UNPLUGGED); } /* unplug queue, schedule it again, if appropriate * Ie: Allow the queue to be drained again */ void work_queue_unplug (struct work_queue *wq) { SET_FLAG (wq->flags, WQ_UNPLUGGED); /* if thread isnt already waiting, add one */ work_queue_schedule (wq, wq->spec.hold); } /* timer thread to process a work queue * will reschedule itself if required, * otherwise work_queue_item_add */ int work_queue_run (struct thread *thread) { struct work_queue *wq; struct work_queue_item *item; unsigned long took; wq_item_status ret; unsigned int cycles = 0; struct listnode *node, *nnode; char yielded = 0; wq = THREAD_ARG (thread); wq->thread = NULL; assert (wq && wq->items); /* calculate cycle granularity: * list iteration == 1 cycle * granularity == # cycles between checks whether we should yield. * * granularity should be > 0, and can increase slowly after each run to * provide some hysteris, but not past cycles.best or 2*cycles. * * Best: starts low, can only increase * * Worst: starts at MAX, can only decrease. * * Granularity: starts at WORK_QUEUE_MIN_GRANULARITY, can be decreased * if we run to end of time slot, can increase otherwise * by a small factor. * * We could use just the average and save some work, however we want to be * able to adjust quickly to CPU pressure. Average wont shift much if * daemon has been running a long time. */ if (wq->cycles.granularity == 0) wq->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY; for (ALL_LIST_ELEMENTS (wq->items, node, nnode, item)) { assert (item && item->data); /* dont run items which are past their allowed retries */ if (item->ran > wq->spec.max_retries) { /* run error handler, if any */ if (wq->spec.errorfunc) wq->spec.errorfunc (wq, item->data); work_queue_item_remove (wq, node); continue; } /* run and take care of items that want to be retried immediately */ do { ret = wq->spec.workfunc (wq, item->data); item->ran++; } while ((ret == WQ_RETRY_NOW) && (item->ran < wq->spec.max_retries)); switch (ret) { case WQ_QUEUE_BLOCKED: { /* decrement item->ran again, cause this isn't an item * specific error, and fall through to WQ_RETRY_LATER */ item->ran--; } case WQ_RETRY_LATER: { goto stats; } case WQ_REQUEUE: { item->ran--; work_queue_item_requeue (wq, node); break; } case WQ_RETRY_NOW: /* a RETRY_NOW that gets here has exceeded max_tries, same as ERROR */ case WQ_ERROR: { if (wq->spec.errorfunc) wq->spec.errorfunc (wq, item); } /* fall through here is deliberate */ case WQ_SUCCESS: default: { work_queue_item_remove (wq, node); break; } } /* completed cycle */ cycles++; /* test if we should yield */ if ( !(cycles % wq->cycles.granularity) && (took = thread_should_yield (thread))) { yielded = 1; goto stats; } } stats: #define WQ_HYSTERESIS_FACTOR 4 if (cycles > wq->cycles.best) wq->cycles.best = cycles; if (took > wq->worst_usec) wq->worst_usec = took; /* we yielded, check whether granularity should be reduced */ if (yielded && (cycles < wq->cycles.granularity)) { wq->cycles.granularity = ((cycles > 0) ? cycles : WORK_QUEUE_MIN_GRANULARITY); if (cycles < wq->cycles.worst) wq->cycles.worst = cycles; } /* otherwise, should granularity increase? */ else if (cycles >= (wq->cycles.granularity)) { /* along with yielded check, provides hysteresis for granularity */ if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR * WQ_HYSTERESIS_FACTOR)) wq->cycles.granularity *= WQ_HYSTERESIS_FACTOR; /* quick ramp-up */ else if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR)) wq->cycles.granularity += WQ_HYSTERESIS_FACTOR; /* clamp granularity down to the worst yielded cycle count */ wq->cycles.granularity = MIN(wq->cycles.granularity, wq->cycles.worst); } #undef WQ_HYSTERIS_FACTOR wq->runs++; wq->cycles.total += cycles; #if 0 printf ("%s: cycles %d, new: best %d, worst %d\n", __func__, cycles, wq->cycles.best, wq->cycles.granularity); #endif /* Is the queue done yet? If it is, call the completion callback. */ if (listcount (wq->items) > 0) work_queue_schedule (wq, 0); else if (wq->spec.completion_func) wq->spec.completion_func (wq); return 0; } quagga-1.2.4/lib/workqueue.h000066400000000000000000000104441325323223500157340ustar00rootroot00000000000000/* * Quagga Work Queues. * * Copyright (C) 2005 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_WORK_QUEUE_H #define _QUAGGA_WORK_QUEUE_H /* Hold time for the initial schedule of a queue run, in millisec */ #define WORK_QUEUE_DEFAULT_HOLD 50 /* action value, for use by item processor and item error handlers */ typedef enum { WQ_SUCCESS = 0, WQ_ERROR, /* Error, run error handler if provided */ WQ_RETRY_NOW, /* retry immediately */ WQ_RETRY_LATER, /* retry later, cease processing work queue */ WQ_REQUEUE, /* requeue item, continue processing work queue */ WQ_QUEUE_BLOCKED, /* Queue cant be processed at this time. * Similar to WQ_RETRY_LATER, but doesn't penalise * the particular item.. */ } wq_item_status; /* A single work queue item, unsurprisingly */ struct work_queue_item { void *data; /* opaque data */ unsigned short ran; /* # of times item has been run */ }; #define WQ_UNPLUGGED (1 << 0) /* available for draining */ struct work_queue { /* Everything but the specification struct is private * the following may be read */ struct thread_master *master; /* thread master */ struct thread *thread; /* thread, if one is active */ char *name; /* work queue name */ /* Specification for this work queue. * Public, must be set before use by caller. May be modified at will. */ struct { /* optional opaque user data, global to the queue. */ void *data; /* work function to process items with: * First argument is the workqueue queue. * Second argument is the item data */ wq_item_status (*workfunc) (struct work_queue *, void *); /* error handling function, optional */ void (*errorfunc) (struct work_queue *, struct work_queue_item *); /* callback to delete user specific item data */ void (*del_item_data) (struct work_queue *, void *); /* completion callback, called when queue is emptied, optional */ void (*completion_func) (struct work_queue *); /* max number of retries to make for item that errors */ unsigned int max_retries; unsigned int hold; /* hold time for first run, in ms */ } spec; /* remaining fields should be opaque to users */ struct list *items; /* queue item list */ unsigned long runs; /* runs count */ unsigned long worst_usec; struct { unsigned int best; unsigned int worst; unsigned int granularity; unsigned long total; } cycles; /* cycle counts */ /* private state */ u_int16_t flags; /* user set flag */ }; /* User API */ /* create a new work queue, of given name. * user must fill in the spec of the returned work queue before adding * anything to it */ extern struct work_queue *work_queue_new (struct thread_master *, const char *); /* destroy work queue */ extern void work_queue_free (struct work_queue *); /* Add the supplied data as an item onto the workqueue */ extern void work_queue_add (struct work_queue *, void *); /* plug the queue, ie prevent it from being drained / processed */ extern void work_queue_plug (struct work_queue *wq); /* unplug the queue, allow it to be drained again */ extern void work_queue_unplug (struct work_queue *wq); bool work_queue_is_scheduled (struct work_queue *); /* Helpers, exported for thread.c and command.c */ extern int work_queue_run (struct thread *); extern struct cmd_element show_work_queues_cmd; #endif /* _QUAGGA_WORK_QUEUE_H */ quagga-1.2.4/lib/zassert.h000066400000000000000000000026311325323223500153770ustar00rootroot00000000000000/* * $Id: zassert.h,v 1.2 2004/12/03 18:01:04 ajs Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_ASSERT_H #define _QUAGGA_ASSERT_H extern void _zlog_assert_failed (const char *assertion, const char *file, unsigned int line, const char *function) __attribute__ ((noreturn)); #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #define __ASSERT_FUNCTION __func__ #elif defined(__GNUC__) #define __ASSERT_FUNCTION __FUNCTION__ #else #define __ASSERT_FUNCTION NULL #endif #define zassert(EX) ((void)((EX) ? 0 : \ (_zlog_assert_failed(#EX, __FILE__, __LINE__, \ __ASSERT_FUNCTION), 0))) #undef assert #define assert(EX) zassert(EX) #endif /* _QUAGGA_ASSERT_H */ quagga-1.2.4/lib/zclient.c000066400000000000000000001070121325323223500153460ustar00rootroot00000000000000/* Zebra's client library. * Copyright (C) 1999 Kunihiro Ishiguro * Copyright (C) 2005 Andrew J. Schorr * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "buffer.h" #include "network.h" #include "if.h" #include "log.h" #include "thread.h" #include "zclient.h" #include "memory.h" #include "table.h" /* Zebra client events. */ enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; /* Prototype for event manager. */ static void zclient_event (enum event, struct zclient *); const char *zclient_serv_path = NULL; /* This file local debug flag. */ int zclient_debug = 0; /* Allocate zclient structure. */ struct zclient * zclient_new (struct thread_master *master) { struct zclient *zclient; zclient = XCALLOC (MTYPE_ZCLIENT, sizeof (struct zclient)); zclient->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); zclient->wb = buffer_new(0); zclient->master = master; return zclient; } /* This function is only called when exiting, because many parts of the code do not check for I/O errors, so they could reference an invalid pointer if the structure was ever freed. Free zclient structure. */ void zclient_free (struct zclient *zclient) { if (zclient->ibuf) stream_free(zclient->ibuf); if (zclient->obuf) stream_free(zclient->obuf); if (zclient->wb) buffer_free(zclient->wb); 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] = vrf_bitmap_init (); /* Set unwanted redistribute route. bgpd does not need BGP route redistribution. */ zclient->redist_default = redist_default; /* Set default-information redistribute to zero. */ zclient->default_information = vrf_bitmap_init (); /* Schedule first zclient connection. */ if (zclient_debug) zlog_debug ("zclient start scheduled"); zclient_event (ZCLIENT_SCHEDULE, zclient); } /* Stop zebra client services. */ void zclient_stop (struct zclient *zclient) { int i; if (zclient_debug) zlog_debug ("zclient stopped"); /* Stop threads. */ THREAD_OFF(zclient->t_read); THREAD_OFF(zclient->t_connect); THREAD_OFF(zclient->t_write); /* Reset streams. */ stream_reset(zclient->ibuf); stream_reset(zclient->obuf); /* Empty the write buffer. */ buffer_reset(zclient->wb); /* Close socket. */ if (zclient->sock >= 0) { close (zclient->sock); zclient->sock = -1; } zclient->fail = 0; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { vrf_bitmap_free(zclient->redist[i]); zclient->redist[i] = VRF_BITMAP_NULL; } vrf_bitmap_free(zclient->default_information); zclient->default_information = VRF_BITMAP_NULL; } void zclient_reset (struct zclient *zclient) { zclient_stop (zclient); zclient_init (zclient, zclient->redist_default); } #ifdef HAVE_TCP_ZEBRA /* Make socket to zebra daemon. Return zebra socket. */ static int zclient_socket(void) { 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_STRUCT_SOCKADDR_IN_SIN_LEN serv.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); /* Connect to zebra. */ ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv)); if (ret < 0) { zlog_warn ("%s connect failure: %d", __PRETTY_FUNCTION__, errno); close (sock); return -1; } return sock; } #else /* For sockaddr_un. */ #include static int zclient_socket_un (const 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_STRUCT_SOCKADDR_UN_SUN_LEN len = addr.sun_len = SUN_LEN(&addr); #else len = sizeof (addr.sun_family) + strlen (addr.sun_path); #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ ret = connect (sock, (struct sockaddr *) &addr, len); if (ret < 0) { zlog_warn ("%s connect failure: %d", __PRETTY_FUNCTION__, errno); close (sock); return -1; } return sock; } #endif /* HAVE_TCP_ZEBRA */ /** * Connect to zebra daemon. * @param zclient a pointer to zclient structure * @return socket fd just to make sure that connection established * @see zclient_init * @see zclient_new */ int zclient_socket_connect (struct zclient *zclient) { #ifdef HAVE_TCP_ZEBRA zclient->sock = zclient_socket (); #else zclient->sock = zclient_socket_un (zclient_serv_path_get()); #endif return zclient->sock; } static int zclient_failed(struct zclient *zclient) { zclient->fail++; zclient_stop(zclient); zclient_event(ZCLIENT_CONNECT, zclient); return -1; } static int zclient_flush_data(struct thread *thread) { struct zclient *zclient = THREAD_ARG(thread); zclient->t_write = NULL; if (zclient->sock < 0) return -1; switch (buffer_flush_available(zclient->wb, zclient->sock)) { case BUFFER_ERROR: zlog_warn("%s: buffer_flush_available failed on zclient fd %d, closing", __func__, zclient->sock); return zclient_failed(zclient); break; case BUFFER_PENDING: zclient->t_write = thread_add_write (zclient->master, zclient_flush_data, zclient, zclient->sock); break; case BUFFER_EMPTY: break; } return 0; } int zclient_send_message(struct zclient *zclient) { if (zclient->sock < 0) return -1; switch (buffer_write(zclient->wb, zclient->sock, STREAM_DATA(zclient->obuf), stream_get_endp(zclient->obuf))) { case BUFFER_ERROR: zlog_warn("%s: buffer_write failed to zclient fd %d, closing", __func__, zclient->sock); return zclient_failed(zclient); break; case BUFFER_EMPTY: THREAD_OFF(zclient->t_write); break; case BUFFER_PENDING: THREAD_WRITE_ON (zclient->master, zclient->t_write, zclient_flush_data, zclient, zclient->sock); break; } return 0; } void zclient_create_header (struct stream *s, uint16_t command, vrf_id_t vrf_id) { /* length placeholder, caller can update */ stream_putw (s, ZEBRA_HEADER_SIZE); stream_putc (s, ZEBRA_HEADER_MARKER); stream_putc (s, ZSERV_VERSION); stream_putw (s, vrf_id); stream_putw (s, command); } int zclient_read_header (struct stream *s, int sock, u_int16_t *size, u_char *marker, u_char *version, u_int16_t *vrf_id, u_int16_t *cmd) { if (stream_read (s, sock, ZEBRA_HEADER_SIZE) != ZEBRA_HEADER_SIZE) return -1; *size = stream_getw (s) - ZEBRA_HEADER_SIZE; *marker = stream_getc (s); *version = stream_getc (s); *vrf_id = stream_getw (s); *cmd = stream_getw (s); if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, sock, *marker, *version); return -1; } if (*size && stream_read (s, sock, *size) != *size) return -1; return 0; } /* Send simple Zebra message. */ static int zebra_message_send (struct zclient *zclient, int command, vrf_id_t vrf_id) { struct stream *s; /* Get zclient output buffer. */ s = zclient->obuf; stream_reset (s); /* Send very simple command only Zebra message. */ zclient_create_header (s, command, vrf_id); return zclient_send_message(zclient); } static int zebra_hello_send (struct zclient *zclient) { struct stream *s; if (zclient->redist_default) { s = zclient->obuf; stream_reset (s); /* The VRF ID in the HELLO message is always 0. */ zclient_create_header (s, ZEBRA_HELLO, VRF_DEFAULT); stream_putc (s, zclient->redist_default); stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); } return 0; } /* Send requests to zebra daemon for the information in a VRF. */ void zclient_send_requests (struct zclient *zclient, vrf_id_t vrf_id) { int i; /* zclient is disabled. */ if (! zclient->enable) return; /* If not connected to the zebra yet. */ if (zclient->sock < 0) return; if (zclient_debug) zlog_debug ("%s: send messages for VRF %u", __func__, vrf_id); /* We need router-id information. */ zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD, vrf_id); /* We need interface information. */ zebra_message_send (zclient, ZEBRA_INTERFACE_ADD, vrf_id); /* Set unwanted redistribute route. */ vrf_bitmap_set (zclient->redist[zclient->redist_default], vrf_id); /* Flush all redistribute request. */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && vrf_bitmap_check (zclient->redist[i], vrf_id)) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, i, vrf_id); /* If default information is needed. */ if (vrf_bitmap_check (zclient->default_information, VRF_DEFAULT)) zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD, vrf_id); } /* Make connection to zebra daemon. */ int zclient_start (struct zclient *zclient) { if (zclient_debug) zlog_debug ("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; /* * If we fail to connect to the socket on initialization, * Let's wait a second and see if we can reconnect. * Cause if we don't connect, we never attempt to * reconnect. On startup if zebra is slow we * can get into this situation. */ while (zclient_socket_connect(zclient) < 0 && zclient->fail < 5) { if (zclient_debug) zlog_debug ("zclient connection fail"); zclient->fail++; sleep (1); } if (zclient->sock < 0) { zclient_event (ZCLIENT_CONNECT, zclient); return -1; } if (set_nonblocking(zclient->sock) < 0) zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock); /* Clear fail count. */ zclient->fail = 0; if (zclient_debug) zlog_debug ("zclient connect success with socket [%d]", zclient->sock); /* Create read thread. */ zclient_event (ZCLIENT_READ, zclient); zebra_hello_send (zclient); /* Inform the successful connection. */ if (zclient->zebra_connected) (*zclient->zebra_connected) (zclient); return 0; } /* This function is a wrapper function for calling zclient_start from timer or event thread. */ static int zclient_connect (struct thread *t) { struct zclient *zclient; zclient = THREAD_ARG (t); zclient->t_connect = NULL; if (zclient_debug) zlog_debug ("zclient_connect is called"); return zclient_start (zclient); } /* * "xdr_encode"-like interface that allows daemon (client) to send * a message to zebra server for a route that needs to be * added/deleted to the kernel. Info about the route is specified * by the caller in a struct zapi_ipv4. zapi_ipv4_read() then writes * the info down the zclient socket using the stream_* functions. * * The corresponding read ("xdr_decode") function on the server * side is zread_ipv4_add()/zread_ipv4_delete(). * * 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Length (2) | Command | Route Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ZEBRA Flags | Message Flags | Prefix length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Destination IPv4 Prefix for route | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Nexthop count | * +-+-+-+-+-+-+-+-+ * * * A number of IPv4 nexthop(s) or nexthop interface index(es) are then * described, as per the Nexthop count. Each nexthop described as: * * +-+-+-+-+-+-+-+-+ * | Nexthop Type | Set to one of ZEBRA_NEXTHOP_* * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | IPv4 Nexthop address or Interface Index number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Alternatively, if the flags field has ZEBRA_FLAG_BLACKHOLE or * ZEBRA_FLAG_REJECT is set then Nexthop count is set to 1, then _no_ * nexthop information is provided, and the message describes a prefix * to blackhole or reject route. * * If ZAPI_MESSAGE_DISTANCE is set, the distance value is written as a 1 * byte value. * * If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8 * byte value. * * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 4 byte value * * XXX: No attention paid to alignment. */ int zapi_ipv4_route (u_char cmd, 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); zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ stream_putc (s, api->type); stream_putc (s, api->flags); stream_putc (s, api->message); stream_putw (s, api->safi); /* 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); /* XXX assert(api->nexthop_num == 0); */ /* XXX assert(api->ifindex_num == 0); */ } 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); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) stream_putl (s, api->mtu); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) stream_putl (s, api->tag); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); } #ifdef HAVE_IPV6 int zapi_ipv6_route (u_char cmd, 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); zclient_create_header (s, cmd, api->vrf_id); /* Put type and nexthop. */ stream_putc (s, api->type); stream_putc (s, api->flags); stream_putc (s, api->message); stream_putw (s, api->safi); /* 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); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_MTU)) stream_putl (s, api->mtu); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG)) stream_putl (s, api->tag); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); } #endif /* HAVE_IPV6 */ /* * send a ZEBRA_REDISTRIBUTE_ADD or ZEBRA_REDISTRIBUTE_DELETE * for the route type (ZEBRA_ROUTE_KERNEL etc.). The zebra server will * then set/unset redist[type] in the client handle (a struct zserv) for the * sending client */ int zebra_redistribute_send (int command, struct zclient *zclient, int type, vrf_id_t vrf_id) { struct stream *s; s = zclient->obuf; stream_reset(s); zclient_create_header (s, command, vrf_id); stream_putc (s, type); stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); } /* Get prefix in ZServ format; family should be filled in on prefix */ static void zclient_stream_get_prefix (struct stream *s, struct prefix *p) { size_t plen = prefix_blen (p); u_char c; p->prefixlen = 0; if (plen == 0) return; stream_get (&p->u.prefix, s, plen); c = stream_getc(s); p->prefixlen = MIN(plen * 8, c); } /* Router-id update from zebra daemon. */ void zebra_router_id_update_read (struct stream *s, struct prefix *rid) { /* Fetch interface address. */ rid->family = stream_getc (s); zclient_stream_get_prefix (s, rid); } /* Interface addition from zebra daemon. */ /* * The format of the message sent with type ZEBRA_INTERFACE_ADD or * ZEBRA_INTERFACE_DELETE from zebra to the client is: * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifname | * | | * | | * | | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifindex | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | status | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | if_flags | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | metric | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifmtu | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifmtu6 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | bandwidth | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Link Layer Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Harware Address Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Hardware Address if HW lenght different from 0 | * | ... max INTERFACE_HWADDR_MAX | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Link_params? | Whether a link-params follows: 1 or 0. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Link_params 0 or 1 INTERFACE_LINK_PARAMS_SIZE sized | * | .... (struct if_link_params). | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ struct interface * zebra_interface_add_read (struct stream *s, vrf_id_t vrf_id) { struct interface *ifp; char ifname_tmp[INTERFACE_NAMSIZ]; /* Read interface name. */ stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); /* Lookup/create interface by name. */ ifp = if_get_by_name_len_vrf (ifname_tmp, strnlen (ifname_tmp, INTERFACE_NAMSIZ), vrf_id); zebra_interface_if_set_value (s, ifp); return ifp; } /* * Read interface up/down msg (ZEBRA_INTERFACE_UP/ZEBRA_INTERFACE_DOWN) * from zebra server. The format of this message is the same as * that sent for ZEBRA_INTERFACE_ADD/ZEBRA_INTERFACE_DELETE (see * comments for zebra_interface_add_read), except that no sockaddr_dl * is sent at the tail of the message. */ struct interface * zebra_interface_state_read (struct stream *s, vrf_id_t vrf_id) { struct interface *ifp; 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_len_vrf (ifname_tmp, strnlen (ifname_tmp, INTERFACE_NAMSIZ), vrf_id); /* If such interface does not exist, indicate an error */ if (! ifp) return NULL; zebra_interface_if_set_value (s, ifp); return ifp; } static void link_params_set_value(struct stream *s, struct if_link_params *iflp) { if (iflp == NULL) return; iflp->lp_status = stream_getl (s); iflp->te_metric = stream_getl (s); iflp->max_bw = stream_getf (s); iflp->max_rsv_bw = stream_getf (s); uint32_t bwclassnum = stream_getl (s); { unsigned int i; for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++) iflp->unrsv_bw[i] = stream_getf (s); if (i < bwclassnum) zlog_err ("%s: received %d > %d (MAX_CLASS_TYPE) bw entries" " - outdated library?", __func__, bwclassnum, MAX_CLASS_TYPE); } iflp->admin_grp = stream_getl (s); iflp->rmt_as = stream_getl (s); iflp->rmt_ip.s_addr = stream_get_ipv4 (s); iflp->av_delay = stream_getl (s); iflp->min_delay = stream_getl (s); iflp->max_delay = stream_getl (s); iflp->delay_var = stream_getl (s); iflp->pkt_loss = stream_getf (s); iflp->res_bw = stream_getf (s); iflp->ava_bw = stream_getf (s); iflp->use_bw = stream_getf (s); } struct interface * zebra_interface_link_params_read (struct stream *s) { struct if_link_params *iflp; uint32_t ifindex = stream_getl (s); struct interface *ifp = if_lookup_by_index (ifindex); if (ifp == NULL || s == NULL) { zlog_err ("%s: unknown ifindex %u, shouldn't happen", __func__, ifindex); return NULL; } if ((iflp = if_link_params_get (ifp)) == NULL) return NULL; link_params_set_value(s, iflp); return ifp; } void zebra_interface_if_set_value (struct stream *s, struct interface *ifp) { u_char link_params_status = 0; /* Read interface's index. */ ifp->ifindex = stream_getl (s); ifp->status = stream_getc (s); /* Read interface's value. */ ifp->flags = stream_getq (s); ifp->metric = stream_getl (s); ifp->mtu = stream_getl (s); ifp->mtu6 = stream_getl (s); ifp->bandwidth = stream_getl (s); ifp->ll_type = stream_getl (s); ifp->hw_addr_len = stream_getl (s); if (ifp->hw_addr_len) stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX)); /* Read Traffic Engineering status */ link_params_status = stream_getc (s); /* Then, Traffic Engineering parameters if any */ if (link_params_status) { struct if_link_params *iflp = if_link_params_get (ifp); link_params_set_value(s, iflp); } } size_t zebra_interface_link_params_write (struct stream *s, struct interface *ifp) { size_t w; struct if_link_params *iflp; int i; if (s == NULL || ifp == NULL || ifp->link_params == NULL) return 0; iflp = ifp->link_params; w = 0; w += stream_putl (s, iflp->lp_status); w += stream_putl (s, iflp->te_metric); w += stream_putf (s, iflp->max_bw); w += stream_putf (s, iflp->max_rsv_bw); w += stream_putl (s, MAX_CLASS_TYPE); for (i = 0; i < MAX_CLASS_TYPE; i++) w += stream_putf (s, iflp->unrsv_bw[i]); w += stream_putl (s, iflp->admin_grp); w += stream_putl (s, iflp->rmt_as); w += stream_put_in_addr (s, &iflp->rmt_ip); w += stream_putl (s, iflp->av_delay); w += stream_putl (s, iflp->min_delay); w += stream_putl (s, iflp->max_delay); w += stream_putl (s, iflp->delay_var); w += stream_putf (s, iflp->pkt_loss); w += stream_putf (s, iflp->res_bw); w += stream_putf (s, iflp->ava_bw); w += stream_putf (s, iflp->use_bw); return w; } /* * format of message for address additon is: * 0 * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * | type | ZEBRA_INTERFACE_ADDRESS_ADD or * +-+-+-+-+-+-+-+-+ ZEBRA_INTERFACE_ADDRES_DELETE * | | * + + * | ifindex | * + + * | | * + + * | | * +-+-+-+-+-+-+-+-+ * | ifc_flags | flags for connected address * +-+-+-+-+-+-+-+-+ * | addr_family | * +-+-+-+-+-+-+-+-+ * | addr... | * : : * | | * +-+-+-+-+-+-+-+-+ * | addr_len | len of addr. E.g., addr_len = 4 for ipv4 addrs. * +-+-+-+-+-+-+-+-+ * | daddr.. | * : : * | | * +-+-+-+-+-+-+-+-+ */ static int memconstant(const void *s, int c, size_t n) { const u_char *p = s; while (n-- > 0) if (*p++ != c) return 0; return 1; } struct connected * zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id) { ifindex_t ifindex; struct interface *ifp; struct connected *ifc; struct prefix p, d, *dp; int plen; u_char ifc_flags; memset (&p, 0, sizeof(p)); memset (&d, 0, sizeof(d)); /* Get interface index. */ ifindex = stream_getl (s); /* Lookup index. */ ifp = if_lookup_by_index_vrf (ifindex, vrf_id); if (ifp == NULL) { zlog_warn ("zebra_interface_address_read(%s): " "Can't find interface by ifindex: %d ", (type == ZEBRA_INTERFACE_ADDRESS_ADD? "ADD" : "DELETE"), ifindex); return NULL; } /* Fetch flag. */ ifc_flags = stream_getc (s); /* Fetch interface address. */ d.family = p.family = stream_getc (s); plen = prefix_blen (&d); zclient_stream_get_prefix (s, &p); /* Fetch destination address. */ stream_get (&d.u.prefix, s, plen); /* N.B. NULL destination pointers are encoded as all zeroes */ dp = memconstant(&d.u.prefix,0,plen) ? NULL : &d; if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { /* N.B. NULL destination pointers are encoded as all zeroes */ ifc = connected_add_by_prefix(ifp, &p, dp); if (ifc != NULL) { ifc->flags = ifc_flags; if (ifc->destination) ifc->destination->prefixlen = ifc->address->prefixlen; else if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { /* carp interfaces on OpenBSD with 0.0.0.0/0 as "peer" */ char buf[PREFIX_STRLEN]; zlog_warn("warning: interface %s address %s " "with peer flag set, but no peer address!", ifp->name, prefix2str (ifc->address, buf, sizeof buf)); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } } } else { assert (type == ZEBRA_INTERFACE_ADDRESS_DELETE); ifc = connected_delete_by_prefix(ifp, &p); } return ifc; } /* Zebra client message read function. */ static int zclient_read (struct thread *thread) { size_t already; uint16_t length, command; uint8_t marker, version; vrf_id_t vrf_id; struct zclient *zclient; /* Get socket to zebra. */ zclient = THREAD_ARG (thread); zclient->t_read = NULL; /* Read zebra header (if we don't have it already). */ if ((already = stream_get_endp(zclient->ibuf)) < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, ZEBRA_HEADER_SIZE-already)) == 0) || (nbyte == -1)) { if (zclient_debug) zlog_debug ("zclient connection closed socket [%d].", zclient->sock); return zclient_failed(zclient); } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already)) { /* Try again later. */ zclient_event (ZCLIENT_READ, zclient); return 0; } already = ZEBRA_HEADER_SIZE; } /* Reset to read from the beginning of the incoming packet. */ stream_set_getp(zclient->ibuf, 0); /* Fetch header values. */ length = stream_getw (zclient->ibuf); marker = stream_getc (zclient->ibuf); version = stream_getc (zclient->ibuf); vrf_id = stream_getw (zclient->ibuf); command = stream_getw (zclient->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zclient->sock, marker, version); return zclient_failed(zclient); } if (length < ZEBRA_HEADER_SIZE) { zlog_err("%s: socket %d message length %u is less than %d ", __func__, zclient->sock, length, ZEBRA_HEADER_SIZE); return zclient_failed(zclient); } /* Length check. */ if (length > STREAM_SIZE(zclient->ibuf)) { struct stream *ns; zlog_warn("%s: message size %u exceeds buffer size %lu, expanding...", __func__, length, (u_long)STREAM_SIZE(zclient->ibuf)); ns = stream_new(length); stream_copy(ns, zclient->ibuf); stream_free (zclient->ibuf); zclient->ibuf = ns; } /* Read rest of zebra packet. */ if (already < length) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, length-already)) == 0) || (nbyte == -1)) { if (zclient_debug) zlog_debug("zclient connection closed socket [%d].", zclient->sock); return zclient_failed(zclient); } if (nbyte != (ssize_t)(length-already)) { /* Try again later. */ zclient_event (ZCLIENT_READ, zclient); return 0; } } length -= ZEBRA_HEADER_SIZE; if (zclient_debug) zlog_debug("zclient 0x%p command 0x%x VRF %u\n", (void *)zclient, command, vrf_id); switch (command) { case ZEBRA_ROUTER_ID_UPDATE: if (zclient->router_id_update) (*zclient->router_id_update) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_ADD: if (zclient->interface_add) (*zclient->interface_add) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_DELETE: if (zclient->interface_delete) (*zclient->interface_delete) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) (*zclient->interface_address_add) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_ADDRESS_DELETE: if (zclient->interface_address_delete) (*zclient->interface_address_delete) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_UP: if (zclient->interface_up) (*zclient->interface_up) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_DOWN: if (zclient->interface_down) (*zclient->interface_down) (command, zclient, length, vrf_id); break; case ZEBRA_IPV4_ROUTE_ADD: if (zclient->ipv4_route_add) (*zclient->ipv4_route_add) (command, zclient, length, vrf_id); break; case ZEBRA_IPV4_ROUTE_DELETE: if (zclient->ipv4_route_delete) (*zclient->ipv4_route_delete) (command, zclient, length, vrf_id); break; case ZEBRA_IPV6_ROUTE_ADD: if (zclient->ipv6_route_add) (*zclient->ipv6_route_add) (command, zclient, length, vrf_id); break; case ZEBRA_IPV6_ROUTE_DELETE: if (zclient->ipv6_route_delete) (*zclient->ipv6_route_delete) (command, zclient, length, vrf_id); break; case ZEBRA_INTERFACE_LINK_PARAMS: if (zclient->interface_link_params) (*zclient->interface_link_params) (command, zclient, length); case ZEBRA_NEXTHOP_UPDATE: if (zclient->nexthop_update) (*zclient->nexthop_update) (command, zclient, length, vrf_id); break; default: break; } if (zclient->sock < 0) /* Connection was closed during packet processing. */ return -1; /* Register read thread. */ stream_reset(zclient->ibuf); zclient_event (ZCLIENT_READ, zclient); return 0; } void zclient_redistribute (int command, struct zclient *zclient, int type, vrf_id_t vrf_id) { if (command == ZEBRA_REDISTRIBUTE_ADD) { if (vrf_bitmap_check (zclient->redist[type], vrf_id)) return; vrf_bitmap_set (zclient->redist[type], vrf_id); } else { if (!vrf_bitmap_check (zclient->redist[type], vrf_id)) return; vrf_bitmap_unset (zclient->redist[type], vrf_id); } if (zclient->sock > 0) zebra_redistribute_send (command, zclient, type, vrf_id); } void zclient_redistribute_default (int command, struct zclient *zclient, vrf_id_t vrf_id) { if (command == ZEBRA_REDISTRIBUTE_DEFAULT_ADD) { if (vrf_bitmap_check (zclient->default_information, vrf_id)) return; vrf_bitmap_set (zclient->default_information, vrf_id); } else { if (!vrf_bitmap_check (zclient->default_information, vrf_id)) return; vrf_bitmap_unset (zclient->default_information, vrf_id); } if (zclient->sock > 0) zebra_message_send (zclient, command, vrf_id); } 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 (zclient->master, zclient_connect, zclient, 0); break; case ZCLIENT_CONNECT: if (zclient->fail >= 10) return; if (zclient_debug) zlog_debug ("zclient connect schedule interval is %d", zclient->fail < 3 ? 10 : 60); if (! zclient->t_connect) zclient->t_connect = thread_add_timer (zclient->master, zclient_connect, zclient, zclient->fail < 3 ? 10 : 60); break; case ZCLIENT_READ: zclient->t_read = thread_add_read (zclient->master, zclient_read, zclient, zclient->sock); break; } } const char *zclient_serv_path_get() { return zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH; } void zclient_serv_path_set (char *path) { struct stat sb; /* reset */ zclient_serv_path = NULL; /* test if `path' is socket. don't set it otherwise. */ if (stat(path, &sb) == -1) { zlog_warn ("%s: zebra socket `%s' does not exist", __func__, path); return; } if ((sb.st_mode & S_IFMT) != S_IFSOCK) { zlog_warn ("%s: `%s' is not unix socket, sir", __func__, path); return; } /* it seems that path is unix socket */ zclient_serv_path = path; } quagga-1.2.4/lib/zclient.h000066400000000000000000000153101325323223500153520ustar00rootroot00000000000000/* 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 zapi_ipv{4,6}. */ #include "prefix.h" /* For struct interface and struct connected. */ #include "if.h" /* For vrf_bitmap_t. */ #include "vrf.h" /* For input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 4096 /* Zebra header size. */ #define ZEBRA_HEADER_SIZE 8 /* Structure for the zebra client. */ struct zclient { /* The thread master we schedule ourselves on */ struct thread_master *master; /* 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; /* Buffer of data waiting to be written to zebra. */ struct buffer *wb; /* Read and connect thread. */ struct thread *t_read; struct thread *t_connect; /* Thread to write buffered data to zebra. */ struct thread *t_write; /* Redistribute information. */ u_char redist_default; vrf_bitmap_t redist[ZEBRA_ROUTE_MAX]; /* Redistribute defauilt. */ vrf_bitmap_t default_information; /* Pointer to the callback functions. */ void (*zebra_connected) (struct zclient *); int (*router_id_update) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_delete) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_up) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_down) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_address_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_address_delete) (int, struct zclient *, uint16_t, vrf_id_t); int (*interface_link_params) (int, struct zclient *, uint16_t); int (*ipv4_route_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t); int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t); int (*ipv6_route_delete) (int, struct zclient *, uint16_t, vrf_id_t); int (*nexthop_update) (int, struct zclient *, uint16_t, vrf_id_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 #define ZAPI_MESSAGE_MTU 0x10 #define ZAPI_MESSAGE_TAG 0x20 /* Zserv protocol message header */ struct zserv_header { uint16_t length; uint8_t marker; /* corresponds to command field in old zserv * always set to 255 in new zserv. */ uint8_t version; #define ZSERV_VERSION 3 vrf_id_t vrf_id; uint16_t command; }; /* Zebra IPv4 route message API. */ struct zapi_ipv4 { u_char type; u_char flags; u_char message; safi_t safi; u_char nexthop_num; struct in_addr **nexthop; u_char ifindex_num; ifindex_t *ifindex; u_char distance; route_tag_t tag; u_int32_t metric; u_int32_t mtu; vrf_id_t vrf_id; }; /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new (struct thread_master *); extern void zclient_init (struct zclient *, int); extern int zclient_start (struct zclient *); extern void zclient_stop (struct zclient *); extern void zclient_reset (struct zclient *); extern void zclient_free (struct zclient *); extern int zclient_socket_connect (struct zclient *); extern void zclient_serv_path_set (char *path); extern const char *zclient_serv_path_get (void); extern void zclient_send_requests (struct zclient *, vrf_id_t); /* Send redistribute command to zebra daemon. Do not update zclient state. */ extern int zebra_redistribute_send (int command, struct zclient *, int type, vrf_id_t vrf_id); /* If state has changed, update state and call zebra_redistribute_send. */ extern void zclient_redistribute (int command, struct zclient *, int type, vrf_id_t vrf_id); /* If state has changed, update state and send the command to zebra. */ extern void zclient_redistribute_default (int command, struct zclient *, vrf_id_t vrf_id); /* Send the message in zclient->obuf to the zebra daemon (or enqueue it). Returns 0 for success or -1 on an I/O error. */ extern int zclient_send_message(struct zclient *); /* create header for command, length to be filled in by user later */ extern void zclient_create_header (struct stream *, uint16_t, vrf_id_t); extern int zclient_read_header (struct stream *s, int sock, u_int16_t *size, u_char *marker, u_char *version, u_int16_t *vrf_id, u_int16_t *cmd); extern struct interface *zebra_interface_add_read (struct stream *, vrf_id_t); extern struct interface *zebra_interface_state_read (struct stream *, vrf_id_t); extern struct connected *zebra_interface_address_read (int, struct stream *, vrf_id_t); extern void zebra_interface_if_set_value (struct stream *, struct interface *); extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid); extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *); extern struct interface *zebra_interface_link_params_read (struct stream *); extern size_t zebra_interface_link_params_write (struct stream *, struct interface *); #ifdef HAVE_IPV6 /* IPv6 prefix add and delete function prototype. */ struct zapi_ipv6 { u_char type; u_char flags; u_char message; safi_t safi; u_char nexthop_num; struct in6_addr **nexthop; u_char ifindex_num; ifindex_t *ifindex; u_char distance; route_tag_t tag; u_int32_t metric; u_int32_t mtu; vrf_id_t vrf_id; }; extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, struct zapi_ipv6 *api); #endif /* HAVE_IPV6 */ #endif /* _ZEBRA_ZCLIENT_H */ quagga-1.2.4/lib/zebra.h000066400000000000000000000360771325323223500150220ustar00rootroot00000000000000/* 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 typedef unsigned int u_int32_t; typedef unsigned short u_int16_t; typedef unsigned char 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 #include #include #include #ifdef HAVE_STROPTS_H #include #endif /* HAVE_STROPTS_H */ #ifdef HAVE_SYS_SELECT_H #include #endif /* HAVE_SYS_SELECT_H */ #include #include #include #ifdef HAVE_SYS_SYSCTL_H #ifdef GNU_LINUX #include #endif #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 #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #include #include #ifdef HAVE_RUSAGE #include #endif /* HAVE_RUSAGE */ #ifdef HAVE_LIMITS_H #include #endif /* HAVE_LIMITS_H */ #ifdef HAVE_INTTYPES_H #include #endif /* HAVE_INTTYPES_H */ #ifdef HAVE_STDBOOL_H #include #endif /* primarily for __STDC_IEC_559__ with clang */ #ifdef HAVE_FEATURES_H #include #endif /* machine dependent includes */ #ifdef SUNOS_5 #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 #if !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) /* Not C99; do we need to define va_copy? */ #ifndef va_copy #ifdef __va_copy #define va_copy(DST,SRC) __va_copy(DST,SRC) #else /* Now we are desperate; this should work on many typical platforms. But this is slightly dangerous, because the standard does not require va_copy to be a macro. */ #define va_copy(DST,SRC) memcpy(&(DST), &(SRC), sizeof(va_list)) #warning "Not C99 and no va_copy macro available, falling back to memcpy" #endif /* __va_copy */ #endif /* !va_copy */ #endif /* !C99 */ /* network include group */ #include #ifdef HAVE_SYS_SOCKIO_H #include #endif /* HAVE_SYS_SOCKIO_H */ #ifdef __APPLE__ #define __APPLE_USE_RFC_3542 #endif #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 */ #ifdef HAVE_NET_ROUTE_H #include #endif /* HAVE_NET_ROUTE_H */ #ifdef HAVE_NETLINK #include #include #include #else #define RT_TABLE_MAIN 0 #endif /* HAVE_NETLINK */ #ifdef HAVE_NETDB_H #include #endif /* HAVE_NETDB_H */ #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_NETINET6_IN6_VAR_H #include #endif /* HAVE_NETINET6_IN6_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 */ /* Privileges / capabilities */ #ifdef HAVE_LCAPS #include #include #endif /* HAVE_LCAPS */ #ifdef HAVE_SOLARIS_CAPABILITIES #include #endif /* HAVE_SOLARIS_CAPABILITIES */ /* Some systems do not define UINT32_MAX, etc.. from inttypes.h * e.g. this makes life easier for FBSD 4.11 users. */ #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifdef HAVE_GLIBC_BACKTRACE #include #endif /* HAVE_GLIBC_BACKTRACE */ /* Local includes: */ #if !(defined(__GNUC__) || defined(VTYSH_EXTRACT_PL)) #define __attribute__(x) #endif /* !__GNUC__ || VTYSH_EXTRACT_PL */ #include "zassert.h" #include "str.h" #ifdef HAVE_BROKEN_CMSG_FIRSTHDR /* This bug is present in Solaris 8 and pre-patch Solaris 9 ; please refer to http://bugzilla.quagga.net/show_bug.cgi?id=142 */ /* Check that msg_controllen is large enough. */ #define ZCMSG_FIRSTHDR(mhdr) \ (((size_t)((mhdr)->msg_controllen) >= sizeof(struct cmsghdr)) ? \ CMSG_FIRSTHDR(mhdr) : (struct cmsghdr *)NULL) #warning "CMSG_FIRSTHDR is broken on this platform, using a workaround" #else /* HAVE_BROKEN_CMSG_FIRSTHDR */ #define ZCMSG_FIRSTHDR(M) CMSG_FIRSTHDR(M) #endif /* HAVE_BROKEN_CMSG_FIRSTHDR */ /* * RFC 3542 defines several macros for using struct cmsghdr. * Here, we define those that are not present */ /* * Internal defines, for use only in this file. * These are likely wrong on other than ILP32 machines, so warn. */ #ifndef _CMSG_DATA_ALIGN #define _CMSG_DATA_ALIGN(n) (((n) + 3) & ~3) #endif /* _CMSG_DATA_ALIGN */ #ifndef _CMSG_HDR_ALIGN #define _CMSG_HDR_ALIGN(n) (((n) + 3) & ~3) #endif /* _CMSG_HDR_ALIGN */ /* * CMSG_SPACE and CMSG_LEN are required in RFC3542, but were new in that * version. */ #ifndef CMSG_SPACE #define CMSG_SPACE(l) (_CMSG_DATA_ALIGN(sizeof(struct cmsghdr)) + \ _CMSG_HDR_ALIGN(l)) #warning "assuming 4-byte alignment for CMSG_SPACE" #endif /* CMSG_SPACE */ #ifndef CMSG_LEN #define CMSG_LEN(l) (_CMSG_DATA_ALIGN(sizeof(struct cmsghdr)) + (l)) #warning "assuming 4-byte alignment for CMSG_LEN" #endif /* CMSG_LEN */ /* The definition of struct in_pktinfo is missing in old version of GLIBC 2.1 (Redhat 6.1). */ #if defined (GNU_LINUX) && ! defined (HAVE_STRUCT_IN_PKTINFO) struct in_pktinfo { int ipi_ifindex; struct in_addr ipi_spec_dst; struct in_addr ipi_addr; }; #endif /* * OSPF Fragmentation / fragmented writes * * ospfd can support writing fragmented packets, for cases where * kernel will not fragment IP_HDRINCL and/or multicast destined * packets (ie TTBOMK all kernels, BSD, SunOS, Linux). However, * SunOS, probably BSD too, clobber the user supplied IP ID and IP * flags fields, hence user-space fragmentation will not work. * Only Linux is known to leave IP header unmolested. * Further, fragmentation really should be done the kernel, which already * supports it, and which avoids nasty IP ID state problems. * * Fragmentation of OSPF packets can be required on networks with router * with many many interfaces active in one area, or on networks with links * with low MTUs. */ #ifdef GNU_LINUX #define WANT_OSPF_WRITE_FRAGMENT #endif /* * IP_HDRINCL / struct ip byte order * * Linux: network byte order * *BSD: network, except for length and offset. (cf Stevens) * SunOS: nominally as per BSD. but bug: network order on LE. * OpenBSD: network byte order, apart from older versions which are as per * *BSD */ #if defined(__NetBSD__) \ || (defined(__FreeBSD__) && (__FreeBSD_version < 1100030)) \ || (defined(__OpenBSD__) && (OpenBSD < 200311)) \ || (defined(__APPLE__)) \ || (defined(SUNOS_5) && defined(WORDS_BIGENDIAN)) #define HAVE_IP_HDRINCL_BSD_ORDER #endif /* Define BYTE_ORDER, if not defined. Useful for compiler conditional * code, rather than preprocessor conditional. * Not all the world has this BSD define. */ #ifndef BYTE_ORDER #define BIG_ENDIAN 4321 /* least-significant byte first (vax, pc) */ #define LITTLE_ENDIAN 1234 /* most-significant byte first (IBM, net) */ #define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ #if defined(WORDS_BIGENDIAN) #define BYTE_ORDER BIG_ENDIAN #else /* !WORDS_BIGENDIAN */ #define BYTE_ORDER LITTLE_ENDIAN #endif /* WORDS_BIGENDIAN */ #endif /* ndef BYTE_ORDER */ /* MAX / MIN are not commonly defined, but useful */ #ifndef MAX #define MAX(a, b) \ ({ typeof (a) _a = (a); \ typeof (b) _b = (b); \ _a > _b ? _a : _b; }) #endif #ifndef MIN #define MIN(a, b) \ ({ typeof (a) _a = (a); \ typeof (b) _b = (b); \ _a < _b ? _a : _b; }) #endif #define ZEBRA_NUM_OF(x) (sizeof (x) / sizeof (x[0])) /* For old definition. */ #ifndef IN6_ARE_ADDR_EQUAL #define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL #endif /* IN6_ARE_ADDR_EQUAL */ /* default zebra TCP port for zclient */ #define ZEBRA_PORT 2600 /* 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_INTERFACE_RENAME 19 #define ZEBRA_ROUTER_ID_ADD 20 #define ZEBRA_ROUTER_ID_DELETE 21 #define ZEBRA_ROUTER_ID_UPDATE 22 #define ZEBRA_HELLO 23 #define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB 24 #define ZEBRA_VRF_UNREGISTER 25 #define ZEBRA_INTERFACE_LINK_PARAMS 26 #define ZEBRA_NEXTHOP_REGISTER 27 #define ZEBRA_NEXTHOP_UNREGISTER 28 #define ZEBRA_NEXTHOP_UPDATE 29 #define ZEBRA_MESSAGE_MAX 30 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new * Zserv headers to be distinguished from each other. */ #define ZEBRA_HEADER_MARKER 255 /* Zebra route's types are defined in route_types.h */ #include "route_types.h" /* Note: whenever a new route-type or zserv-command is added the * corresponding {command,route}_types[] table in lib/log.c MUST be * updated! */ /* Map a route type to a string. For example, ZEBRA_ROUTE_RIPNG -> "ripng". */ extern const char *zebra_route_string(unsigned int route_type); /* Map a route type to a char. For example, ZEBRA_ROUTE_RIPNG -> 'R'. */ extern char zebra_route_char(unsigned int route_type); /* Map a zserv command type to the same string, * e.g. ZEBRA_INTERFACE_ADD -> "ZEBRA_INTERFACE_ADD" */ /* Map a protocol name to its number. e.g. ZEBRA_ROUTE_BGP->9*/ extern int proto_name2num(const char *s); /* Map redistribute X argument to protocol number. * unlike proto_name2num, this accepts shorthands and takes * an AFI value to restrict input */ extern int proto_redistnum(int afi, const char *s); extern const char *zserv_command_string (unsigned int command); /* Error codes of zebra. */ #define ZEBRA_ERR_NOERROR 0 #define ZEBRA_ERR_RTEXIST -1 #define ZEBRA_ERR_RTUNREACH -2 #define ZEBRA_ERR_EPERM -3 #define ZEBRA_ERR_RTNOEXIST -4 #define ZEBRA_ERR_KERNEL -5 /* 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_FIB_OVERRIDE 0x20 #define ZEBRA_FLAG_STATIC 0x40 #define ZEBRA_FLAG_REJECT 0x80 /* 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. */ typedef enum { AFI_IP = 1, AFI_IP6 = 2, AFI_ETHER = 3, /* RFC 1700 has "6" for 802.* */ #define AFI_MAX 4 } afi_t; /* Subsequent Address Family Identifier. */ #define SAFI_UNICAST 1 #define SAFI_MULTICAST 2 #define SAFI_RESERVED_3 3 #define SAFI_MPLS_VPN 4 #define SAFI_ENCAP 7 /* per IANA */ #define SAFI_MAX 8 /* 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_ISIS_DISTANCE_DEFAULT 115 #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) |= (F) #define UNSET_FLAG(V,F) (V) &= ~(F) #define RESET_FLAG(V) (V) = 0 typedef u_int8_t safi_t; /* Zebra types. Used in Zserv message header. */ typedef u_int16_t zebra_size_t; typedef u_int16_t zebra_command_t; /* VRF ID type. */ typedef u_int16_t vrf_id_t; typedef uint32_t route_tag_t; #define ROUTE_TAG_MAX UINT32_MAX #endif /* _ZEBRA_H */ quagga-1.2.4/ltmain.sh000066400000000000000000011707711325323223500146210ustar00rootroot00000000000000#! /bin/sh ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in ## by inline-source v2014-01-03.01 # libtool (GNU libtool) 2.4.6 # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . PROGRAM=libtool PACKAGE=libtool VERSION=2.4.6 package_revision=2.4.6 ## ------ ## ## Usage. ## ## ------ ## # Run './libtool --help' for help with using this script from the # command line. ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # After configure completes, it has a better idea of some of the # shell tools we need than the defaults used by the functions shared # with bootstrap, so set those here where they can still be over- # ridden by the user, but otherwise take precedence. : ${AUTOCONF="autoconf"} : ${AUTOMAKE="automake"} ## -------------------------- ## ## Source external libraries. ## ## -------------------------- ## # Much of our low-level functionality needs to be sourced from external # libraries, which are installed to $pkgauxdir. # Set a version string for this script. scriptversion=2015-01-20.17; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 # Copyright (C) 2004-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # 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 3 of the License, or # (at your option) any later version. # As a special exception to the GNU General Public License, if you distribute # this file as part of a program or library that is built using GNU Libtool, # you may include this file under the same distribution terms that you use # for the rest of that program. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # Evaluate this file near the top of your script to gain access to # the functions and variables defined here: # # . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh # # If you need to override any of the default environment variable # settings, do that before evaluating this file. ## -------------------- ## ## Shell normalisation. ## ## -------------------- ## # Some shells need a little help to be as Bourne compatible as possible. # Before doing anything else, make sure all that help has been provided! DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # NLS nuisances: We save the old values in case they are required later. _G_user_locale= _G_safe_locale= for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test set = \"\${$_G_var+set}\"; then save_$_G_var=\$$_G_var $_G_var=C export $_G_var _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Make sure IFS has a sensible default sp=' ' nl=' ' IFS="$sp $nl" # There are apparently some retarded systems that use ';' as a PATH separator! if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi ## ------------------------- ## ## Locate command utilities. ## ## ------------------------- ## # func_executable_p FILE # ---------------------- # Check that FILE is an executable regular file. func_executable_p () { test -f "$1" && test -x "$1" } # func_path_progs PROGS_LIST CHECK_FUNC [PATH] # -------------------------------------------- # Search for either a program that responds to --version with output # containing "GNU", or else returned by CHECK_FUNC otherwise, by # trying all the directories in PATH with each of the elements of # PROGS_LIST. # # CHECK_FUNC should accept the path to a candidate program, and # set $func_check_prog_result if it truncates its output less than # $_G_path_prog_max characters. func_path_progs () { _G_progs_list=$1 _G_check_func=$2 _G_PATH=${3-"$PATH"} _G_path_prog_max=0 _G_path_prog_found=false _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} for _G_dir in $_G_PATH; do IFS=$_G_save_IFS test -z "$_G_dir" && _G_dir=. for _G_prog_name in $_G_progs_list; do for _exeext in '' .EXE; do _G_path_prog=$_G_dir/$_G_prog_name$_exeext func_executable_p "$_G_path_prog" || continue case `"$_G_path_prog" --version 2>&1` in *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; *) $_G_check_func $_G_path_prog func_path_progs_result=$func_check_prog_result ;; esac $_G_path_prog_found && break 3 done done done IFS=$_G_save_IFS test -z "$func_path_progs_result" && { echo "no acceptable sed could be found in \$PATH" >&2 exit 1 } } # We want to be able to use the functions in this file before configure # has figured out where the best binaries are kept, which means we have # to search for them ourselves - except when the results are already set # where we skip the searches. # Unless the user overrides by setting SED, search the path for either GNU # sed, or the sed that truncates its output the least. test -z "$SED" && { _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for _G_i in 1 2 3 4 5 6 7; do _G_sed_script=$_G_sed_script$nl$_G_sed_script done echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed _G_sed_script= func_check_prog_sed () { _G_path_prog=$1 _G_count=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo '' >> conftest.nl "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin rm -f conftest.sed SED=$func_path_progs_result } # Unless the user overrides by setting GREP, search the path for either GNU # grep, or the grep that truncates its output the least. test -z "$GREP" && { func_check_prog_grep () { _G_path_prog=$1 _G_count=0 _G_path_prog_max=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo 'GREP' >> conftest.nl "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin GREP=$func_path_progs_result } ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # All uppercase variable names are used for environment variables. These # variables can be overridden by the user before calling a script that # uses them if a suitable command of that name is not already available # in the command search PATH. : ${CP="cp -f"} : ${ECHO="printf %s\n"} : ${EGREP="$GREP -E"} : ${FGREP="$GREP -F"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} ## -------------------- ## ## Useful sed snippets. ## ## -------------------- ## sed_dirname='s|/[^/]*$||' sed_basename='s|^.*/||' # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s|\([`"$\\]\)|\\\1|g' # Same as above, but do not quote variable references. sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' # Sed substitution that converts a w32 file name or path # that contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-'\' parameter expansions in output of sed_double_quote_subst that # were '\'-ed in input to the same. If an odd number of '\' preceded a # '$' in input to sed_double_quote_subst, that '$' was protected from # expansion. Since each input '\' is now two '\'s, look for any number # of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. _G_bs='\\' _G_bs2='\\\\' _G_bs4='\\\\\\\\' _G_dollar='\$' sed_double_backslash="\ s/$_G_bs4/&\\ /g s/^$_G_bs2$_G_dollar/$_G_bs&/ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" ## ----------------- ## ## Global variables. ## ## ----------------- ## # Except for the global variables explicitly listed below, the following # functions in the '^func_' namespace, and the '^require_' namespace # variables initialised in the 'Resource management' section, sourcing # this file will not pollute your global namespace with anything # else. There's no portable way to scope variables in Bourne shell # though, so actually running these functions will sometimes place # results into a variable named after the function, and often use # temporary variables in the '^_G_' namespace. If you are careful to # avoid using those namespaces casually in your sourcing script, things # should continue to work as you expect. And, of course, you can freely # overwrite any of the functions or variables defined here before # calling anything to customize them. EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. # Allow overriding, eg assuming that you follow the convention of # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # # debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: # By convention, finish your script with: # # exit $exit_status # # so that you can set exit_status to non-zero if you want to indicate # something went wrong during execution without actually bailing out at # the point of failure. exit_status=$EXIT_SUCCESS # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath=$0 # The name of this program. progname=`$ECHO "$progpath" |$SED "$sed_basename"` # Make sure we have an absolute progpath for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` progdir=`cd "$progdir" && pwd` progpath=$progdir/$progname ;; *) _G_IFS=$IFS IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS=$_G_IFS test -x "$progdir/$progname" && break done IFS=$_G_IFS test -n "$progdir" || progdir=`pwd` progpath=$progdir/$progname ;; esac ## ----------------- ## ## Standard options. ## ## ----------------- ## # The following options affect the operation of the functions defined # below, and should be set appropriately depending on run-time para- # meters passed on the command line. opt_dry_run=false opt_quiet=false opt_verbose=false # Categories 'all' and 'none' are always available. Append any others # you will pass as the first argument to func_warning from your own # code. warning_categories= # By default, display warnings according to 'opt_warning_types'. Set # 'warning_func' to ':' to elide all warnings, or func_fatal_error to # treat the next displayed warning as a fatal error. warning_func=func_warn_and_continue # Set to 'all' to display all warnings, 'none' to suppress all # warnings, or a space delimited list of some subset of # 'warning_categories' to display only the listed warnings. opt_warning_types=all ## -------------------- ## ## Resource management. ## ## -------------------- ## # This section contains definitions for functions that each ensure a # particular resource (a file, or a non-empty configuration variable for # example) is available, and if appropriate to extract default values # from pertinent package files. Call them using their associated # 'require_*' variable to ensure that they are executed, at most, once. # # It's entirely deliberate that calling these functions can set # variables that don't obey the namespace limitations obeyed by the rest # of this file, in order that that they be as useful as possible to # callers. # require_term_colors # ------------------- # Allow display of bold text on terminals that support it. require_term_colors=func_require_term_colors func_require_term_colors () { $debug_cmd test -t 1 && { # COLORTERM and USE_ANSI_COLORS environment variables take # precedence, because most terminfo databases neglect to describe # whether color sequences are supported. test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} if test 1 = "$USE_ANSI_COLORS"; then # Standard ANSI escape sequences tc_reset='' tc_bold=''; tc_standout='' tc_red=''; tc_green='' tc_blue=''; tc_cyan='' else # Otherwise trust the terminfo database after all. test -n "`tput sgr0 2>/dev/null`" && { tc_reset=`tput sgr0` test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` tc_standout=$tc_bold test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` } fi } require_term_colors=: } ## ----------------- ## ## Function library. ## ## ----------------- ## # This section contains a variety of useful functions to call in your # scripts. Take note of the portable wrappers for features provided by # some modern shells, which will fall back to slower equivalents on # less featureful shells. # func_append VAR VALUE # --------------------- # Append VALUE onto the existing contents of VAR. # We should try to minimise forks, especially on Windows where they are # unreasonably slow, so skip the feature probes when bash or zsh are # being used: if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then : ${_G_HAVE_ARITH_OP="yes"} : ${_G_HAVE_XSI_OPS="yes"} # The += operator was introduced in bash 3.1 case $BASH_VERSION in [12].* | 3.0 | 3.0*) ;; *) : ${_G_HAVE_PLUSEQ_OP="yes"} ;; esac fi # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is # useable or anything else if it does not work. test -z "$_G_HAVE_PLUSEQ_OP" \ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ && _G_HAVE_PLUSEQ_OP=yes if test yes = "$_G_HAVE_PLUSEQ_OP" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_append () { $debug_cmd eval "$1+=\$2" }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_append () { $debug_cmd eval "$1=\$$1\$2" } fi # func_append_quoted VAR VALUE # ---------------------------- # Quote VALUE and append to the end of shell variable VAR, separated # by a space. if test yes = "$_G_HAVE_PLUSEQ_OP"; then eval 'func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1+=\\ \$func_quote_for_eval_result" }' else func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1=\$$1\\ \$func_quote_for_eval_result" } fi # func_append_uniq VAR VALUE # -------------------------- # Append unique VALUE onto the existing contents of VAR, assuming # entries are delimited by the first character of VALUE. For example: # # func_append_uniq options " --another-option option-argument" # # will only append to $options if " --another-option option-argument " # is not already present somewhere in $options already (note spaces at # each end implied by leading space in second argument). func_append_uniq () { $debug_cmd eval _G_current_value='`$ECHO $'$1'`' _G_delim=`expr "$2" : '\(.\)'` case $_G_delim$_G_current_value$_G_delim in *"$2$_G_delim"*) ;; *) func_append "$@" ;; esac } # func_arith TERM... # ------------------ # Set func_arith_result to the result of evaluating TERMs. test -z "$_G_HAVE_ARITH_OP" \ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ && _G_HAVE_ARITH_OP=yes if test yes = "$_G_HAVE_ARITH_OP"; then eval 'func_arith () { $debug_cmd func_arith_result=$(( $* )) }' else func_arith () { $debug_cmd func_arith_result=`expr "$@"` } fi # func_basename FILE # ------------------ # Set func_basename_result to FILE with everything up to and including # the last / stripped. if test yes = "$_G_HAVE_XSI_OPS"; then # If this shell supports suffix pattern removal, then use it to avoid # forking. Hide the definitions single quotes in case the shell chokes # on unsupported syntax... _b='func_basename_result=${1##*/}' _d='case $1 in */*) func_dirname_result=${1%/*}$2 ;; * ) func_dirname_result=$3 ;; esac' else # ...otherwise fall back to using sed. _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` if test "X$func_dirname_result" = "X$1"; then func_dirname_result=$3 else func_append func_dirname_result "$2" fi' fi eval 'func_basename () { $debug_cmd '"$_b"' }' # func_dirname FILE APPEND NONDIR_REPLACEMENT # ------------------------------------------- # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. eval 'func_dirname () { $debug_cmd '"$_d"' }' # func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT # -------------------------------------------------------- # Perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () { $debug_cmd '"$_b"' '"$_d"' }' # func_echo ARG... # ---------------- # Echo program name prefixed message. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname: $_G_line" done IFS=$func_echo_IFS } # func_echo_all ARG... # -------------------- # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_echo_infix_1 INFIX ARG... # ------------------------------ # Echo program name, followed by INFIX on the first line, with any # additional lines not showing INFIX. func_echo_infix_1 () { $debug_cmd $require_term_colors _G_infix=$1; shift _G_indent=$_G_infix _G_prefix="$progname: $_G_infix: " _G_message=$* # Strip color escape sequences before counting printable length for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" do test -n "$_G_tc" && { _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` } done _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes func_echo_infix_1_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_infix_1_IFS $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 _G_prefix=$_G_indent done IFS=$func_echo_infix_1_IFS } # func_error ARG... # ----------------- # Echo program name prefixed message to standard error. func_error () { $debug_cmd $require_term_colors func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 } # func_fatal_error ARG... # ----------------------- # Echo program name prefixed message to standard error, and exit. func_fatal_error () { $debug_cmd func_error "$*" exit $EXIT_FAILURE } # func_grep EXPRESSION FILENAME # ----------------------------- # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $debug_cmd $GREP "$1" "$2" >/dev/null 2>&1 } # func_len STRING # --------------- # Set func_len_result to the length of STRING. STRING may not # start with a hyphen. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_len () { $debug_cmd func_len_result=${#1} }' else func_len () { $debug_cmd func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } fi # func_mkdir_p DIRECTORY-PATH # --------------------------- # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { $debug_cmd _G_directory_path=$1 _G_dir_list= if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then # Protect directory names starting with '-' case $_G_directory_path in -*) _G_directory_path=./$_G_directory_path ;; esac # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done case $_G_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` done _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` func_mkdir_p_IFS=$IFS; IFS=: for _G_dir in $_G_dir_list; do IFS=$func_mkdir_p_IFS # mkdir can fail with a 'File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$_G_dir" 2>/dev/null || : done IFS=$func_mkdir_p_IFS # Bail out if we (or some other process) failed to create a directory. test -d "$_G_directory_path" || \ func_fatal_error "Failed to create '$1'" fi } # func_mktempdir [BASENAME] # ------------------------- # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, BASENAME is the basename for that directory. func_mktempdir () { $debug_cmd _G_template=${TMPDIR-/tmp}/${1-$progname} if test : = "$opt_dry_run"; then # Return a directory name, but don't create it in dry-run mode _G_tmpdir=$_G_template-$$ else # If mktemp works, use that first and foremost _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` if test ! -d "$_G_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race _G_tmpdir=$_G_template-${RANDOM-0}$$ func_mktempdir_umask=`umask` umask 0077 $MKDIR "$_G_tmpdir" umask $func_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$_G_tmpdir" || \ func_fatal_error "cannot create temporary directory '$_G_tmpdir'" fi $ECHO "$_G_tmpdir" } # func_normal_abspath PATH # ------------------------ # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. func_normal_abspath () { $debug_cmd # These SED scripts presuppose an absolute path with a trailing slash. _G_pathcar='s|^/\([^/]*\).*$|\1|' _G_pathcdr='s|^/[^/]*||' _G_removedotparts=':dotsl s|/\./|/|g t dotsl s|/\.$|/|' _G_collapseslashes='s|/\{1,\}|/|g' _G_finalslash='s|/*$|/|' # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` while :; do # Processed it all yet? if test / = "$func_normal_abspath_tpath"; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result"; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_notquiet ARG... # -------------------- # Echo program name prefixed message only when not in quiet mode. func_notquiet () { $debug_cmd $opt_quiet || func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_relative_path SRCDIR DSTDIR # -------------------------------- # Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. func_relative_path () { $debug_cmd func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=$func_dirname_result if test -z "$func_relative_path_tlibdir"; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test -n "$func_stripname_result"; then func_append func_relative_path_result "/$func_stripname_result" fi # Normalisation. If bindir is libdir, return '.' else relative path. if test -n "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result" func_relative_path_result=$func_stripname_result fi test -n "$func_relative_path_result" || func_relative_path_result=. : } # func_quote_for_eval ARG... # -------------------------- # Aesthetically quote ARGs to be evaled later. # This function returns two values: # i) func_quote_for_eval_result # double-quoted, suitable for a subsequent eval # ii) func_quote_for_eval_unquoted_result # has all characters that are still active within double # quotes backslashified. func_quote_for_eval () { $debug_cmd func_quote_for_eval_unquoted_result= func_quote_for_eval_result= while test 0 -lt $#; do case $1 in *[\\\`\"\$]*) _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; *) _G_unquoted_arg=$1 ;; esac if test -n "$func_quote_for_eval_unquoted_result"; then func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" else func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" fi case $_G_unquoted_arg in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and variable expansion # for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_quoted_arg=\"$_G_unquoted_arg\" ;; *) _G_quoted_arg=$_G_unquoted_arg ;; esac if test -n "$func_quote_for_eval_result"; then func_append func_quote_for_eval_result " $_G_quoted_arg" else func_append func_quote_for_eval_result "$_G_quoted_arg" fi shift done } # func_quote_for_expand ARG # ------------------------- # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { $debug_cmd case $1 in *[\\\`\"]*) _G_arg=`$ECHO "$1" | $SED \ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; *) _G_arg=$1 ;; esac case $_G_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_arg=\"$_G_arg\" ;; esac func_quote_for_expand_result=$_G_arg } # func_stripname PREFIX SUFFIX NAME # --------------------------------- # strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_stripname () { $debug_cmd # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary variable first. func_stripname_result=$3 func_stripname_result=${func_stripname_result#"$1"} func_stripname_result=${func_stripname_result%"$2"} }' else func_stripname () { $debug_cmd case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; esac } fi # func_show_eval CMD [FAIL_EXP] # ----------------------------- # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} func_quote_for_expand "$_G_cmd" eval "func_notquiet $func_quote_for_expand_result" $opt_dry_run || { eval "$_G_cmd" _G_status=$? if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_show_eval_locale CMD [FAIL_EXP] # ------------------------------------ # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} $opt_quiet || { func_quote_for_expand "$_G_cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || { eval "$_G_user_locale $_G_cmd" _G_status=$? eval "$_G_safe_locale" if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_tr_sh # ---------- # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { $debug_cmd case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_verbose ARG... # ------------------- # Echo program name prefixed message in verbose mode only. func_verbose () { $debug_cmd $opt_verbose && func_echo "$*" : } # func_warn_and_continue ARG... # ----------------------------- # Echo program name prefixed warning message to standard error. func_warn_and_continue () { $debug_cmd $require_term_colors func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 } # func_warning CATEGORY ARG... # ---------------------------- # Echo program name prefixed warning message to standard error. Warning # messages can be filtered according to CATEGORY, where this function # elides messages where CATEGORY is not listed in the global variable # 'opt_warning_types'. func_warning () { $debug_cmd # CATEGORY must be in the warning_categories list! case " $warning_categories " in *" $1 "*) ;; *) func_internal_error "invalid warning category '$1'" ;; esac _G_category=$1 shift case " $opt_warning_types " in *" $_G_category "*) $warning_func ${1+"$@"} ;; esac } # func_sort_ver VER1 VER2 # ----------------------- # 'sort -V' is not generally available. # Note this deviates from the version comparison in automake # in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a # but this should suffice as we won't be specifying old # version formats or redundant trailing .0 in bootstrap.conf. # If we did want full compatibility then we should probably # use m4_version_compare from autoconf. func_sort_ver () { $debug_cmd printf '%s\n%s\n' "$1" "$2" \ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n } # func_lt_ver PREV CURR # --------------------- # Return true if PREV and CURR are in the correct order according to # func_sort_ver, otherwise false. Use it like this: # # func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." func_lt_ver () { $debug_cmd test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: #! /bin/sh # Set a version string for this script. scriptversion=2014-01-07.03; # UTC # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 # Copyright (C) 2010-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # 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 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # This file is a library for parsing options in your shell scripts along # with assorted other useful supporting features that you can make use # of too. # # For the simplest scripts you might need only: # # #!/bin/sh # . relative/path/to/funclib.sh # . relative/path/to/options-parser # scriptversion=1.0 # func_options ${1+"$@"} # eval set dummy "$func_options_result"; shift # ...rest of your script... # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file # starting with '# Written by ' and ending with '# warranty; '. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the # '# Written by ' line, like the one at the top of this file. # # The default options also support '--debug', which will turn on shell # execution tracing (see the comment above debug_cmd below for another # use), and '--verbose' and the func_verbose function to allow your script # to display verbose messages only when your user has specified # '--verbose'. # # After sourcing this file, you can plug processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. ## -------------- ## ## Configuration. ## ## -------------- ## # You should override these variables in your script after sourcing this # file so that they reflect the customisations you have added to the # option parser. # The usage line for option parsing errors and the start of '-h' and # '--help' output messages. You can embed shell variables for delayed # expansion at the time the message is displayed, but you will need to # quote other shell meta-characters carefully to prevent them being # expanded when the contents are evaled. usage='$progpath [OPTION]...' # Short help message in response to '-h' and '--help'. Add to this or # override it after sourcing this library to reflect the full set of # options your script accepts. usage_message="\ --debug enable verbose shell tracing -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -v, --verbose verbosely report processing --version print version information and exit -h, --help print short or long help message and exit " # Additional text appended to 'usage_message' in response to '--help'. long_help_message=" Warning categories include: 'all' show all warnings 'none' turn off all the warnings 'error' warnings are treated as fatal errors" # Help message printed before fatal option parsing errors. fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## ## Hook function management. ## ## ------------------------- ## # This section contains functions for adding, removing, and running hooks # to the main code. A hook is just a named list of of function, that can # be run in order later on. # func_hookable FUNC_NAME # ----------------------- # Declare that FUNC_NAME will run hooks added with # 'func_add_hook FUNC_NAME ...'. func_hookable () { $debug_cmd func_append hookable_fns " $1" } # func_add_hook FUNC_NAME HOOK_FUNC # --------------------------------- # Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must # first have been declared "hookable" by a call to 'func_hookable'. func_add_hook () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not accept hook functions." ;; esac eval func_append ${1}_hooks '" $2"' } # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ # Remove HOOK_FUNC from the list of functions called by FUNC_NAME. func_remove_hook () { $debug_cmd eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' } # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. # It is assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. func_run_hooks () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook funcions.n" ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do eval $_G_hook '"$@"' # store returned options list back into positional # parameters for next 'cmd' execution. eval _G_hook_result=\$${_G_hook}_result eval set dummy "$_G_hook_result"; shift done func_quote_for_eval ${1+"$@"} func_run_hooks_result=$func_quote_for_eval_result } ## --------------- ## ## Option parsing. ## ## --------------- ## # In order to add your own option parsing hooks, you must accept the # full positional parameter list in your hook function, remove any # options that you action, and then pass back the remaining unprocessed # options in '_result', escaped suitably for # 'eval'. Like this: # # my_options_prep () # { # $debug_cmd # # # Extend the existing usage message. # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' # # func_quote_for_eval ${1+"$@"} # my_options_prep_result=$func_quote_for_eval_result # } # func_add_hook func_options_prep my_options_prep # # # my_silent_option () # { # $debug_cmd # # # Note that for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in # --silent|-s) opt_silent=: ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift # ;; # *) set dummy "$_G_opt" "$*"; shift; break ;; # esac # done # # func_quote_for_eval ${1+"$@"} # my_silent_option_result=$func_quote_for_eval_result # } # func_add_hook func_parse_options my_silent_option # # # my_option_validation () # { # $debug_cmd # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." # # func_quote_for_eval ${1+"$@"} # my_option_validation_result=$func_quote_for_eval_result # } # func_add_hook func_validate_options my_option_validation # # You'll alse need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the # individual implementations for details. func_hookable func_options func_options () { $debug_cmd func_options_prep ${1+"$@"} eval func_parse_options \ ${func_options_prep_result+"$func_options_prep_result"} eval func_validate_options \ ${func_parse_options_result+"$func_parse_options_result"} eval func_run_hooks func_options \ ${func_validate_options_result+"$func_validate_options_result"} # save modified positional parameters for caller func_options_result=$func_run_hooks_result } # func_options_prep [ARG]... # -------------------------- # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and # needs to propogate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before # returning. func_hookable func_options_prep func_options_prep () { $debug_cmd # Option defaults: opt_verbose=false opt_warning_types= func_run_hooks func_options_prep ${1+"$@"} # save modified positional parameters for caller func_options_prep_result=$func_run_hooks_result } # func_parse_options [ARG]... # --------------------------- # The main option parsing loop. func_hookable func_parse_options func_parse_options () { $debug_cmd func_parse_options_result= # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. func_run_hooks func_parse_options ${1+"$@"} # Adjust func_parse_options positional parameters to match eval set dummy "$func_run_hooks_result"; shift # Break out of the loop if we already parsed every option. test $# -gt 0 || break _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' func_echo "enabling shell trace mode" $debug_cmd ;; --no-warnings|--no-warning|--no-warn) set dummy --warnings none ${1+"$@"} shift ;; --warnings|--warning|-W) test $# = 0 && func_missing_arg $_G_opt && break case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above func_append_uniq opt_warning_types " $1" ;; *all) opt_warning_types=$warning_categories ;; *none) opt_warning_types=none warning_func=: ;; *error) opt_warning_types=$warning_categories warning_func=func_fatal_error ;; *) func_fatal_error \ "unsupported warning category: '$1'" ;; esac shift ;; --verbose|-v) opt_verbose=: ;; --version) func_version ;; -\?|-h) func_usage ;; --help) func_help ;; # Separate optargs to long options (plugins may need this): --*=*) func_split_equals "$_G_opt" set dummy "$func_split_equals_lhs" \ "$func_split_equals_rhs" ${1+"$@"} shift ;; # Separate optargs to short options: -W*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "$func_split_short_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-v*|-x*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; esac done # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} func_parse_options_result=$func_quote_for_eval_result } # func_validate_options [ARG]... # ------------------------------ # Perform any sanity checks on option settings and/or unconsumed # arguments. func_hookable func_validate_options func_validate_options () { $debug_cmd # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" func_run_hooks func_validate_options ${1+"$@"} # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE # save modified positional parameters for caller func_validate_options_result=$func_run_hooks_result } ## ----------------- ## ## Helper functions. ## ## ----------------- ## # This section contains the helper functions used by the rest of the # hookable option parser framework in ascii-betical order. # func_fatal_help ARG... # ---------------------- # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { $debug_cmd eval \$ECHO \""Usage: $usage"\" eval \$ECHO \""$fatal_help"\" func_error ${1+"$@"} exit $EXIT_FAILURE } # func_help # --------- # Echo long help message to standard output and exit. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message" exit 0 } # func_missing_arg ARGNAME # ------------------------ # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $debug_cmd func_error "Missing argument for '$1'." exit_cmd=exit } # func_split_equals STRING # ------------------------ # Set func_split_equals_lhs and func_split_equals_rhs shell variables after # splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_equals () { $debug_cmd func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} test "x$func_split_equals_lhs" = "x$1" \ && func_split_equals_rhs= }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_equals () { $debug_cmd func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= test "x$func_split_equals_lhs" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals # func_split_short_opt SHORTOPT # ----------------------------- # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_short_opt () { $debug_cmd func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"} }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_short_opt () { $debug_cmd func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt # func_usage # ---------- # Echo short help message to standard output and exit. func_usage () { $debug_cmd func_usage_message $ECHO "Run '$progname --help |${PAGER-more}' for full usage" exit 0 } # func_usage_message # ------------------ # Echo short help message to standard output. func_usage_message () { $debug_cmd eval \$ECHO \""Usage: $usage"\" echo $SED -n 's|^# || /^Written by/{ x;p;x } h /^Written by/q' < "$progpath" echo eval \$ECHO \""$usage_message"\" } # func_version # ------------ # Echo version message to standard output and exit. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' /(C)/!b go :more /\./!{ N s|\n# | | b more } :go /^# Written by /,/# warranty; / { s|^# || s|^# *$|| s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| p } /^# Written by / { s|^# || p } /^warranty; /q' < "$progpath" exit $? } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. scriptversion='(GNU libtool) 2.4.6' # func_echo ARG... # ---------------- # Libtool also displays the current mode in messages, so override # funclib.sh func_echo with this custom definition. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" done IFS=$func_echo_IFS } # func_warning ARG... # ------------------- # Libtool warnings are not categorized, so override funclib.sh # func_warning with this simpler definition. func_warning () { $debug_cmd $warning_func ${1+"$@"} } ## ---------------- ## ## Options parsing. ## ## ---------------- ## # Hook in the functions to make sure our own options are parsed during # the option parsing loop. usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --mode=MODE use operation mode MODE --no-warnings equivalent to '-Wnone' --preserve-dup-deps don't remove duplicate dependency libraries --quiet, --silent don't print informational messages --tag=TAG use configuration variables from tag TAG -v, --verbose print more informational messages than default --version print version information -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. When passed as first option, '--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. Try '$progname --help --mode=MODE' for a more detailed description of MODE. When reporting a bug, please describe a test case to reproduce it and include the following information: host-triplet: $host shell: $SHELL compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) version: $progname (GNU libtool) 2.4.6 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . GNU libtool home page: . General help using GNU software: ." exit 0 } # func_lo2o OBJECT-NAME # --------------------- # Transform OBJECT-NAME from a '.lo' suffix to the platform specific # object suffix. lo2o=s/\\.lo\$/.$objext/ o2lo=s/\\.$objext\$/.lo/ if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_lo2o () { case $1 in *.lo) func_lo2o_result=${1%.lo}.$objext ;; * ) func_lo2o_result=$1 ;; esac }' # func_xform LIBOBJ-OR-SOURCE # --------------------------- # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) # suffix to a '.lo' libtool-object suffix. eval 'func_xform () { func_xform_result=${1%.*}.lo }' else # ...otherwise fall back to using sed. func_lo2o () { func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` } func_xform () { func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` } fi # func_fatal_configuration ARG... # ------------------------------- # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func__fatal_error ${1+"$@"} \ "See the $PACKAGE documentation for more information." \ "Fatal configuration error." } # func_config # ----------- # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # ------------- # Display the features supported by this script. func_features () { echo "host: $host" if test yes = "$build_libtool_libs"; then echo "enable shared libraries" else echo "disable shared libraries" fi if test yes = "$build_old_libs"; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag TAGNAME # ----------------------- # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname=$1 re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf=/$re_begincf/,/$re_endcf/p # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # ------------------------ # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # libtool_options_prep [ARG]... # ----------------------------- # Preparation for options parsed by libtool. libtool_options_prep () { $debug_mode # Option defaults: opt_config=false opt_dlopen= opt_dry_run=false opt_help=false opt_mode= opt_preserve_dup_deps=false opt_quiet=false nonopt= preserve_args= # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Pass back the list of options. func_quote_for_eval ${1+"$@"} libtool_options_prep_result=$func_quote_for_eval_result } func_add_hook func_options_prep libtool_options_prep # libtool_parse_options [ARG]... # --------------------------------- # Provide handling for libtool specific options. libtool_parse_options () { $debug_cmd # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do _G_opt=$1 shift case $_G_opt in --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) func_config ;; --dlopen|-dlopen) opt_dlopen="${opt_dlopen+$opt_dlopen }$1" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) func_features ;; --finish) set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $_G_opt && break opt_mode=$1 case $1 in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $_G_opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" ;; --no-warnings|--no-warning|--no-warn) opt_warning=false func_append preserve_args " $_G_opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $_G_opt" ;; --silent|--quiet) opt_quiet=: opt_verbose=false func_append preserve_args " $_G_opt" ;; --tag) test $# = 0 && func_missing_arg $_G_opt && break opt_tag=$1 func_append preserve_args " $_G_opt $1" func_enable_tag "$1" shift ;; --verbose|-v) opt_quiet=false opt_verbose=: func_append preserve_args " $_G_opt" ;; # An option not handled by this hook function: *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; esac done # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} libtool_parse_options_result=$func_quote_for_eval_result } func_add_hook func_parse_options libtool_parse_options # libtool_validate_options [ARG]... # --------------------------------- # Perform any sanity checks on option settings and/or unconsumed # arguments. libtool_validate_options () { # save first non-option argument if test 0 -lt $#; then nonopt=$1 shift fi # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" case $host in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match test yes != "$build_libtool_libs" \ && test yes != "$build_old_libs" \ && func_fatal_configuration "not configured to build any kind of library" # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test execute != "$opt_mode"; then func_error "unrecognized option '-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help=$help help="Try '$progname --help --mode=$opt_mode' for more information." } # Pass back the unparsed argument list func_quote_for_eval ${1+"$@"} libtool_validate_options_result=$func_quote_for_eval_result } func_add_hook func_validate_options libtool_validate_options # Process options as early as possible so that --help and --version # can return quickly. func_options ${1+"$@"} eval set dummy "$func_options_result"; shift ## ----------- ## ## Main. ## ## ----------- ## magic='%%%MAGIC variable%%%' magic_exe='%%%MAGIC EXE variable%%%' # Global variables. extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # func_generated_by_libtool # True iff stdin has been generated by Libtool. This function is only # a basic sanity check; it will hardly flush out determined imposters. func_generated_by_libtool_p () { $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p } # func_lalib_unsafe_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if 'file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case $lalib_p_line in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test yes = "$lalib_p" } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { test -f "$1" && $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $debug_cmd save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # 'FILE.' does not work on cygwin managed mounts. func_source () { $debug_cmd case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case $lt_sysroot:$1 in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result='='$func_stripname_result ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $debug_cmd if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with '--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=$1 if test yes = "$build_libtool_libs"; then write_lobj=\'$2\' else write_lobj=none fi if test yes = "$build_old_libs"; then write_oldobj=\'$3\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $debug_cmd # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result= if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result"; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $debug_cmd if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $debug_cmd # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $debug_cmd if test -z "$2" && test -n "$1"; then func_error "Could not determine host file name corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result=$1 fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $debug_cmd if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " '$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result=$3 fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $debug_cmd case $4 in $1 ) func_to_host_path_result=$3$func_to_host_path_result ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via '$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $debug_cmd $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $debug_cmd case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result=$1 } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result=$func_convert_core_msys_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result=$func_convert_core_file_wine_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via '$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $debug_cmd if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd=func_convert_path_$func_stripname_result fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $debug_cmd func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result=$1 } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_msys_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_path_wine_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_dll_def_p FILE # True iff FILE is a Windows DLL '.def' file. # Keep in sync with _LT_DLL_DEF_P in libtool.m4 func_dll_def_p () { $debug_cmd func_dll_def_p_tmp=`$SED -n \ -e 's/^[ ]*//' \ -e '/^\(;.*\)*$/d' \ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ -e q \ "$1"` test DEF = "$func_dll_def_p_tmp" } # func_mode_compile arg... func_mode_compile () { $debug_cmd # Get the compilation command and the source file. base_compile= srcfile=$nonopt # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg=$arg arg_mode=normal ;; target ) libobj=$arg arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify '-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs=$IFS; IFS=, for arg in $args; do IFS=$save_ifs func_append_quoted lastarg "$arg" done IFS=$save_ifs func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg=$srcfile srcfile=$arg ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with '-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj=$func_basename_result } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from '$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test yes = "$build_libtool_libs" \ || func_fatal_configuration "cannot build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name '$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname=$func_basename_result xdir=$func_dirname_result lobj=$xdir$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test yes = "$build_old_libs"; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test no = "$compiler_c_o"; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext lockfile=$output_obj.lock else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test yes = "$need_locks"; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test warn = "$need_locks"; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test no != "$pic_mode"; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test yes = "$suppress_opt"; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test yes = "$build_old_libs"; then if test yes != "$pic_mode"; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test yes = "$compiler_c_o"; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test no != "$need_locks"; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test compile = "$opt_mode" && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a '.o' file suitable for static linking -static only build a '.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a 'standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix '.c' with the library object suffix, '.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to '-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the '--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the 'install' or 'cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE use a list of object files found in FILE to specify objects -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with '-') are ignored. Every other argument is treated as a filename. Files ending in '.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in '.la', then a libtool library is created, only library objects ('.lo' files) may be specified, and '-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created using 'ar' and 'ranlib', or on Windows using 'lib'. If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode '$opt_mode'" ;; esac echo $ECHO "Try '$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test : = "$opt_help"; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | $SED -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | $SED '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $debug_cmd # The first argument is the command name. cmd=$nonopt test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "'$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "'$file' was not linked with '-export-dynamic'" continue fi func_dirname "$file" "" "." dir=$func_dirname_result if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir=$func_dirname_result ;; *) func_warning "'-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir=$absdir # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic=$magic # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file=$progdir/$program elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file=$progdir/$program fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if $opt_dry_run; then # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS else if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd=\$cmd$args fi } test execute = "$opt_mode" && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $debug_cmd libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "'$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument '$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and '=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_quiet && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the '-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the '$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the '$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the '$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test finish = "$opt_mode" && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $debug_cmd # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=false stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=: ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test X-m = "X$prev" && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the '$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=: if $isdir; then destdir=$dest destname= else func_dirname_and_basename "$dest" "" "." destdir=$func_dirname_result destname=$func_basename_result # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "'$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "'$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir=$func_dirname_result func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking '$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname=$1 shift srcname=$realname test -n "$relink_command" && srcname=${realname}T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme=$stripme case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= ;; esac ;; os2*) case $realname in *_dll.a) tstripme= ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try 'ln -sf' first, because the 'ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib=$destdir/$realname func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name=$func_basename_result instname=$dir/${name}i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest=$destfile destfile= ;; *) func_fatal_help "cannot copy a libtool object to '$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test yes = "$build_old_libs"; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext= case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=.exe fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script '$wrapper'" finalize=: for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` if test -n "$libdir" && test ! -f "$libfile"; then func_warning "'$lib' has not been installed in '$libdir'" finalize=false fi done relink_command= func_source "$wrapper" outputname= if test no = "$fast_install" && test -n "$relink_command"; then $opt_dry_run || { if $finalize; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file=$func_basename_result outputname=$tmpdir/$file # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_quiet || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink '$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file=$outputname else func_warning "cannot relink '$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name=$func_basename_result # Set up the ranlib parameters. oldlib=$destdir/$name func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run '$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test install = "$opt_mode" && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $debug_cmd my_outputname=$1 my_originator=$2 my_pic_p=${3-false} my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms=${my_outputname}S.c else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist=$output_objdir/$my_outputname.nm func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* External symbol declarations for the compiler. */\ " if test yes = "$dlself"; then func_verbose "generating symbol list for '$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from '$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols=$output_objdir/$outputname.exp $opt_dry_run || { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from '$dlprefile'" func_basename "$dlprefile" name=$func_basename_result case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename= if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname"; then func_basename "$dlprefile_dlname" dlprefile_dlbasename=$func_basename_result else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename"; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi func_show_eval '$RM "${nlist}I"' if test -n "$global_symbol_to_import"; then eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[];\ " if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ static void lt_syminit(void) { LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; for (; symbol->name; ++symbol) {" $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" echo >> "$output_objdir/$my_dlsyms" "\ } }" fi echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = { {\"$my_originator\", (void *) 0}," if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ {\"@INIT@\", (void *) <_syminit}," fi case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) $my_pic_p && pic_flag_for_symtable=" $pic_flag" ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for '$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $debug_cmd win32_libid_type=unknown win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || func_cygming_gnu_implib_p "$1" then win32_nmres=import else win32_nmres= fi ;; *) func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s|.*|import| p q } }'` ;; esac case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $debug_cmd sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $debug_cmd match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive that possess that section. Heuristic: eliminate # all those that have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $debug_cmd if func_cygming_gnu_implib_p "$1"; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1"; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result= fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $debug_cmd f_ex_an_ar_dir=$1; shift f_ex_an_ar_oldlib=$1 if test yes = "$lock_old_archive_extraction"; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test yes = "$lock_old_archive_extraction"; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $debug_cmd my_gentop=$1; shift my_oldlibs=${1+"$@"} my_oldobjs= my_xlib= my_xabs= my_xdir= for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib=$func_basename_result my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir=$my_gentop/$my_xlib_u func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` func_basename "$darwin_archive" darwin_base_archive=$func_basename_result darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches; do func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" cd "unfat-$$/$darwin_base_archive-$darwin_arch" func_extract_an_archive "`pwd`" "$darwin_base_archive" cd "$darwin_curdir" $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result=$my_oldobjs } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # 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+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ that is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options that match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test yes = "$fast_install"; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else \$ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined other_platform || defined ... */ #endif /* portability defines, excluding path handling macros */ #if defined _MSC_VER # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC #elif defined __MINGW32__ # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined __CYGWIN__ # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined other platforms ... */ #endif #if defined PATH_MAX # define LT_PATHMAX PATH_MAX #elif defined MAXPATHLEN # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ defined __OS2__ # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free (stale); stale = 0; } \ } while (0) #if defined LT_DEBUGWRAPPER static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; size_t tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined HAVE_DOS_BASED_FILE_SYSTEM if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined HAVE_DOS_BASED_FILE_SYSTEM } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = (size_t) (q - p); p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (STREQ (str, pat)) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else size_t len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { size_t orig_value_len = strlen (orig_value); size_t add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ size_t len = strlen (new_value); while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[--len] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $debug_cmd case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_suncc_cstd_abi # !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! # Several compiler flags select an ABI that is incompatible with the # Cstd library. Avoid specifying it if any are in CXXFLAGS. func_suncc_cstd_abi () { $debug_cmd case " $compile_command " in *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) suncc_use_cstd_abi=no ;; *) suncc_use_cstd_abi=yes ;; esac } # func_mode_link arg... func_mode_link () { $debug_cmd case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll that has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= os2dllname= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=false prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module=$wl-single_module func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test yes != "$build_libtool_libs" \ && func_fatal_configuration "cannot build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg=$1 shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir=$arg prev= continue ;; dlfiles|dlprefiles) $preload || { # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=: } case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test no = "$dlself"; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test dlprefiles = "$prev"; then dlself=yes elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test dlfiles = "$prev"; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols=$arg test -f "$arg" \ || func_fatal_error "symbol file '$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex=$arg prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir=$arg prev= continue ;; mllvm) # Clang does not use LLVM to link, so we can simply discard any # '-mllvm $arg' options when doing the link step. prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result if test none != "$pic_object"; then # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object fi # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file '$arg' does not exist" fi arg=$save_arg prev= continue ;; os2dllname) os2dllname=$arg prev= continue ;; precious_regex) precious_files_regex=$arg prev= continue ;; release) release=-$arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test rpath = "$prev"; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds=$arg prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg=$arg case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "'-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test X-export-symbols = "X$arg"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between '-L' and '$1'" else func_fatal_error "need path for '-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of '$dir'" dir=$absdir ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test X-lc = "X$arg" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test X-lc = "X$arg" && continue ;; esac elif test X-lc_r = "X$arg"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -mllvm) prev=mllvm continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module=$wl-multi_module continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "'-no-install' is ignored for $host" func_warning "assuming '-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -os2dllname) prev=os2dllname continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # -fstack-protector* stack protector flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -stdlib=* select c++ std lib with clang -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; -Z*) if test os2 = "`expr $host : '.*\(os2\)'`"; then # OS/2 uses -Zxxx to specify OS/2-specific options compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case $arg in -Zlinker | -Zstack) prev=xcompiler ;; esac continue else # Otherwise treat like 'Some other compiler flag' below func_quote_for_eval "$arg" arg=$func_quote_for_eval_result fi ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result test none = "$pic_object" || { # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object } # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test dlfiles = "$prev"; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test dlprefiles = "$prev"; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the '$prevarg' option requires an argument" if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname=$func_basename_result libobjs_save=$libobjs if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" # Definition is injected by LT_CONFIG during libtool generation. func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" func_dirname "$output" "/" "" output_objdir=$func_dirname_result$objdir func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test lib = "$linkmode"; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=false newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test lib,link = "$linkmode,$pass"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs=$tmp_deplibs fi if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass"; then libs=$deplibs deplibs= fi if test prog = "$linkmode"; then case $pass in dlopen) libs=$dlfiles ;; dlpreopen) libs=$dlprefiles ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test lib,dlpreopen = "$linkmode,$pass"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs=$dlprefiles fi if test dlopen = "$pass"; then # Collect dlpreopened libraries save_deplibs=$deplibs deplibs= fi for deplib in $libs; do lib= found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test lib != "$linkmode" && test prog != "$linkmode"; then func_warning "'-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test lib = "$linkmode"; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib=$searchdir/lib$name$search_ext if test -f "$lib"; then if test .la = "$search_ext"; then found=: else found=false fi break 2 fi done done if $found; then # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll=$l done if test "X$ll" = "X$old_library"; then # only static version available found=false func_dirname "$lib" "" "." ladir=$func_dirname_result lib=$ladir/$old_library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi else # deplib doesn't seem to be a libtool library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l *.ltframework) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test conv = "$pass" && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi if test scan = "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "'-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test link = "$pass"; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=false case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=: fi ;; pass_all) valid_a_lib=: ;; esac if $valid_a_lib; then echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" else echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." fi ;; esac continue ;; prog) if test link != "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test conv = "$pass"; then deplibs="$deplib $deplibs" elif test prog = "$linkmode"; then if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=: continue ;; esac # case $deplib $found || test -f "$lib" \ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "'$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir=$func_dirname_result dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass" || { test prog != "$linkmode" && test lib != "$linkmode"; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test conv = "$pass"; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for '$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" elif test prog != "$linkmode" && test lib != "$linkmode"; then func_fatal_error "'$lib' is not a convenience library" fi tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test yes = "$prefer_static_libs" || test built,no = "$prefer_static_libs,$installed"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib=$l done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for '$lib'" fi # This library was specified with -dlopen. if test dlopen = "$pass"; then test -z "$libdir" \ && func_fatal_error "cannot -dlopen a convenience library: '$lib'" if test -z "$dlname" || test yes != "$dlopen_support" || test no = "$build_libtool_libs" then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of '$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir=$ladir fi ;; esac func_basename "$lib" laname=$func_basename_result # Find the relevant object directory and library name. if test yes = "$installed"; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library '$lib' was moved." dir=$ladir absdir=$abs_ladir libdir=$abs_ladir else dir=$lt_sysroot$libdir absdir=$lt_sysroot$libdir fi test yes = "$hardcode_automatic" && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir=$ladir absdir=$abs_ladir # Remove this search path later func_append notinst_path " $abs_ladir" else dir=$ladir/$objdir absdir=$abs_ladir/$objdir # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test dlpreopen = "$pass"; then if test -z "$libdir" && test prog = "$linkmode"; then func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" fi case $host in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test lib = "$linkmode"; then deplibs="$dir/$old_library $deplibs" elif test prog,link = "$linkmode,$pass"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test prog = "$linkmode" && test link != "$pass"; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=false if test no != "$link_all_deplibs" || test -z "$library_names" || test no = "$build_libtool_libs"; then linkalldeplibs=: fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if $linkalldeplibs; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test prog,link = "$linkmode,$pass"; then if test -n "$library_names" && { { test no = "$prefer_static_libs" || test built,yes = "$prefer_static_libs,$installed"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then # Make sure the rpath contains only unique directories. case $temp_rpath: in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if $alldeplibs && { test pass_all = "$deplibs_check_method" || { test yes = "$build_libtool_libs" && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test built = "$use_static_libs" && test yes = "$installed"; then use_static_libs=no fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc* | *os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test no = "$installed"; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule= for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule=$dlpremoduletest break fi done if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test lib = "$linkmode" && test yes = "$hardcode_into_libs"; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname=$1 shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname=$dlname elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc* | *os2*) func_arith $current - $age major=$func_arith_result versuffix=-$major ;; esac eval soname=\"$soname_spec\" else soname=$realname fi # Make a new name for the extract_expsyms_cmds to use soroot=$soname func_basename "$soroot" soname=$func_basename_result func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from '$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for '$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test prog = "$linkmode" || test relink != "$opt_mode"; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test no = "$hardcode_direct"; then add=$dir/$linklib case $host in *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; *-*-sysv4*uw2*) add_dir=-L$dir ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir=-L$dir ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we cannot # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library"; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add=$dir/$old_library fi elif test -n "$old_library"; then add=$dir/$old_library fi fi esac elif test no = "$hardcode_minus_L"; then case $host in *-*-sunos*) add_shlibpath=$dir ;; esac add_dir=-L$dir add=-l$name elif test no = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; relink) if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$dir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$absdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name elif test yes = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; *) lib_linked=no ;; esac if test yes != "$lib_linked"; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test prog = "$linkmode"; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test yes != "$hardcode_direct" && test yes != "$hardcode_minus_L" && test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test prog = "$linkmode" || test relink = "$opt_mode"; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$libdir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$libdir add=-l$name elif test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add=-l$name elif test yes = "$hardcode_automatic"; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib"; then add=$inst_prefix_dir$libdir/$linklib else add=$libdir/$linklib fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir=-L$libdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name fi if test prog = "$linkmode"; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test prog = "$linkmode"; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test unsupported != "$hardcode_direct"; then test -n "$old_library" && linklib=$old_library compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test yes = "$build_libtool_libs"; then # Not a shared library if test pass_all != "$deplibs_check_method"; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system cannot link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test yes = "$module"; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test lib = "$linkmode"; then if test -n "$dependency_libs" && { test yes != "$hardcode_into_libs" || test yes = "$build_old_libs" || test yes = "$link_static"; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs=$temp_deplibs fi func_append newlib_search_path " $absdir" # Link against this library test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test no != "$link_all_deplibs"; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path=$deplib ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of '$dir'" absdir=$dir fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names"; then for tmp in $deplibrary_names; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl"; then depdepl=$absdir/$objdir/$depdepl darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" path= fi fi ;; *) path=-L$absdir/$objdir ;; esac else eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "'$deplib' seems to be moved" path=-L$absdir fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test link = "$pass"; then if test prog = "$linkmode"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs=$newdependency_libs if test dlpreopen = "$pass"; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test dlopen != "$pass"; then test conv = "$pass" || { # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= } if test prog,link = "$linkmode,$pass"; then vars="compile_deplibs finalize_deplibs" else vars=deplibs fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Add Sun CC postdeps if required: test CXX = "$tagname" && { case $host_os in linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; solaris*) func_cc_basename "$CC" case $func_cc_basename_result in CC* | sunCC*) func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; esac } # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i= ;; esac if test -n "$i"; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test prog = "$linkmode"; then dlfiles=$newdlfiles fi if test prog = "$linkmode" || test lib = "$linkmode"; then dlprefiles=$newdlprefiles fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "'-R' is ignored for archives" test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "'-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "'-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs=$output func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form 'libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test no = "$module" \ && func_fatal_help "libtool library '$output' must begin with 'lib'" if test no != "$need_lib_prefix"; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test pass_all != "$deplibs_check_method"; then func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test no = "$dlself" \ || func_warning "'-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test 1 -lt "$#" \ && func_warning "ignoring multiple '-rpath's for a libtool library" install_libdir=$1 oldlibs= if test -z "$rpath"; then if test yes = "$build_libtool_libs"; then # Building a libtool convenience library. # Some compilers have problems with a '.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "'-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs=$IFS; IFS=: set dummy $vinfo 0 0 0 shift IFS=$save_ifs test -n "$7" && \ func_fatal_help "too many parameters to '-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major=$1 number_minor=$2 number_revision=$3 # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # that has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|freebsd-elf|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; freebsd-aout|qnx|sunos) current=$number_major revision=$number_minor age=0 ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_minor lt_irix_increment=no ;; esac ;; no) current=$1 revision=$2 age=$3 ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT '$current' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION '$revision' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE '$age' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE '$age' is greater than the current interface number '$current'" func_fatal_error "'$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" # On Darwin other compilers case $CC in nagfor*) verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" ;; *) verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; esac ;; freebsd-aout) major=.$current versuffix=.$current.$revision ;; freebsd-elf) func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; irix | nonstopux) if test no = "$lt_irix_increment"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring=$verstring_prefix$major.$revision # Add in all the interfaces that we are compatible with. loop=$revision while test 0 -ne "$loop"; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring_prefix$major.$iface:$verstring done # Before this point, $major must not contain '.'. major=.$major versuffix=$major.$revision ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=.$current.$age.$revision verstring=$current.$age.$revision # Add in all the interfaces that we are compatible with. loop=$age while test 0 -ne "$loop"; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring:$iface.0 done # Make executables depend on our current version. func_append verstring ":$current.0" ;; qnx) major=.$current versuffix=.$current ;; sco) major=.$current versuffix=.$current ;; sunos) major=.$current versuffix=.$current.$revision ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 file systems. func_arith $current - $age major=$func_arith_result versuffix=-$major ;; *) func_fatal_configuration "unknown library version type '$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring=0.0 ;; esac if test no = "$need_version"; then versuffix= else versuffix=.0.0 fi fi # Remove version info from name if versioning should be avoided if test yes,no = "$avoid_version,$need_version"; then major= versuffix= verstring= fi # Check to see if the archive will have undefined symbols. if test yes = "$allow_undefined"; then if test unsupported = "$allow_undefined_flag"; then if test yes = "$build_old_libs"; then func_warning "undefined symbols not allowed in $host shared libraries; building static only" build_libtool_libs=no else func_fatal_error "can't build $host shared library unless -no-undefined is specified" fi fi else # Don't allow undefined symbols. allow_undefined_flag=$no_undefined_flag fi fi func_generate_dlsyms "$libname" "$libname" : func_append libobjs " $symfileobj" test " " = "$libobjs" && libobjs= if test relink != "$opt_mode"; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) if test -n "$precious_files_regex"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles=$dlfiles dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles=$dlprefiles dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test yes = "$build_libtool_libs"; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test yes = "$build_libtool_need_lc"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release= versuffix= major= newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib=$potent_lib while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | $SED 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib= ;; esac fi if test -n "$a_deplib"; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib=$potent_lib # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs= tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test yes = "$allow_libtool_libs_with_static_runtimes"; then for i in $predeps $postdeps; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test none = "$deplibs_check_method"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test yes = "$droppeddeps"; then if test yes = "$module"; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test no = "$allow_undefined"; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs=$new_libs # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test yes = "$build_libtool_libs"; then # Remove $wl instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test yes = "$hardcode_into_libs"; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath=$finalize_rpath test relink = "$opt_mode" || rpath=$compile_rpath$rpath for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath=$finalize_shlibpath test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname=$1 shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname=$realname fi if test -z "$dlname"; then dlname=$soname fi lib=$output_objdir/$realname linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols=$output_objdir/$libname.uexp func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile func_dll_def_p "$export_symbols" || { # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols=$export_symbols export_symbols= always_export_symbols=yes } fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs=$IFS; IFS='~' for cmd1 in $cmds; do IFS=$save_ifs # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test yes = "$try_normal_branch" \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=$output_objdir/$output_la.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS=$save_ifs if test -n "$export_symbols_regex" && test : != "$skipped_export"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test : != "$skipped_export" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs=$tmp_deplibs if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test yes = "$compiler_needs_object" && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test : != "$skipped_export" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then output=$output_objdir/$output_la.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then output=$output_objdir/$output_la.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test yes = "$compiler_needs_object"; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-$k.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test -z "$objlist" || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test 1 -eq "$k"; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-$k.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-$k.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi ${skipped_export-false} && { func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi } test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs=$IFS; IFS='~' for cmd in $concat_cmds; do IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi ${skipped_export-false} && { if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi } libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs=$IFS; IFS='~' for cmd in $cmds; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs # Restore the uninstalled library and exit if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test yes = "$module" || test yes = "$export_dynamic"; then # On all known operating systems, these are identical. dlname=$soname fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "'-R' is ignored for objects" test -n "$vinfo" && \ func_warning "'-version-info' is ignored for objects" test -n "$release" && \ func_warning "'-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object '$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj=$output ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # if reload_cmds runs $LD directly, get rid of -Wl from # whole_archive_flag_spec and hope we can get by with turning comma # into space. case $reload_cmds in *\$LD[\ \$]*) wl= ;; esac if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags else gentop=$output_objdir/${obj}x func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test yes = "$build_libtool_libs" || libobjs=$non_pic_objects # Create the old-style object. reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs output=$obj func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi test yes = "$build_libtool_libs" || { if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS } if test -n "$pic_flag" || test default != "$pic_mode"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output=$libobj func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "'-version-info' is ignored for programs" test -n "$release" && \ func_warning "'-release' is ignored for programs" $preload \ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test CXX = "$tagname"; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " $wl-bind_at_load" func_append finalize_command " $wl-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs=$new_libs func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath=$rpath rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath=$rpath if test -n "$libobjs" && test yes = "$build_old_libs"; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" false # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=: case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=false ;; *cygwin* | *mingw* ) test yes = "$build_libtool_libs" || wrappers_required=false ;; *) if test no = "$need_relink" || test yes != "$build_libtool_libs"; then wrappers_required=false fi ;; esac $wrappers_required || { # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command=$compile_command$compile_rpath # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.$objext"; then func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' fi exit $exit_status } if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test yes = "$no_install"; then # We don't need to create a wrapper script. link_command=$compile_var$compile_command$compile_rpath # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi case $hardcode_action,$fast_install in relink,*) # Fast installation is not supported link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath func_warning "this platform does not like uninstalled shared libraries" func_warning "'$output' will be relinked during installation" ;; *,yes) link_command=$finalize_var$compile_command$finalize_rpath relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` ;; *,no) link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath ;; *,needless) link_command=$finalize_var$compile_command$finalize_rpath relink_command= ;; esac # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource=$output_path/$objdir/lt-$output_name.c cwrapper=$output_path/$output_name.exe $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host"; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do case $build_libtool_libs in convenience) oldobjs="$libobjs_save $symfileobj" addlibs=$convenience build_libtool_libs=no ;; module) oldobjs=$libobjs_save addlibs=$old_convenience build_libtool_libs=no ;; *) oldobjs="$old_deplibs $non_pic_objects" $preload && test -f "$symfileobj" \ && func_append oldobjs " $symfileobj" addlibs=$old_convenience ;; esac if test -n "$addlibs"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase=$func_basename_result case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj"; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test -z "$oldobjs"; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test yes = "$build_old_libs" && old_library=$libname.$libext func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test yes = "$hardcode_automatic"; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test yes = "$installed"; then if test -z "$install_libdir"; then break fi output=$output_objdir/${outputname}i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name=$func_basename_result func_resolve_sysroot "$deplib" eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs=$newdependency_libs newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles=$newdlprefiles else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles=$newdlprefiles fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test -n "$bindir"; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result/$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that cannot go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test no,yes = "$installed,$need_relink"; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } if test link = "$opt_mode" || test relink = "$opt_mode"; then func_mode_link ${1+"$@"} fi # func_mode_uninstall arg... func_mode_uninstall () { $debug_cmd RM=$nonopt files= rmforce=false exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic for arg do case $arg in -f) func_append RM " $arg"; rmforce=: ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir=$func_dirname_result if test . = "$dir"; then odir=$objdir else odir=$dir/$objdir fi func_basename "$file" name=$func_basename_result test uninstall = "$opt_mode" && odir=$dir # Remember odir for removal later, being careful to avoid duplicates if test clean = "$opt_mode"; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif $rmforce; then continue fi rmfiles=$file case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case $opt_mode in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test none != "$pic_object"; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test none != "$non_pic_object"; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test clean = "$opt_mode"; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.$objext" if test yes = "$fast_install" && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name"; then func_append rmfiles " $odir/lt-$noexename.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the $objdir's in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then func_mode_uninstall ${1+"$@"} fi test -z "$opt_mode" && { help=$generic_help func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode '$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # where we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: quagga-1.2.4/m4/000077500000000000000000000000001325323223500133035ustar00rootroot00000000000000quagga-1.2.4/m4/Makefile.am000066400000000000000000000000421325323223500153330ustar00rootroot00000000000000EXTRA_DIST=Makefile.am README.txt quagga-1.2.4/m4/Makefile.in000066400000000000000000000323171325323223500153560ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = Makefile.am README.txt all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu m4/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu m4/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # 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: quagga-1.2.4/m4/README.txt000066400000000000000000000007721325323223500150070ustar00rootroot00000000000000This directory contains local additions to/overrides for the Quagga autoconf build system. At this time additions are: - m4 files taken from libtool CVS circa august 2004. These have been imported into Quagga as they are more robust with respect to configuring libtool support for languages which Quagga does not use. As and when libtool releases become commonly available with that capability, these can be removed. The files are: argz.m4 libtool.m4 ltdl.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 quagga-1.2.4/m4/ax_sys_weak_alias.m4000066400000000000000000000271571325323223500172470ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_sys_weak_alias.html # =========================================================================== # # SYNOPSIS # # AX_SYS_WEAK_ALIAS # # DESCRIPTION # # Determines whether weak aliases are supported on the system, and if so, # what scheme is used to declare them. Also checks to see if aliases can # cross object file boundaries, as some systems don't permit them to. # # Most systems permit something called a "weak alias" or "weak symbol." # These aliases permit a library to provide a stub form of a routine # defined in another library, thus allowing the first library to operate # even if the other library is not linked. This macro will check for # support of weak aliases, figure out what schemes are available, and # determine some characteristics of the weak alias support -- primarily, # whether a weak alias declared in one object file may be referenced from # another object file. # # There are four known schemes of declaring weak symbols; each scheme is # checked in turn, and the first one found is prefered. Note that only one # of the mentioned preprocessor macros will be defined! # # 1. Function attributes # # This scheme was first introduced by the GNU C compiler, and attaches # attributes to particular functions. It is among the easiest to use, and # so is the first one checked. If this scheme is detected, the # preprocessor macro HAVE_SYS_WEAK_ALIAS_ATTRIBUTE will be defined to 1. # This scheme is used as in the following code fragment: # # void __weakf(int c) # { # /* Function definition... */ # } # # void weakf(int c) __attribute__((weak, alias("__weakf"))); # # 2. #pragma weak # # This scheme is in use by many compilers other than the GNU C compiler. # It is also particularly easy to use, and fairly portable -- well, as # portable as these things get. If this scheme is detected first, the # preprocessor macro HAVE_SYS_WEAK_ALIAS_PRAGMA will be defined to 1. This # scheme is used as in the following code fragment: # # extern void weakf(int c); # #pragma weak weakf = __weakf # void __weakf(int c) # { # /* Function definition... */ # } # # 3. #pragma _HP_SECONDARY_DEF # # This scheme appears to be in use by the HP compiler. As it is rather # specialized, this is one of the last schemes checked. If it is the first # one detected, the preprocessor macro HAVE_SYS_WEAK_ALIAS_HPSECONDARY # will be defined to 1. This scheme is used as in the following code # fragment: # # extern void weakf(int c); # #pragma _HP_SECONDARY_DEF __weakf weakf # void __weakf(int c) # { # /* Function definition... */ # } # # 4. #pragma _CRI duplicate # # This scheme appears to be in use by the Cray compiler. As it is rather # specialized, it too is one of the last schemes checked. If it is the # first one detected, the preprocessor macro # HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE will be defined to 1. This scheme is # used as in the following code fragment: # # extern void weakf(int c); # #pragma _CRI duplicate weakf as __weakf # void __weakf(int c) # { # /* Function definition... */ # } # # In addition to the preprocessor macros listed above, if any scheme is # found, the preprocessor macro HAVE_SYS_WEAK_ALIAS will also be defined # to 1. # # Once a weak aliasing scheme has been found, a check will be performed to # see if weak aliases are honored across object file boundaries. If they # are, the HAVE_SYS_WEAK_ALIAS_CROSSFILE preprocessor macro is defined to # 1. # # This Autoconf macro also makes two substitutions. The first, WEAK_ALIAS, # contains the name of the scheme found (one of "attribute", "pragma", # "hpsecondary", or "criduplicate"), or "no" if no weak aliasing scheme # was found. The second, WEAK_ALIAS_CROSSFILE, is set to "yes" or "no" # depending on whether or not weak aliases may cross object file # boundaries. # # LICENSE # # Copyright (c) 2008 Kevin L. Mitchell # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AU_ALIAS([KLM_SYS_WEAK_ALIAS], [AX_SYS_WEAK_ALIAS]) AC_DEFUN([AX_SYS_WEAK_ALIAS], [ # starting point: no aliasing scheme yet... ax_sys_weak_alias=no # Figure out what kind of aliasing may be supported... _AX_SYS_WEAK_ALIAS_ATTRIBUTE _AX_SYS_WEAK_ALIAS_PRAGMA _AX_SYS_WEAK_ALIAS_HPSECONDARY _AX_SYS_WEAK_ALIAS_CRIDUPLICATE # Do we actually support aliasing? AC_CACHE_CHECK([how to create weak aliases with $CC], [ax_cv_sys_weak_alias], [ax_cv_sys_weak_alias=$ax_sys_weak_alias]) # OK, set a #define AS_IF([test $ax_cv_sys_weak_alias != no], [ AC_DEFINE([HAVE_SYS_WEAK_ALIAS], 1, [Define this if your system can create weak aliases]) ]) # Can aliases cross object file boundaries? _AX_SYS_WEAK_ALIAS_CROSSFILE # OK, remember the results AC_SUBST([WEAK_ALIAS], [$ax_cv_sys_weak_alias]) AC_SUBST([WEAK_ALIAS_CROSSFILE], [$ax_cv_sys_weak_alias_crossfile]) ]) AC_DEFUN([_AX_SYS_WEAK_ALIAS_ATTRIBUTE], [ # Test whether compiler accepts __attribute__ form of weak aliasing AC_CACHE_CHECK([whether $CC accepts function __attribute__((weak,alias()))], [ax_cv_sys_weak_alias_attribute], [ # We add -Werror if it's gcc to force an error exit if the weak attribute # isn't understood AS_IF([test $GCC = yes], [ save_CFLAGS=$CFLAGS CFLAGS=-Werror]) # Try linking with a weak alias... AC_LINK_IFELSE([ AC_LANG_PROGRAM([ void __weakf(int c) {} void weakf(int c) __attribute__((weak, alias("__weakf")));], [weakf(0)])], [ax_cv_sys_weak_alias_attribute=yes], [ax_cv_sys_weak_alias_attribute=no]) # Restore original CFLAGS AS_IF([test $GCC = yes], [ CFLAGS=$save_CFLAGS]) ]) # What was the result of the test? AS_IF([test $ax_cv_sys_weak_alias_attribute = yes], [ test $ax_sys_weak_alias = no && ax_sys_weak_alias=attribute AC_DEFINE([HAVE_SYS_WEAK_ALIAS_ATTRIBUTE], 1, [Define this if weak aliases may be created with __attribute__]) ]) ]) AC_DEFUN([_AX_SYS_WEAK_ALIAS_PRAGMA], [ # Test whether compiler accepts #pragma form of weak aliasing AC_CACHE_CHECK([whether $CC supports @%:@pragma weak], [ax_cv_sys_weak_alias_pragma], [ # Try linking with a weak alias... AC_LINK_IFELSE([ AC_LANG_PROGRAM([ extern void weakf(int c); @%:@pragma weak weakf = __weakf void __weakf(int c) {}], [weakf(0)])], [ax_cv_sys_weak_alias_pragma=yes], [ax_cv_sys_weak_alias_pragma=no]) ]) # What was the result of the test? AS_IF([test $ax_cv_sys_weak_alias_pragma = yes], [ test $ax_sys_weak_alias = no && ax_sys_weak_alias=pragma AC_DEFINE([HAVE_SYS_WEAK_ALIAS_PRAGMA], 1, [Define this if weak aliases may be created with @%:@pragma weak]) ]) ]) AC_DEFUN([_AX_SYS_WEAK_ALIAS_HPSECONDARY], [ # Test whether compiler accepts _HP_SECONDARY_DEF pragma from HP... AC_CACHE_CHECK([whether $CC supports @%:@pragma _HP_SECONDARY_DEF], [ax_cv_sys_weak_alias_hpsecondary], [ # Try linking with a weak alias... AC_LINK_IFELSE([ AC_LANG_PROGRAM([ extern void weakf(int c); @%:@pragma _HP_SECONDARY_DEF __weakf weakf void __weakf(int c) {}], [weakf(0)])], [ax_cv_sys_weak_alias_hpsecondary=yes], [ax_cv_sys_weak_alias_hpsecondary=no]) ]) # What was the result of the test? AS_IF([test $ax_cv_sys_weak_alias_hpsecondary = yes], [ test $ax_sys_weak_alias = no && ax_sys_weak_alias=hpsecondary AC_DEFINE([HAVE_SYS_WEAK_ALIAS_HPSECONDARY], 1, [Define this if weak aliases may be created with @%:@pragma _HP_SECONDARY_DEF]) ]) ]) AC_DEFUN([_AX_SYS_WEAK_ALIAS_CRIDUPLICATE], [ # Test whether compiler accepts "_CRI duplicate" pragma from Cray AC_CACHE_CHECK([whether $CC supports @%:@pragma _CRI duplicate], [ax_cv_sys_weak_alias_criduplicate], [ # Try linking with a weak alias... AC_LINK_IFELSE([ AC_LANG_PROGRAM([ extern void weakf(int c); @%:@pragma _CRI duplicate weakf as __weakf void __weakf(int c) {}], [weakf(0)])], [ax_cv_sys_weak_alias_criduplicate=yes], [ax_cv_sys_weak_alias_criduplicate=no]) ]) # What was the result of the test? AS_IF([test $ax_cv_sys_weak_alias_criduplicate = yes], [ test $ax_sys_weak_alias = no && ax_sys_weak_alias=criduplicate AC_DEFINE([HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE], 1, [Define this if weak aliases may be created with @%:@pragma _CRI duplicate]) ]) ]) dnl Note: This macro is modeled closely on AC_LINK_IFELSE, and in fact dnl depends on some implementation details of that macro, particularly dnl its use of _AC_MSG_LOG_CONFTEST to log the failed test program and dnl its use of ac_link for running the linker. AC_DEFUN([_AX_SYS_WEAK_ALIAS_CROSSFILE], [ # Check to see if weak aliases can cross object file boundaries AC_CACHE_CHECK([whether $CC supports weak aliases across object file boundaries], [ax_cv_sys_weak_alias_crossfile], [ AS_IF([test $ax_cv_sys_weak_alias = no], [ax_cv_sys_weak_alias_crossfile=no], [ dnl Must build our own test files... # conftest1 contains our weak alias definition... cat >conftest1.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest1.$ac_ext cat >>conftest1.$ac_ext <<_ACEOF /* end confdefs.h. */ @%:@ifndef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE extern void weakf(int c); @%:@if defined(HAVE_SYS_WEAK_ALIAS_PRAGMA) @%:@pragma weak weakf = __weakf @%:@elif defined(HAVE_SYS_WEAK_ALIAS_HPSECONDARY) @%:@pragma _HP_SECONDARY_DEF __weakf weakf @%:@elif defined(HAVE_SYS_WEAK_ALIAS_CRIDUPLICATE) @%:@pragma _CRI duplicate weakf as __weakf @%:@endif @%:@endif void __weakf(int c) {} @%:@ifdef HAVE_SYS_WEAK_ALIAS_ATTRIBUTE void weakf(int c) __attribute((weak, alias("__weakf"))); @%:@endif _ACEOF # And conftest2 contains our main routine that calls it cat >conftest2.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >> conftest2.$ac_ext cat >>conftest2.$ac_ext <<_ACEOF /* end confdefs.h. */ extern void weakf(int c); int main () { weakf(0); return 0; } _ACEOF # We must remove the object files (if any) ourselves... rm -f conftest2.$ac_objext conftest$ac_exeext # Change ac_link to compile *2* files together save_aclink=$ac_link ac_link=`echo "$ac_link" | \ sed -e 's/conftest\(\.\$ac_ext\)/conftest1\1 conftest2\1/'` dnl Substitute our own routine for logging the conftest m4_pushdef([_AC_MSG_LOG_CONFTEST], [echo "$as_me: failed program was:" >&AS_MESSAGE_LOG_FD echo ">>> conftest1.$ac_ext" >&AS_MESSAGE_LOG_FD sed "s/^/| /" conftest1.$ac_ext >&AS_MESSAGE_LOG_FD echo ">>> conftest2.$ac_ext" >&AS_MESSAGE_LOG_FD sed "s/^/| /" conftest2.$ac_ext >&AS_MESSAGE_LOG_FD ])dnl # Since we created the files ourselves, don't use SOURCE argument AC_LINK_IFELSE(, [ax_cv_sys_weak_alias_crossfile=yes], [ax_cv_sys_weak_alias_crossfile=no]) dnl Restore _AC_MSG_LOG_CONFTEST m4_popdef([_AC_MSG_LOG_CONFTEST])dnl # Restore ac_link ac_link=$save_aclink # We must remove the object files (if any) and C files ourselves... rm -f conftest1.$ac_ext conftest2.$ac_ext \ conftest1.$ac_objext conftest2.$ac_objext ]) ]) # What were the results of the test? AS_IF([test $ax_cv_sys_weak_alias_crossfile = yes], [ AC_DEFINE([HAVE_SYS_WEAK_ALIAS_CROSSFILE], 1, [Define this if weak aliases in other files are honored]) ]) ]) quagga-1.2.4/m4/libtool.m4000066400000000000000000011253061325323223500152210ustar00rootroot00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # 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. m4_define([_LT_COPYING], [dnl # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ]) # serial 58 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from 'configure', and 'config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # 'config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain=$ac_aux_dir/ltmain.sh ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the 'libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to 'config.status' so that its # declaration there will have the same value as in 'configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags='_LT_TAGS'dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into 'config.status', and then the shell code to quote escape them in # for loops in 'config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # '#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test 0 = "$lt_write_fail" && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -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 Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $[#] do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try '$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try '$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS=$save_LDFLAGS ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[[012]][[,.]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test yes = "$lt_cv_ld_force_load"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], [ if test yes != "$lt_cv_apple_cc_single_mod"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script that will find a shell with a builtin # printf (that we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case $ECHO in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot if not specified).])], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([$with_sysroot]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and where our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS ]) if test yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n "$lt_cv_sys_max_cmd_len"; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes = "$cross_compiling"; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen=shl_load], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen=dlopen], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) ]) ]) ]) ]) ]) ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links=nottested if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test no = "$hard_links"; then AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", [Define to the sub-directory where libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Add ABI-specific directories to the system library path. sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$1"; then lt_cv_path_MAGIC_CMD=$ac_dir/"$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac]) MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program that can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi]) if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM=-lm) ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test yes = "$GCC"; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([nm_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test yes = "$GCC"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS=$save_LDFLAGS]) if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; osf3*) if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test yes,yes = "$GCC,$enable_shared"; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC=$CC AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report what library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC=$lt_save_CC ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(GCC, $1)=$GXX _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)=$p else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)=$p else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test no = "$F77"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_F77"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$G77 _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_F77" AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test no = "$FC"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_FC"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_FC" AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code=$lt_simple_compile_test_code # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f "$lt_ac_sed" && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test 10 -lt "$lt_ac_count" && break lt_ac_count=`expr $lt_ac_count + 1` if test "$lt_ac_count" -gt "$lt_ac_max"; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS quagga-1.2.4/m4/ltoptions.m4000066400000000000000000000342621325323223500156070ustar00rootroot00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # 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. # serial 8 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option '$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl 'shared' nor 'disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the 'shared' and # 'disable-shared' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the 'static' and # 'disable-static' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the 'fast-install' # and 'disable-fast-install' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac], [pic_mode=m4_default([$1], [default])]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) quagga-1.2.4/m4/ltsugar.m4000066400000000000000000000104401325323223500152250ustar00rootroot00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # 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. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59, which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) quagga-1.2.4/m4/ltversion.m4000066400000000000000000000012731325323223500155750ustar00rootroot00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # 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. # @configure_input@ # serial 4179 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.6]) m4_define([LT_PACKAGE_REVISION], [2.4.6]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.6' macro_revision='2.4.6' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) quagga-1.2.4/m4/lt~obsolete.m4000066400000000000000000000137741325323223500161330ustar00rootroot00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software # Foundation, Inc. # Written by Scott James Remnant, 2004. # # 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. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) quagga-1.2.4/missing000077500000000000000000000153301325323223500143640ustar00rootroot00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2014 Free Software Foundation, Inc. # Originally written 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, see . # 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 case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: quagga-1.2.4/nhrpd/000077500000000000000000000000001325323223500140765ustar00rootroot00000000000000quagga-1.2.4/nhrpd/Makefile.am000066400000000000000000000015001325323223500161260ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DQUAGGA_NO_DEPRECATED_INTERFACES DEFS = @DEFS@ @CARES_CFLAGS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) #$(WERROR) AM_LDFLAGS = $(PICLDFLAGS) sbin_PROGRAMS = nhrpd nhrpd_SOURCES = \ zbuf.c \ znl.c \ resolver.c \ linux.c \ netlink_arp.c \ netlink_gre.c \ vici.c \ reqid.c \ nhrp_event.c \ nhrp_packet.c \ nhrp_interface.c \ nhrp_vc.c \ nhrp_peer.c \ nhrp_cache.c \ nhrp_nhs.c \ nhrp_route.c \ nhrp_shortcut.c \ nhrp_vty.c \ nhrp_main.c nhrpd_LDADD = ../lib/libzebra.la @LIBCAP@ @CARES_LIBS@ noinst_HEADERS = debug.h netlink.h nhrpd.h vici.h znl.h list.h \ nhrp_protocol.h os.h zbuf.h #dist_examples_DATA = nhrpd.conf.sample quagga-1.2.4/nhrpd/Makefile.in000066400000000000000000000553041325323223500161520ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = nhrpd$(EXEEXT) subdir = nhrpd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am_nhrpd_OBJECTS = zbuf.$(OBJEXT) znl.$(OBJEXT) resolver.$(OBJEXT) \ linux.$(OBJEXT) netlink_arp.$(OBJEXT) netlink_gre.$(OBJEXT) \ vici.$(OBJEXT) reqid.$(OBJEXT) nhrp_event.$(OBJEXT) \ nhrp_packet.$(OBJEXT) nhrp_interface.$(OBJEXT) \ nhrp_vc.$(OBJEXT) nhrp_peer.$(OBJEXT) nhrp_cache.$(OBJEXT) \ nhrp_nhs.$(OBJEXT) nhrp_route.$(OBJEXT) \ nhrp_shortcut.$(OBJEXT) nhrp_vty.$(OBJEXT) nhrp_main.$(OBJEXT) nhrpd_OBJECTS = $(am_nhrpd_OBJECTS) nhrpd_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(nhrpd_SOURCES) DIST_SOURCES = $(nhrpd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ @CARES_CFLAGS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DQUAGGA_NO_DEPRECATED_INTERFACES INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) #$(WERROR) AM_LDFLAGS = $(PICLDFLAGS) nhrpd_SOURCES = \ zbuf.c \ znl.c \ resolver.c \ linux.c \ netlink_arp.c \ netlink_gre.c \ vici.c \ reqid.c \ nhrp_event.c \ nhrp_packet.c \ nhrp_interface.c \ nhrp_vc.c \ nhrp_peer.c \ nhrp_cache.c \ nhrp_nhs.c \ nhrp_route.c \ nhrp_shortcut.c \ nhrp_vty.c \ nhrp_main.c nhrpd_LDADD = ../lib/libzebra.la @LIBCAP@ @CARES_LIBS@ noinst_HEADERS = debug.h netlink.h nhrpd.h vici.h znl.h list.h \ nhrp_protocol.h os.h zbuf.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu nhrpd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu nhrpd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list nhrpd$(EXEEXT): $(nhrpd_OBJECTS) $(nhrpd_DEPENDENCIES) $(EXTRA_nhrpd_DEPENDENCIES) @rm -f nhrpd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nhrpd_OBJECTS) $(nhrpd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlink_arp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlink_gre.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_event.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_nhs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_packet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_peer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_route.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_shortcut.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_vc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nhrp_vty.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reqid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vici.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zbuf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/znl.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool clean-sbinPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS .PRECIOUS: Makefile #dist_examples_DATA = nhrpd.conf.sample # 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: quagga-1.2.4/nhrpd/debug.h000066400000000000000000000016211325323223500153350ustar00rootroot00000000000000#include "log.h" #if defined(__GNUC__) && (__GNUC__ >= 3) #define likely(_x) __builtin_expect(!!(_x), 1) #define unlikely(_x) __builtin_expect(!!(_x), 0) #else #define likely(_x) !!(_x) #define unlikely(_x) !!(_x) #endif #define NHRP_DEBUG_COMMON (1 << 0) #define NHRP_DEBUG_KERNEL (1 << 1) #define NHRP_DEBUG_IF (1 << 2) #define NHRP_DEBUG_ROUTE (1 << 3) #define NHRP_DEBUG_VICI (1 << 4) #define NHRP_DEBUG_EVENT (1 << 5) #define NHRP_DEBUG_ALL (0xFFFF) extern unsigned int debug_flags; #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define debugf(level, ...) \ do { \ if (unlikely(debug_flags & level)) \ zlog_debug(__VA_ARGS__); \ } while(0) #elif defined __GNUC__ #define debugf(level, _args...) \ do { \ if (unlikely(debug_flags & level)) \ zlog_debug(_args); \ } while(0) #else static inline void debugf(int level, const char *format, ...) { } #endif quagga-1.2.4/nhrpd/linux.c000066400000000000000000000062031325323223500154020ustar00rootroot00000000000000/* NHRP daemon Linux specific glue * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nhrp_protocol.h" #include "os.h" #include "netlink.h" static int nhrp_socket_fd = -1; int os_socket(void) { if (nhrp_socket_fd < 0) nhrp_socket_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_NHRP)); return nhrp_socket_fd; } int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, size_t addrlen) { struct sockaddr_ll lladdr; struct iovec iov = { .iov_base = (void*) buf, .iov_len = len, }; struct msghdr msg = { .msg_name = &lladdr, .msg_namelen = sizeof(lladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int status; if (addrlen > sizeof(lladdr.sll_addr)) return -1; memset(&lladdr, 0, sizeof(lladdr)); lladdr.sll_family = AF_PACKET; lladdr.sll_protocol = htons(ETH_P_NHRP); lladdr.sll_ifindex = ifindex; lladdr.sll_halen = addrlen; memcpy(lladdr.sll_addr, addr, addrlen); status = sendmsg(nhrp_socket_fd, &msg, 0); if (status < 0) return -1; return 0; } int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr, size_t *addrlen) { struct sockaddr_ll lladdr; struct iovec iov = { .iov_base = buf, .iov_len = *len, }; struct msghdr msg = { .msg_name = &lladdr, .msg_namelen = sizeof(lladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int r; r = recvmsg(nhrp_socket_fd, &msg, MSG_DONTWAIT); if (r < 0) return r; *len = r; *ifindex = lladdr.sll_ifindex; if (*addrlen <= (size_t) lladdr.sll_addr) { if (memcmp(lladdr.sll_addr, "\x00\x00\x00\x00", 4) != 0) { memcpy(addr, lladdr.sll_addr, lladdr.sll_halen); *addrlen = lladdr.sll_halen; } else { *addrlen = 0; } } return 0; } static int linux_configure_arp(const char *iface, int on) { struct ifreq ifr; strncpy(ifr.ifr_name, iface, IFNAMSIZ); if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr)) return -1; if (on) ifr.ifr_flags &= ~IFF_NOARP; else ifr.ifr_flags |= IFF_NOARP; if (ioctl(nhrp_socket_fd, SIOCSIFFLAGS, &ifr)) return -1; return 0; } static int linux_icmp_redirect_off(const char *iface) { char fname[256]; int fd, ret = -1; sprintf(fname, "/proc/sys/net/ipv4/conf/%s/send_redirects", iface); fd = open(fname, O_WRONLY); if (fd < 0) return -1; if (write(fd, "0\n", 2) == 2) ret = 0; close(fd); return ret; } int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af) { int ret = 0; switch (af) { case AF_INET: ret |= linux_icmp_redirect_off("all"); ret |= linux_icmp_redirect_off(ifname); break; } ret |= linux_configure_arp(ifname, 1); ret |= netlink_configure_arp(ifindex, af); return ret; } quagga-1.2.4/nhrpd/list.h000066400000000000000000000110771325323223500152300ustar00rootroot00000000000000/* Linux kernel style list handling function * * Written from scratch by Timo Teräs , but modeled * after the linux kernel code. * * This file is free software: you may copy, redistribute 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. */ #ifndef LIST_H #define LIST_H #ifndef NULL #define NULL 0L #endif #ifndef offsetof #ifdef __compiler_offsetof #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) #else #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif #endif #ifndef container_of #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #endif struct hlist_head { struct hlist_node *first; }; struct hlist_node { struct hlist_node *next; struct hlist_node **pprev; }; static inline int hlist_empty(const struct hlist_head *h) { return !h->first; } static inline int hlist_hashed(const struct hlist_node *n) { return n->pprev != NULL; } static inline void hlist_del(struct hlist_node *n) { struct hlist_node *next = n->next; struct hlist_node **pprev = n->pprev; *pprev = next; if (next) next->pprev = pprev; n->next = NULL; n->pprev = NULL; } static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; n->pprev = &h->first; h->first = n; } static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *prev) { n->next = prev->next; n->pprev = &prev->next; prev->next = n; } static inline struct hlist_node **hlist_tail_ptr(struct hlist_head *h) { struct hlist_node *n = h->first; if (n == NULL) return &h->first; while (n->next != NULL) n = n->next; return &n->next; } #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ for (pos = (head)->first; pos; pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); pos = n) #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ for (pos = (head)->first; \ pos && ({ n = pos->next; 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = n) struct list_head { struct list_head *next, *prev; }; #define LIST_INITIALIZER(l) { .next = &l, .prev = &l } static inline void list_init(struct list_head *list) { list->next = list; list->prev = list; } static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = NULL; entry->prev = NULL; } static inline int list_hashed(const struct list_head *n) { return n->next != n && n->next != NULL; } static inline int list_empty(const struct list_head *n) { return !list_hashed(n); } #define list_next(ptr, type, member) \ (list_hashed(ptr) ? container_of((ptr)->next,type,member) : NULL) #define list_entry(ptr, type, member) container_of(ptr,type,member) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif quagga-1.2.4/nhrpd/netlink.h000066400000000000000000000015421325323223500157150ustar00rootroot00000000000000/* NHRP netlink/neighbor table API * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include union sockunion; struct interface; extern int netlink_nflog_group; extern int netlink_req_fd; int netlink_init(void); int netlink_configure_arp(unsigned int ifindex, int pf); void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma); void netlink_set_nflog_group(int nlgroup); void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, unsigned int *link_index, struct in_addr *saddr); void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index); quagga-1.2.4/nhrpd/netlink_arp.c000066400000000000000000000160621325323223500165550ustar00rootroot00000000000000/* NHRP netlink/neighbor table arpd code * Copyright (c) 2014-2016 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include "thread.h" #include "nhrpd.h" #include "netlink.h" #include "znl.h" int netlink_req_fd = -1; int netlink_nflog_group; static int netlink_log_fd = -1; static struct thread *netlink_log_thread; static int netlink_listen_fd = -1; typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb); void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma) { struct nlmsghdr *n; struct ndmsg *ndm; struct zbuf *zb = zbuf_alloc(512); n = znl_nlmsg_push(zb, nbma ? RTM_NEWNEIGH : RTM_DELNEIGH, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE); ndm = znl_push(zb, sizeof(*ndm)); *ndm = (struct ndmsg) { .ndm_family = sockunion_family(proto), .ndm_ifindex = ifp->ifindex, .ndm_type = RTN_UNICAST, .ndm_state = nbma ? NUD_REACHABLE : NUD_FAILED, }; znl_rta_push(zb, NDA_DST, sockunion_get_addr(proto), family2addrsize(sockunion_family(proto))); if (nbma) znl_rta_push(zb, NDA_LLADDR, sockunion_get_addr(nbma), family2addrsize(sockunion_family(nbma))); znl_nlmsg_complete(zb, n); zbuf_send(zb, netlink_req_fd); zbuf_recv(zb, netlink_req_fd); zbuf_free(zb); } static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb) { struct ndmsg *ndm; struct rtattr *rta; struct nhrp_cache *c; struct interface *ifp; struct zbuf payload; union sockunion addr; size_t len; char buf[SU_ADDRSTRLEN]; int state; ndm = znl_pull(zb, sizeof(*ndm)); if (!ndm) return; sockunion_family(&addr) = AF_UNSPEC; while ((rta = znl_rta_pull(zb, &payload)) != NULL) { len = zbuf_used(&payload); switch (rta->rta_type) { case NDA_DST: sockunion_set(&addr, ndm->ndm_family, zbuf_pulln(&payload, len), len); break; } } ifp = if_lookup_by_index(ndm->ndm_ifindex); if (!ifp || sockunion_family(&addr) == AF_UNSPEC) return; c = nhrp_cache_get(ifp, &addr, 0); if (!c) return; if (msg->nlmsg_type == RTM_GETNEIGH) { debugf(NHRP_DEBUG_KERNEL, "Netlink: who-has %s dev %s", sockunion2str(&addr, buf, sizeof buf), ifp->name); if (c->cur.type >= NHRP_CACHE_CACHED) { nhrp_cache_set_used(c, 1); netlink_update_binding(ifp, &addr, &c->cur.peer->vc->remote.nbma); } } else { debugf(NHRP_DEBUG_KERNEL, "Netlink: update %s dev %s nud %x", sockunion2str(&addr, buf, sizeof buf), ifp->name, ndm->ndm_state); state = (msg->nlmsg_type == RTM_NEWNEIGH) ? ndm->ndm_state : NUD_FAILED; nhrp_cache_set_used(c, state == NUD_REACHABLE); } } static int netlink_route_recv(struct thread *t) { uint8_t buf[ZNL_BUFFER_SIZE]; int fd = THREAD_FD(t); struct zbuf payload, zb; struct nlmsghdr *n; zbuf_init(&zb, buf, sizeof(buf), 0); while (zbuf_recv(&zb, fd) > 0) { while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) { debugf(NHRP_DEBUG_KERNEL, "Netlink: Received msg_type %u, msg_flags %u", n->nlmsg_type, n->nlmsg_flags); switch (n->nlmsg_type) { case RTM_GETNEIGH: case RTM_NEWNEIGH: case RTM_DELNEIGH: netlink_neigh_msg(n, &payload); break; } } } thread_add_read(master, netlink_route_recv, 0, fd); return 0; } static void netlink_log_register(int fd, int group) { struct nlmsghdr *n; struct nfgenmsg *nf; struct nfulnl_msg_config_cmd cmd; struct zbuf *zb = zbuf_alloc(512); n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG<<8) | NFULNL_MSG_CONFIG, NLM_F_REQUEST | NLM_F_ACK); nf = znl_push(zb, sizeof(*nf)); *nf = (struct nfgenmsg) { .nfgen_family = AF_UNSPEC, .version = NFNETLINK_V0, .res_id = htons(group), }; cmd.command = NFULNL_CFG_CMD_BIND; znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd)); znl_nlmsg_complete(zb, n); zbuf_send(zb, fd); zbuf_free(zb); } static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb) { struct nfgenmsg *nf; struct rtattr *rta; struct zbuf rtapl, pktpl; struct interface *ifp; struct nfulnl_msg_packet_hdr *pkthdr = NULL; uint32_t *in_ndx = NULL; nf = znl_pull(zb, sizeof(*nf)); if (!nf) return; memset(&pktpl, 0, sizeof(pktpl)); while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) { switch (rta->rta_type) { case NFULA_PACKET_HDR: pkthdr = znl_pull(&rtapl, sizeof(*pkthdr)); break; case NFULA_IFINDEX_INDEV: in_ndx = znl_pull(&rtapl, sizeof(*in_ndx)); break; case NFULA_PAYLOAD: pktpl = rtapl; break; /* NFULA_HWHDR exists and is supposed to contain source * hardware address. However, for ip_gre it seems to be * the nexthop destination address if the packet matches * route. */ } } if (!pkthdr || !in_ndx || !zbuf_used(&pktpl)) return; ifp = if_lookup_by_index(htonl(*in_ndx)); if (!ifp) return; nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl); } static int netlink_log_recv(struct thread *t) { uint8_t buf[ZNL_BUFFER_SIZE]; int fd = THREAD_FD(t); struct zbuf payload, zb; struct nlmsghdr *n; netlink_log_thread = NULL; zbuf_init(&zb, buf, sizeof(buf), 0); while (zbuf_recv(&zb, fd) > 0) { while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) { debugf(NHRP_DEBUG_KERNEL, "Netlink-log: Received msg_type %u, msg_flags %u", n->nlmsg_type, n->nlmsg_flags); switch (n->nlmsg_type) { case (NFNL_SUBSYS_ULOG<<8) | NFULNL_MSG_PACKET: netlink_log_indication(n, &payload); break; } } } THREAD_READ_ON(master, netlink_log_thread, netlink_log_recv, 0, netlink_log_fd); return 0; } void netlink_set_nflog_group(int nlgroup) { if (netlink_log_fd >= 0) { THREAD_OFF(netlink_log_thread); close(netlink_log_fd); netlink_log_fd = -1; } netlink_nflog_group = nlgroup; if (nlgroup) { netlink_log_fd = znl_open(NETLINK_NETFILTER, 0); netlink_log_register(netlink_log_fd, nlgroup); THREAD_READ_ON(master, netlink_log_thread, netlink_log_recv, 0, netlink_log_fd); } } int netlink_init(void) { netlink_req_fd = znl_open(NETLINK_ROUTE, 0); netlink_listen_fd = znl_open(NETLINK_ROUTE, RTMGRP_NEIGH); thread_add_read(master, netlink_route_recv, 0, netlink_listen_fd); return 0; } int netlink_configure_arp(unsigned int ifindex, int pf) { struct nlmsghdr *n; struct ndtmsg *ndtm; struct rtattr *rta; struct zbuf *zb = zbuf_alloc(512); int r; n = znl_nlmsg_push(zb, RTM_SETNEIGHTBL, NLM_F_REQUEST | NLM_F_REPLACE); ndtm = znl_push(zb, sizeof(*ndtm)); *ndtm = (struct ndtmsg) { .ndtm_family = pf, }; znl_rta_push(zb, NDTA_NAME, pf == AF_INET ? "arp_cache" : "ndisc_cache", 10); rta = znl_rta_nested_push(zb, NDTA_PARMS); znl_rta_push_u32(zb, NDTPA_IFINDEX, ifindex); znl_rta_push_u32(zb, NDTPA_APP_PROBES, 1); znl_rta_push_u32(zb, NDTPA_MCAST_PROBES, 0); znl_rta_push_u32(zb, NDTPA_UCAST_PROBES, 0); znl_rta_nested_complete(zb, rta); znl_nlmsg_complete(zb, n); r = zbuf_send(zb, netlink_req_fd); zbuf_recv(zb, netlink_req_fd); zbuf_free(zb); return r; } quagga-1.2.4/nhrpd/netlink_gre.c000066400000000000000000000067611325323223500165550ustar00rootroot00000000000000/* NHRP netlink/GRE tunnel configuration code * Copyright (c) 2014-2016 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include "debug.h" #include "netlink.h" #include "znl.h" static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data, int ifindex) { struct nlmsghdr *n; struct ifinfomsg *ifi; struct zbuf payload, rtapayload; struct rtattr *rta; debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex); n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST); ifi = znl_push(zb, sizeof(*ifi)); *ifi = (struct ifinfomsg) { .ifi_index = ifindex, }; znl_nlmsg_complete(zb, n); if (zbuf_send(zb, netlink_req_fd) < 0 || zbuf_recv(zb, netlink_req_fd) < 0) return -1; n = znl_nlmsg_pull(zb, &payload); if (!n) return -1; if (n->nlmsg_type != RTM_NEWLINK) return -1; ifi = znl_pull(&payload, sizeof(struct ifinfomsg)); if (!ifi) return -1; debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u", ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags); if (ifi->ifi_index != ifindex) return -1; while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL) if (rta->rta_type == IFLA_LINKINFO) break; if (!rta) return -1; payload = rtapayload; while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL) if (rta->rta_type == IFLA_INFO_DATA) break; if (!rta) return -1; *data = rtapayload; return 0; } void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, unsigned int *link_index, struct in_addr *saddr) { struct zbuf *zb = zbuf_alloc(8192), data, rtapl; struct rtattr *rta; *link_index = 0; *gre_key = 0; saddr->s_addr = 0; if (__netlink_gre_get_data(zb, &data, ifindex) < 0) goto err; while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) { switch (rta->rta_type) { case IFLA_GRE_LINK: *link_index = zbuf_get32(&rtapl); break; case IFLA_GRE_IKEY: case IFLA_GRE_OKEY: *gre_key = zbuf_get32(&rtapl); break; case IFLA_GRE_LOCAL: saddr->s_addr = zbuf_get32(&rtapl); break; } } err: zbuf_free(zb); } void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index) { struct nlmsghdr *n; struct ifinfomsg *ifi; struct rtattr *rta_info, *rta_data, *rta; struct zbuf *zr = zbuf_alloc(8192), data, rtapl; struct zbuf *zb = zbuf_alloc(8192); size_t len; if (__netlink_gre_get_data(zr, &data, ifindex) < 0) goto err; n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST); ifi = znl_push(zb, sizeof(*ifi)); *ifi = (struct ifinfomsg) { .ifi_index = ifindex, }; rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO); znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3); rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA); znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index); while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) { if (rta->rta_type == IFLA_GRE_LINK) continue; len = zbuf_used(&rtapl); znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len); } znl_rta_nested_complete(zb, rta_data); znl_rta_nested_complete(zb, rta_info); znl_nlmsg_complete(zb, n); zbuf_send(zb, netlink_req_fd); zbuf_recv(zb, netlink_req_fd); err: zbuf_free(zb); zbuf_free(zr); } quagga-1.2.4/nhrpd/nhrp_cache.c000066400000000000000000000223241325323223500163370ustar00rootroot00000000000000/* NHRP cache * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include "zebra.h" #include "memory.h" #include "thread.h" #include "hash.h" #include "nhrpd.h" #include "netlink.h" unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES]; const char * const nhrp_cache_type_str[] = { [NHRP_CACHE_INVALID] = "invalid", [NHRP_CACHE_INCOMPLETE] = "incomplete", [NHRP_CACHE_NEGATIVE] = "negative", [NHRP_CACHE_CACHED] = "cached", [NHRP_CACHE_DYNAMIC] = "dynamic", [NHRP_CACHE_NHS] = "nhs", [NHRP_CACHE_STATIC] = "static", [NHRP_CACHE_LOCAL] = "local", }; static unsigned int nhrp_cache_protocol_key(void *peer_data) { struct nhrp_cache *p = peer_data; return sockunion_hash(&p->remote_addr); } static int nhrp_cache_protocol_cmp(const void *cache_data, const void *key_data) { const struct nhrp_cache *a = cache_data; const struct nhrp_cache *b = key_data; return sockunion_same(&a->remote_addr, &b->remote_addr); } static void *nhrp_cache_alloc(void *data) { struct nhrp_cache *p, *key = data; p = XMALLOC(MTYPE_NHRP_CACHE, sizeof(struct nhrp_cache)); if (p) { *p = (struct nhrp_cache) { .cur.type = NHRP_CACHE_INVALID, .new.type = NHRP_CACHE_INVALID, .remote_addr = key->remote_addr, .ifp = key->ifp, .notifier_list = NOTIFIER_LIST_INITIALIZER(&p->notifier_list), }; nhrp_cache_counts[p->cur.type]++; } return p; } static void nhrp_cache_free(struct nhrp_cache *c) { struct nhrp_interface *nifp = c->ifp->info; zassert(c->cur.type == NHRP_CACHE_INVALID && c->cur.peer == NULL); zassert(c->new.type == NHRP_CACHE_INVALID && c->new.peer == NULL); nhrp_cache_counts[c->cur.type]--; notifier_call(&c->notifier_list, NOTIFY_CACHE_DELETE); zassert(!notifier_active(&c->notifier_list)); hash_release(nifp->cache_hash, c); XFREE(MTYPE_NHRP_CACHE, c); } struct nhrp_cache *nhrp_cache_get(struct interface *ifp, union sockunion *remote_addr, int create) { struct nhrp_interface *nifp = ifp->info; struct nhrp_cache key; if (!nifp->cache_hash) { nifp->cache_hash = hash_create(nhrp_cache_protocol_key, nhrp_cache_protocol_cmp); if (!nifp->cache_hash) return NULL; } key.remote_addr = *remote_addr; key.ifp = ifp; return hash_get(nifp->cache_hash, &key, create ? nhrp_cache_alloc : NULL); } static int nhrp_cache_do_free(struct thread *t) { struct nhrp_cache *c = THREAD_ARG(t); c->t_timeout = NULL; nhrp_cache_free(c); return 0; } static int nhrp_cache_do_timeout(struct thread *t) { struct nhrp_cache *c = THREAD_ARG(t); c->t_timeout = NULL; if (c->cur.type != NHRP_CACHE_INVALID) nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); return 0; } static void nhrp_cache_update_route(struct nhrp_cache *c) { struct prefix pfx; struct nhrp_peer *p = c->cur.peer; sockunion2hostprefix(&c->remote_addr, &pfx); if (p && nhrp_peer_check(p, 1)) { netlink_update_binding(p->ifp, &c->remote_addr, &p->vc->remote.nbma); nhrp_route_announce(1, c->cur.type, &pfx, c->ifp, NULL, c->cur.mtu); if (c->cur.type >= NHRP_CACHE_DYNAMIC) { nhrp_route_update_nhrp(&pfx, c->ifp); c->nhrp_route_installed = 1; } else if (c->nhrp_route_installed) { nhrp_route_update_nhrp(&pfx, NULL); c->nhrp_route_installed = 0; } if (!c->route_installed) { notifier_call(&c->notifier_list, NOTIFY_CACHE_UP); c->route_installed = 1; } } else { if (c->nhrp_route_installed) { nhrp_route_update_nhrp(&pfx, NULL); c->nhrp_route_installed = 0; } if (c->route_installed) { sockunion2hostprefix(&c->remote_addr, &pfx); notifier_call(&c->notifier_list, NOTIFY_CACHE_DOWN); nhrp_route_announce(0, c->cur.type, &pfx, NULL, NULL, 0); c->route_installed = 0; } } } static void nhrp_cache_peer_notifier(struct notifier_block *n, unsigned long cmd) { struct nhrp_cache *c = container_of(n, struct nhrp_cache, peer_notifier); switch (cmd) { case NOTIFY_PEER_UP: nhrp_cache_update_route(c); break; case NOTIFY_PEER_DOWN: case NOTIFY_PEER_IFCONFIG_CHANGED: notifier_call(&c->notifier_list, NOTIFY_CACHE_DOWN); nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); break; case NOTIFY_PEER_NBMA_CHANGING: if (c->cur.type == NHRP_CACHE_DYNAMIC) c->cur.peer->vc->abort_migration = 1; break; } } static void nhrp_cache_reset_new(struct nhrp_cache *c) { THREAD_OFF(c->t_auth); if (list_hashed(&c->newpeer_notifier.notifier_entry)) nhrp_peer_notify_del(c->new.peer, &c->newpeer_notifier); nhrp_peer_unref(c->new.peer); memset(&c->new, 0, sizeof(c->new)); c->new.type = NHRP_CACHE_INVALID; } static void nhrp_cache_update_timers(struct nhrp_cache *c) { THREAD_OFF(c->t_timeout); switch (c->cur.type) { case NHRP_CACHE_INVALID: if (!c->t_auth) THREAD_TIMER_MSEC_ON(master, c->t_timeout, nhrp_cache_do_free, c, 10); break; default: if (c->cur.expires) THREAD_TIMER_ON(master, c->t_timeout, nhrp_cache_do_timeout, c, c->cur.expires - recent_relative_time().tv_sec); break; } } static void nhrp_cache_authorize_binding(struct nhrp_reqid *r, void *arg) { struct nhrp_cache *c = container_of(r, struct nhrp_cache, eventid); char buf[SU_ADDRSTRLEN]; debugf(NHRP_DEBUG_COMMON, "cache: %s %s: %s", c->ifp->name, sockunion2str(&c->remote_addr, buf, sizeof buf), (const char *) arg); nhrp_reqid_free(&nhrp_event_reqid, r); if (arg && strcmp(arg, "accept") == 0) { if (c->cur.peer) { netlink_update_binding(c->cur.peer->ifp, &c->remote_addr, NULL); nhrp_peer_notify_del(c->cur.peer, &c->peer_notifier); nhrp_peer_unref(c->cur.peer); } nhrp_cache_counts[c->cur.type]--; nhrp_cache_counts[c->new.type]++; c->cur = c->new; c->cur.peer = nhrp_peer_ref(c->cur.peer); nhrp_cache_reset_new(c); if (c->cur.peer) nhrp_peer_notify_add(c->cur.peer, &c->peer_notifier, nhrp_cache_peer_notifier); nhrp_cache_update_route(c); notifier_call(&c->notifier_list, NOTIFY_CACHE_BINDING_CHANGE); } else { nhrp_cache_reset_new(c); } nhrp_cache_update_timers(c); } static int nhrp_cache_do_auth_timeout(struct thread *t) { struct nhrp_cache *c = THREAD_ARG(t); c->t_auth = NULL; nhrp_cache_authorize_binding(&c->eventid, (void *) "timeout"); return 0; } static void nhrp_cache_newpeer_notifier(struct notifier_block *n, unsigned long cmd) { struct nhrp_cache *c = container_of(n, struct nhrp_cache, newpeer_notifier); switch (cmd) { case NOTIFY_PEER_UP: if (nhrp_peer_check(c->new.peer, 1)) { evmgr_notify("authorize-binding", c, nhrp_cache_authorize_binding); THREAD_TIMER_ON(master, c->t_auth, nhrp_cache_do_auth_timeout, c, 10); } break; case NOTIFY_PEER_DOWN: case NOTIFY_PEER_IFCONFIG_CHANGED: nhrp_cache_reset_new(c); break; } } int nhrp_cache_update_binding(struct nhrp_cache *c, enum nhrp_cache_type type, int holding_time, struct nhrp_peer *p, uint32_t mtu, union sockunion *nbma_oa) { if (c->cur.type > type || c->new.type > type) { nhrp_peer_unref(p); return 0; } /* Sanitize MTU */ switch (sockunion_family(&c->remote_addr)) { case AF_INET: if (mtu < 576 || mtu >= 1500) mtu = 0; /* Opennhrp announces nbma mtu, but we use protocol mtu. * This heuristic tries to fix up it. */ if (mtu > 1420) mtu = (mtu & -16) - 80; break; default: mtu = 0; break; } nhrp_cache_reset_new(c); if (c->cur.type == type && c->cur.peer == p && c->cur.mtu == mtu) { if (holding_time > 0) c->cur.expires = recent_relative_time().tv_sec + holding_time; if (nbma_oa) c->cur.remote_nbma_natoa = *nbma_oa; else memset(&c->cur.remote_nbma_natoa, 0, sizeof c->cur.remote_nbma_natoa); nhrp_peer_unref(p); } else { c->new.type = type; c->new.peer = p; c->new.mtu = mtu; if (nbma_oa) c->new.remote_nbma_natoa = *nbma_oa; if (holding_time > 0) c->new.expires = recent_relative_time().tv_sec + holding_time; else if (holding_time < 0) c->new.type = NHRP_CACHE_INVALID; if (c->new.type == NHRP_CACHE_INVALID || c->new.type >= NHRP_CACHE_STATIC || c->map) { nhrp_cache_authorize_binding(&c->eventid, (void *) "accept"); } else { nhrp_peer_notify_add(c->new.peer, &c->newpeer_notifier, nhrp_cache_newpeer_notifier); nhrp_cache_newpeer_notifier(&c->newpeer_notifier, NOTIFY_PEER_UP); THREAD_TIMER_ON(master, c->t_auth, nhrp_cache_do_auth_timeout, c, 60); } } nhrp_cache_update_timers(c); return 1; } void nhrp_cache_set_used(struct nhrp_cache *c, int used) { c->used = used; if (c->used) notifier_call(&c->notifier_list, NOTIFY_CACHE_USED); } struct nhrp_cache_iterator_ctx { void (*cb)(struct nhrp_cache *, void *); void *ctx; }; static void nhrp_cache_iterator(struct hash_backet *b, void *ctx) { struct nhrp_cache_iterator_ctx *ic = ctx; ic->cb(b->data, ic->ctx); } void nhrp_cache_foreach(struct interface *ifp, void (*cb)(struct nhrp_cache *, void *), void *ctx) { struct nhrp_interface *nifp = ifp->info; struct nhrp_cache_iterator_ctx ic = { .cb = cb, .ctx = ctx, }; if (nifp->cache_hash) hash_iterate(nifp->cache_hash, nhrp_cache_iterator, &ic); } void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *n, notifier_fn_t fn) { notifier_add(n, &c->notifier_list, fn); } void nhrp_cache_notify_del(struct nhrp_cache *c, struct notifier_block *n) { notifier_del(n); } quagga-1.2.4/nhrpd/nhrp_event.c000066400000000000000000000151221325323223500164130ustar00rootroot00000000000000/* NHRP event manager * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include "thread.h" #include "zbuf.h" #include "log.h" #include "nhrpd.h" const char *nhrp_event_socket_path; struct nhrp_reqid_pool nhrp_event_reqid; struct event_manager { struct thread *t_reconnect, *t_read, *t_write; struct zbuf ibuf; struct zbuf_queue obuf; int fd; uint8_t ibuf_data[4*1024]; }; static int evmgr_reconnect(struct thread *t); static void evmgr_connection_error(struct event_manager *evmgr) { THREAD_OFF(evmgr->t_read); THREAD_OFF(evmgr->t_write); zbuf_reset(&evmgr->ibuf); zbufq_reset(&evmgr->obuf); if (evmgr->fd >= 0) close(evmgr->fd); evmgr->fd = -1; if (nhrp_event_socket_path) THREAD_TIMER_MSEC_ON(master, evmgr->t_reconnect, evmgr_reconnect, evmgr, 10); } static void evmgr_recv_message(struct event_manager *evmgr, struct zbuf *zb) { struct zbuf zl; uint32_t eventid = 0; size_t len; char buf[256], result[64] = ""; while (zbuf_may_pull_until(zb, "\n", &zl)) { len = zbuf_used(&zl) - 1; if (len >= sizeof(buf)-1) continue; memcpy(buf, zbuf_pulln(&zl, len), len); buf[len] = 0; debugf(NHRP_DEBUG_EVENT, "evmgr: msg: %s", buf); sscanf(buf, "eventid=%d", &eventid); sscanf(buf, "result=%63s", result); } debugf(NHRP_DEBUG_EVENT, "evmgr: received: eventid=%d result=%s", eventid, result); if (eventid && result[0]) { struct nhrp_reqid *r = nhrp_reqid_lookup(&nhrp_event_reqid, eventid); if (r) r->cb(r, result); } } static int evmgr_read(struct thread *t) { struct event_manager *evmgr = THREAD_ARG(t); struct zbuf *ibuf = &evmgr->ibuf; struct zbuf msg; evmgr->t_read = NULL; if (zbuf_read(ibuf, evmgr->fd, (size_t) -1) < 0) { evmgr_connection_error(evmgr); return 0; } /* Process all messages in buffer */ while (zbuf_may_pull_until(ibuf, "\n\n", &msg)) evmgr_recv_message(evmgr, &msg); THREAD_READ_ON(master, evmgr->t_read, evmgr_read, evmgr, evmgr->fd); return 0; } static int evmgr_write(struct thread *t) { struct event_manager *evmgr = THREAD_ARG(t); int r; evmgr->t_write = NULL; r = zbufq_write(&evmgr->obuf, evmgr->fd); if (r > 0) { THREAD_WRITE_ON(master, evmgr->t_write, evmgr_write, evmgr, evmgr->fd); } else if (r < 0) { evmgr_connection_error(evmgr); } return 0; } static void evmgr_hexdump(struct zbuf *zb, const uint8_t *val, size_t vallen) { static const char xd[] = "0123456789abcdef"; size_t i; char *ptr; ptr = zbuf_pushn(zb, 2*vallen); if (!ptr) return; for (i = 0; i < vallen; i++) { uint8_t b = val[i]; *(ptr++) = xd[b >> 4]; *(ptr++) = xd[b & 0xf]; } } static void evmgr_put(struct zbuf *zb, const char *fmt, ...) { const char *pos, *nxt, *str; const uint8_t *bin; const union sockunion *su; int len; va_list va; va_start(va, fmt); for (pos = fmt; (nxt = strchr(pos, '%')) != NULL; pos = nxt + 2) { zbuf_put(zb, pos, nxt-pos); switch (nxt[1]) { case '%': zbuf_put8(zb, '%'); break; case 'u': zb->tail += snprintf((char *) zb->tail, zbuf_tailroom(zb), "%u", va_arg(va, uint32_t)); break; case 's': str = va_arg(va, const char *); zbuf_put(zb, str, strlen(str)); break; case 'U': su = va_arg(va, const union sockunion *); if (sockunion2str(su, (char *) zb->tail, zbuf_tailroom(zb))) zb->tail += strlen((char *) zb->tail); else zbuf_set_werror(zb); break; case 'H': bin = va_arg(va, const uint8_t *); len = va_arg(va, int); evmgr_hexdump(zb, bin, len); break; } } va_end(va); zbuf_put(zb, pos, strlen(pos)); } static void evmgr_submit(struct event_manager *evmgr, struct zbuf *obuf) { if (obuf->error) { zbuf_free(obuf); return; } zbuf_put(obuf, "\n", 1); zbufq_queue(&evmgr->obuf, obuf); if (evmgr->fd >= 0) THREAD_WRITE_ON(master, evmgr->t_write, evmgr_write, evmgr, evmgr->fd); } static int evmgr_reconnect(struct thread *t) { struct event_manager *evmgr = THREAD_ARG(t); int fd; evmgr->t_reconnect = NULL; if (evmgr->fd >= 0 || !nhrp_event_socket_path) return 0; fd = sock_open_unix(nhrp_event_socket_path); if (fd < 0) { zlog_warn("%s: failure connecting nhrp-event socket: %s", __PRETTY_FUNCTION__, strerror(errno)); zbufq_reset(&evmgr->obuf); THREAD_TIMER_ON(master, evmgr->t_reconnect, evmgr_reconnect, evmgr, 10); return 0; } zlog_info("Connected to Event Manager"); evmgr->fd = fd; THREAD_READ_ON(master, evmgr->t_read, evmgr_read, evmgr, evmgr->fd); return 0; } static struct event_manager evmgr_connection; void evmgr_init(void) { struct event_manager *evmgr = &evmgr_connection; evmgr->fd = -1; zbuf_init(&evmgr->ibuf, evmgr->ibuf_data, sizeof(evmgr->ibuf_data), 0); zbufq_init(&evmgr->obuf); THREAD_TIMER_MSEC_ON(master, evmgr->t_reconnect, evmgr_reconnect, evmgr, 10); } void evmgr_set_socket(const char *socket) { if (nhrp_event_socket_path) { free((char *) nhrp_event_socket_path); nhrp_event_socket_path = NULL; } if (socket) nhrp_event_socket_path = strdup(socket); evmgr_connection_error(&evmgr_connection); } void evmgr_terminate(void) { } void evmgr_notify(const char *name, struct nhrp_cache *c, void (*cb)(struct nhrp_reqid *, void *)) { struct event_manager *evmgr = &evmgr_connection; struct nhrp_vc *vc; struct nhrp_interface *nifp = c->ifp->info; struct zbuf *zb; afi_t afi = family2afi(sockunion_family(&c->remote_addr)); if (!nhrp_event_socket_path) { cb(&c->eventid, (void*) "accept"); return; } debugf(NHRP_DEBUG_EVENT, "evmgr: sending event %s", name); vc = c->new.peer ? c->new.peer->vc : NULL; zb = zbuf_alloc(1024 + (vc ? (vc->local.certlen + vc->remote.certlen) * 2 : 0)); if (cb) { nhrp_reqid_free(&nhrp_event_reqid, &c->eventid); evmgr_put(zb, "eventid=%u\n", nhrp_reqid_alloc(&nhrp_event_reqid, &c->eventid, cb)); } evmgr_put(zb, "event=%s\n" "type=%s\n" "old_type=%s\n" "num_nhs=%u\n" "interface=%s\n" "local_addr=%U\n", name, nhrp_cache_type_str[c->new.type], nhrp_cache_type_str[c->cur.type], (unsigned int) nhrp_cache_counts[NHRP_CACHE_NHS], c->ifp->name, &nifp->afi[afi].addr); if (vc) { evmgr_put(zb, "vc_initiated=%s\n" "local_nbma=%U\n" "local_cert=%H\n" "remote_addr=%U\n" "remote_nbma=%U\n" "remote_cert=%H\n", c->new.peer->requested ? "yes" : "no", &vc->local.nbma, vc->local.cert, vc->local.certlen, &c->remote_addr, &vc->remote.nbma, vc->remote.cert, vc->remote.certlen); } evmgr_submit(evmgr, zb); } quagga-1.2.4/nhrpd/nhrp_interface.c000066400000000000000000000252051325323223500172350ustar00rootroot00000000000000/* NHRP interface * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include "zebra.h" #include "linklist.h" #include "memory.h" #include "thread.h" #include "nhrpd.h" #include "os.h" #include "netlink.h" static int nhrp_if_new_hook(struct interface *ifp) { struct nhrp_interface *nifp; afi_t afi; nifp = XCALLOC(MTYPE_NHRP_IF, sizeof(struct nhrp_interface)); if (!nifp) return 0; ifp->info = nifp; nifp->ifp = ifp; notifier_init(&nifp->notifier_list); for (afi = 0; afi < AFI_MAX; afi++) { struct nhrp_afi_data *ad = &nifp->afi[afi]; ad->holdtime = NHRPD_DEFAULT_HOLDTIME; list_init(&ad->nhslist_head); } return 0; } static int nhrp_if_delete_hook(struct interface *ifp) { XFREE(MTYPE_NHRP_IF, ifp->info); return 0; } void nhrp_interface_init(void) { if_add_hook(IF_NEW_HOOK, nhrp_if_new_hook); if_add_hook(IF_DELETE_HOOK, nhrp_if_delete_hook); } void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi) { struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad = &nifp->afi[afi]; unsigned short new_mtu; if (if_ad->configured_mtu < 0) new_mtu = nifp->nbmaifp ? nifp->nbmaifp->mtu : 0; else new_mtu = if_ad->configured_mtu; if (new_mtu >= 1500) new_mtu = 0; if (new_mtu != if_ad->mtu) { debugf(NHRP_DEBUG_IF, "%s: MTU changed to %d", ifp->name, new_mtu); if_ad->mtu = new_mtu; notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_MTU_CHANGED); } } static void nhrp_interface_update_source(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info; if (!nifp->source || !nifp->nbmaifp || nifp->linkidx == nifp->nbmaifp->ifindex) return; nifp->linkidx = nifp->nbmaifp->ifindex; debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d", ifp->name, nifp->linkidx); netlink_gre_set_link(ifp->ifindex, nifp->linkidx); } static void nhrp_interface_interface_notifier(struct notifier_block *n, unsigned long cmd) { struct nhrp_interface *nifp = container_of(n, struct nhrp_interface, nbmanifp_notifier); struct interface *nbmaifp = nifp->nbmaifp; struct nhrp_interface *nbmanifp = nbmaifp->info; char buf[SU_ADDRSTRLEN]; switch (cmd) { case NOTIFY_INTERFACE_CHANGED: nhrp_interface_update_mtu(nifp->ifp, AFI_IP); nhrp_interface_update_source(nifp->ifp); break; case NOTIFY_INTERFACE_ADDRESS_CHANGED: nifp->nbma = nbmanifp->afi[AFI_IP].addr; nhrp_interface_update(nifp->ifp); notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED); debugf(NHRP_DEBUG_IF, "%s: NBMA change: address %s", nifp->ifp->name, sockunion2str(&nifp->nbma, buf, sizeof buf)); break; } } static void nhrp_interface_update_nbma(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info, *nbmanifp = NULL; struct interface *nbmaifp = NULL; union sockunion nbma; sockunion_family(&nbma) = AF_UNSPEC; if (nifp->source) nbmaifp = if_lookup_by_name(nifp->source); switch (ifp->ll_type) { case ZEBRA_LLT_IPGRE: { struct in_addr saddr = {0}; netlink_gre_get_info(ifp->ifindex, &nifp->grekey, &nifp->linkidx, &saddr); debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name, nifp->grekey, nifp->linkidx, saddr.s_addr); if (saddr.s_addr) sockunion_set(&nbma, AF_INET, (u_char *) &saddr.s_addr, sizeof(saddr.s_addr)); else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL) nbmaifp = if_lookup_by_index(nifp->linkidx); } break; default: break; } if (nbmaifp) nbmanifp = nbmaifp->info; if (nbmaifp != nifp->nbmaifp) { if (nifp->nbmaifp) notifier_del(&nifp->nbmanifp_notifier); nifp->nbmaifp = nbmaifp; if (nbmaifp) { notifier_add(&nifp->nbmanifp_notifier, &nbmanifp->notifier_list, nhrp_interface_interface_notifier); debugf(NHRP_DEBUG_IF, "%s: bound to %s", ifp->name, nbmaifp->name); } } if (nbmaifp) { if (sockunion_family(&nbma) == AF_UNSPEC) nbma = nbmanifp->afi[AFI_IP].addr; nhrp_interface_update_mtu(ifp, AFI_IP); nhrp_interface_update_source(ifp); } if (!sockunion_same(&nbma, &nifp->nbma)) { nifp->nbma = nbma; nhrp_interface_update(nifp->ifp); debugf(NHRP_DEBUG_IF, "%s: NBMA address changed", ifp->name); notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED); } nhrp_interface_update(ifp); } static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, int force) { const int family = afi2family(afi); struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad = &nifp->afi[afi]; struct nhrp_cache *nc; struct connected *c, *best; struct listnode *cnode; union sockunion addr; char buf[PREFIX_STRLEN]; /* Select new best match preferring primary address */ best = NULL; for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { if (PREFIX_FAMILY(c->address) != family) continue; if (best == NULL) { best = c; continue; } if ((best->flags & ZEBRA_IFA_SECONDARY) && !(c->flags & ZEBRA_IFA_SECONDARY)) { best = c; continue; } if (!(best->flags & ZEBRA_IFA_SECONDARY) && (c->flags & ZEBRA_IFA_SECONDARY)) continue; if (best->address->prefixlen > c->address->prefixlen) { best = c; continue; } if (best->address->prefixlen < c->address->prefixlen) continue; } /* On NHRP interfaces a host prefix is required */ if (best && if_ad->configured && best->address->prefixlen != 8 * prefix_blen(best->address)) { zlog_notice("%s: %s is not a host prefix", ifp->name, prefix2str(best->address, buf, sizeof buf)); best = NULL; } /* Update address if it changed */ if (best) prefix2sockunion(best->address, &addr); else memset(&addr, 0, sizeof(addr)); if (!force && sockunion_same(&if_ad->addr, &addr)) return; if (sockunion_family(&if_ad->addr) != AF_UNSPEC) { nc = nhrp_cache_get(ifp, &if_ad->addr, 0); if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, -1, NULL, 0, NULL); } debugf(NHRP_DEBUG_KERNEL, "%s: IPv%d address changed to %s", ifp->name, afi == AFI_IP ? 4 : 6, best ? prefix2str(best->address, buf, sizeof buf) : "(none)"); if_ad->addr = addr; if (if_ad->configured && sockunion_family(&if_ad->addr) != AF_UNSPEC) { nc = nhrp_cache_get(ifp, &addr, 1); if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL); } notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED); } void nhrp_interface_update(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad; afi_t afi; int enabled = 0; notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_CHANGED); for (afi = 0; afi < AFI_MAX; afi++) { if_ad = &nifp->afi[afi]; if (sockunion_family(&nifp->nbma) == AF_UNSPEC || ifp->ifindex == IFINDEX_INTERNAL || !if_is_up(ifp) || !if_ad->network_id) { if (if_ad->configured) { if_ad->configured = 0; nhrp_interface_update_address(ifp, afi, 1); } continue; } if (!if_ad->configured) { os_configure_dmvpn(ifp->ifindex, ifp->name, afi2family(afi)); if_ad->configured = 1; nhrp_interface_update_address(ifp, afi, 1); } enabled = 1; } if (enabled != nifp->enabled) { nifp->enabled = enabled; notifier_call(&nifp->notifier_list, enabled ? NOTIFY_INTERFACE_UP : NOTIFY_INTERFACE_DOWN); } } int nhrp_interface_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; /* read and add the interface in the iflist. */ ifp = zebra_interface_add_read(client->ibuf, vrf_id); if (ifp == NULL) return 0; debugf(NHRP_DEBUG_IF, "if-add: %s, ifindex: %u, hw_type: %d %s", ifp->name, ifp->ifindex, ifp->ll_type, if_link_type_str(ifp->ll_type)); nhrp_interface_update_nbma(ifp); return 0; } int nhrp_interface_delete(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = client->ibuf; ifp = zebra_interface_state_read(s, vrf_id); if (ifp == NULL) return 0; debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name); ifp->ifindex = IFINDEX_INTERNAL; nhrp_interface_update(ifp); /* if_delete(ifp); */ return 0; } int nhrp_interface_up(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_state_read(client->ibuf, vrf_id); if (ifp == NULL) return 0; debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name); nhrp_interface_update_nbma(ifp); return 0; } int nhrp_interface_down(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_state_read(client->ibuf, vrf_id); if (ifp == NULL) return 0; debugf(NHRP_DEBUG_IF, "if-down: %s", ifp->name); nhrp_interface_update(ifp); return 0; } int nhrp_interface_address_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; char buf[PREFIX_STRLEN]; ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id); if (ifc == NULL) return 0; debugf(NHRP_DEBUG_IF, "if-addr-add: %s: %s", ifc->ifp->name, prefix2str(ifc->address, buf, sizeof buf)); nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0); return 0; } int nhrp_interface_address_delete(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; char buf[PREFIX_STRLEN]; ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id); if (ifc == NULL) return 0; debugf(NHRP_DEBUG_IF, "if-addr-del: %s: %s", ifc->ifp->name, prefix2str(ifc->address, buf, sizeof buf)); nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0); connected_free(ifc); return 0; } void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn) { struct nhrp_interface *nifp = ifp->info; notifier_add(n, &nifp->notifier_list, fn); } void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n) { notifier_del(n); } void nhrp_interface_set_protection(struct interface *ifp, const char *profile, const char *fallback_profile) { struct nhrp_interface *nifp = ifp->info; if (nifp->ipsec_profile) free(nifp->ipsec_profile); nifp->ipsec_profile = profile ? strdup(profile) : NULL; if (nifp->ipsec_fallback_profile) free(nifp->ipsec_fallback_profile); nifp->ipsec_fallback_profile = fallback_profile ? strdup(fallback_profile) : NULL; notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED); } void nhrp_interface_set_source(struct interface *ifp, const char *ifname) { struct nhrp_interface *nifp = ifp->info; if (nifp->source) free(nifp->source); nifp->source = ifname ? strdup(ifname) : NULL; nhrp_interface_update_nbma(ifp); } quagga-1.2.4/nhrpd/nhrp_main.c000066400000000000000000000131741325323223500162230ustar00rootroot00000000000000/* NHRP daemon main functions * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include #include "zebra.h" #include "privs.h" #include "getopt.h" #include "thread.h" #include "sigevent.h" #include "version.h" #include "log.h" #include "memory.h" #include "command.h" #include "nhrpd.h" #include "netlink.h" unsigned int debug_flags = 0; struct thread_master *master; struct timeval current_time; static const char *pid_file = PATH_NHRPD_PID; static char config_default[] = SYSCONFDIR NHRP_DEFAULT_CONFIG; static char *config_file = NULL; static char *vty_addr = NULL; static int vty_port = NHRP_VTY_PORT; static int do_daemonise = 0; /* nhrpd options. */ struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { 0 } }; /* nhrpd privileges */ static zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_NET_ADMIN, ZCAP_DAC_OVERRIDE, /* for now needed to write to /proc/sys/net/ipv4//send_redirect */ }; static struct zebra_privs_t nhrpd_privs = { #ifdef QUAGGA_USER .user = QUAGGA_USER, #endif #ifdef QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = ZEBRA_NUM_OF(_caps_p), }; static void usage(const 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 NHRP protocol.\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\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ -g, --group Group to run as\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); } static void parse_arguments(const char *progname, int argc, char **argv) { int opt; while (1) { opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0); if(opt < 0) break; switch (opt) { case 0: break; case 'd': do_daemonise = -1; break; case 'f': config_file = optarg; break; case 'i': pid_file = optarg; break; case 'z': zclient_serv_path_set(optarg); break; case 'A': vty_addr = optarg; break; case 'P': vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = NHRP_VTY_PORT; break; case 'u': nhrpd_privs.user = optarg; break; case 'g': nhrpd_privs.group = optarg; break; case 'v': print_version(progname); exit(0); break; case 'h': usage(progname, 0); break; default: usage(progname, 1); break; } } } static void nhrp_sigusr1(void) { zlog_rotate(NULL); } static void nhrp_request_stop(void) { debugf(NHRP_DEBUG_COMMON, "Exiting..."); nhrp_shortcut_terminate(); nhrp_nhs_terminate(); nhrp_zebra_terminate(); vici_terminate(); evmgr_terminate(); nhrp_vc_terminate(); vrf_terminate(); /* memory_terminate(); */ /* vty_terminate(); */ cmd_terminate(); /* signal_terminate(); */ zprivs_terminate(&nhrpd_privs); debugf(NHRP_DEBUG_COMMON, "Remove pid file."); if (pid_file) unlink(pid_file); debugf(NHRP_DEBUG_COMMON, "Done."); closezlog(zlog_default); exit(0); } static struct quagga_signal_t sighandlers[] = { { .signal = SIGUSR1, .handler = &nhrp_sigusr1, }, { .signal = SIGINT, .handler = &nhrp_request_stop, }, { .signal = SIGTERM, .handler = &nhrp_request_stop, }, }; int main(int argc, char **argv) { const char *progname; /* Set umask before anything for security */ umask(0027); progname = basename(argv[0]); zlog_default = openzlog(progname, ZLOG_NHRP, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING); parse_arguments(progname, argc, argv); /* Library inits. */ master = thread_master_create(); zprivs_init(&nhrpd_privs); signal_init(master, array_size(sighandlers), sighandlers); cmd_init(1); vty_init(master); memory_init(); nhrp_interface_init(); vrf_init(); resolver_init(); /* Run with elevated capabilities, as for all netlink activity * we need privileges anyway. */ nhrpd_privs.change(ZPRIVS_RAISE); netlink_init(); evmgr_init(); nhrp_vc_init(); nhrp_packet_init(); vici_init(); nhrp_zebra_init(); nhrp_shortcut_init(); nhrp_config_init(); /* Get zebra configuration file. */ zlog_set_level(NULL, ZLOG_DEST_STDOUT, do_daemonise ? ZLOG_DISABLED : LOG_DEBUG); vty_read_config(config_file, config_default); if (do_daemonise && daemon(0, 0) < 0) { zlog_err("daemonise: %s", safe_strerror(errno)); exit (1); } /* write pid file */ if (pid_output(pid_file) < 0) { zlog_err("error while writing pidfile"); exit (1); } /* Create VTY socket */ vty_serv_sock(vty_addr, vty_port, NHRP_VTYSH_PATH); zlog_notice("nhrpd starting: vty@%d", vty_port); /* Main loop */ thread_main (master); return 0; } quagga-1.2.4/nhrpd/nhrp_nhs.c000066400000000000000000000256621325323223500160740ustar00rootroot00000000000000/* NHRP NHC nexthop server functions (registration) * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include "zebra.h" #include "zbuf.h" #include "memory.h" #include "thread.h" #include "nhrpd.h" #include "nhrp_protocol.h" static int nhrp_nhs_resolve(struct thread *t); static int nhrp_reg_send_req(struct thread *t); static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) { struct nhrp_packet_parser *p = arg; struct nhrp_registration *r = container_of(reqid, struct nhrp_registration, reqid); struct nhrp_nhs *nhs = r->nhs; struct interface *ifp = nhs->ifp; struct nhrp_interface *nifp = ifp->info; struct nhrp_extension_header *ext; struct nhrp_cie_header *cie; struct nhrp_cache *c; struct zbuf extpl; union sockunion cie_nbma, cie_proto, *proto; char buf[64]; int ok = 0, holdtime; nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid); if (p->hdr->type != NHRP_PACKET_REGISTRATION_REPLY) { debugf(NHRP_DEBUG_COMMON, "NHS: Registration failed"); return; } debugf(NHRP_DEBUG_COMMON, "NHS: Reg.reply received"); ok = 1; while ((cie = nhrp_cie_pull(&p->payload, p->hdr, &cie_nbma, &cie_proto)) != NULL) { proto = sockunion_family(&cie_proto) != AF_UNSPEC ? &cie_proto : &p->src_proto; debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %s: %d", sockunion2str(proto, buf, sizeof(buf)), cie->code); if (!((cie->code == NHRP_CODE_SUCCESS) || (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED && nhs->hub))) ok = 0; } if (!ok) return; /* Parse extensions */ sockunion_family(&nifp->nat_nbma) = AF_UNSPEC; while ((ext = nhrp_ext_pull(&p->extensions, &extpl)) != NULL) { switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { case NHRP_EXTENSION_NAT_ADDRESS: /* NHS adds second CIE if NAT is detected */ if (nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto) && nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto)) { nifp->nat_nbma = cie_nbma; debugf(NHRP_DEBUG_IF, "%s: NAT detected, real NBMA address: %s", ifp->name, sockunion2str(&nifp->nbma, buf, sizeof(buf))); } break; } } /* Success - schedule next registration, and route NHS */ r->timeout = 2; holdtime = nifp->afi[nhs->afi].holdtime; THREAD_OFF(r->t_register); /* RFC 2332 5.2.3 - Registration is recommend to be renewed * every one third of holdtime */ THREAD_TIMER_ON(master, r->t_register, nhrp_reg_send_req, r, holdtime / 3); r->proto_addr = p->dst_proto; c = nhrp_cache_get(ifp, &p->dst_proto, 1); if (c) nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime, nhrp_peer_ref(r->peer), 0, NULL); } static int nhrp_reg_timeout(struct thread *t) { struct nhrp_registration *r = THREAD_ARG(t); struct nhrp_cache *c; r->t_register = NULL; if (r->timeout >= 16 && sockunion_family(&r->proto_addr) != AF_UNSPEC) { nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid); c = nhrp_cache_get(r->nhs->ifp, &r->proto_addr, 0); if (c) nhrp_cache_update_binding(c, NHRP_CACHE_NHS, -1, NULL, 0, NULL); sockunion_family(&r->proto_addr) = AF_UNSPEC; } r->timeout <<= 1; if (r->timeout > 64) r->timeout = 2; THREAD_TIMER_MSEC_ON(master, r->t_register, nhrp_reg_send_req, r, 10); return 0; } static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd) { struct nhrp_registration *r = container_of(n, struct nhrp_registration, peer_notifier); char buf[SU_ADDRSTRLEN]; switch (cmd) { case NOTIFY_PEER_UP: case NOTIFY_PEER_DOWN: case NOTIFY_PEER_IFCONFIG_CHANGED: case NOTIFY_PEER_MTU_CHANGED: debugf(NHRP_DEBUG_COMMON, "NHS: Flush timer for %s", sockunion2str(&r->peer->vc->remote.nbma, buf, sizeof buf)); THREAD_TIMER_OFF(r->t_register); THREAD_TIMER_MSEC_ON(master, r->t_register, nhrp_reg_send_req, r, 10); break; } } static int nhrp_reg_send_req(struct thread *t) { struct nhrp_registration *r = THREAD_ARG(t); struct nhrp_nhs *nhs = r->nhs; char buf1[SU_ADDRSTRLEN], buf2[SU_ADDRSTRLEN]; struct interface *ifp = nhs->ifp; struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad = &nifp->afi[nhs->afi]; union sockunion *dst_proto; struct zbuf *zb; struct nhrp_packet_header *hdr; struct nhrp_extension_header *ext; struct nhrp_cie_header *cie; r->t_register = NULL; if (!nhrp_peer_check(r->peer, 2)) { debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %s", sockunion2str(&r->peer->vc->remote.nbma, buf1, sizeof buf1)); THREAD_TIMER_ON(master, r->t_register, nhrp_reg_send_req, r, 120); return 0; } THREAD_TIMER_ON(master, r->t_register, nhrp_reg_timeout, r, r->timeout); /* RFC2332 5.2.3 NHC uses it's own address as dst if NHS is unknown */ dst_proto = &nhs->proto_addr; if (sockunion_family(dst_proto) == AF_UNSPEC) dst_proto = &if_ad->addr; sockunion2str(&if_ad->addr, buf1, sizeof(buf1)); sockunion2str(dst_proto, buf2, sizeof(buf2)); debugf(NHRP_DEBUG_COMMON, "NHS: Register %s -> %s (timeout %d)", buf1, buf2, r->timeout); /* No protocol address configured for tunnel interface */ if (sockunion_family(&if_ad->addr) == AF_UNSPEC) return 0; zb = zbuf_alloc(1400); hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST, &nifp->nbma, &if_ad->addr, dst_proto); hdr->hop_count = 1; if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE)) hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE); hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &r->reqid, nhrp_reg_reply)); /* FIXME: push CIE for each local protocol address */ cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL); cie->prefix_length = 0xff; cie->holding_time = htons(if_ad->holdtime); cie->mtu = htons(if_ad->mtu); nhrp_ext_request(zb, hdr, ifp); /* Cisco NAT detection extension */ hdr->flags |= htons(NHRP_FLAG_REGISTRATION_NAT); ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr); cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr); nhrp_ext_complete(zb, ext); nhrp_packet_complete(zb, hdr); nhrp_peer_send(r->peer, zb); zbuf_free(zb); return 0; } static void nhrp_reg_delete(struct nhrp_registration *r) { nhrp_peer_notify_del(r->peer, &r->peer_notifier); nhrp_peer_unref(r->peer); list_del(&r->reglist_entry); THREAD_OFF(r->t_register); XFREE(MTYPE_NHRP_REGISTRATION, r); } static struct nhrp_registration *nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr) { struct nhrp_registration *r; list_for_each_entry(r, &nhs->reglist_head, reglist_entry) if (sockunion_same(&r->peer->vc->remote.nbma, nbma_addr)) return r; return NULL; } static void nhrp_nhs_resolve_cb(struct resolver_query *q, int n, union sockunion *addrs) { struct nhrp_nhs *nhs = container_of(q, struct nhrp_nhs, dns_resolve); struct nhrp_interface *nifp = nhs->ifp->info; struct nhrp_registration *reg, *regn; int i; nhs->t_resolve = NULL; if (n < 0) { /* Failed, retry in a moment */ THREAD_TIMER_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 5); return; } THREAD_TIMER_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 2*60*60); list_for_each_entry(reg, &nhs->reglist_head, reglist_entry) reg->mark = 1; nhs->hub = 0; for (i = 0; i < n; i++) { if (sockunion_same(&addrs[i], &nifp->nbma)) { nhs->hub = 1; continue; } reg = nhrp_reg_by_nbma(nhs, &addrs[i]); if (reg) { reg->mark = 0; continue; } reg = XCALLOC(MTYPE_NHRP_REGISTRATION, sizeof(*reg)); reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]); reg->nhs = nhs; reg->timeout = 1; list_init(®->reglist_entry); list_add_tail(®->reglist_entry, &nhs->reglist_head); nhrp_peer_notify_add(reg->peer, ®->peer_notifier, nhrp_reg_peer_notify); THREAD_TIMER_MSEC_ON(master, reg->t_register, nhrp_reg_send_req, reg, 50); } list_for_each_entry_safe(reg, regn, &nhs->reglist_head, reglist_entry) { if (reg->mark) nhrp_reg_delete(reg); } } static int nhrp_nhs_resolve(struct thread *t) { struct nhrp_nhs *nhs = THREAD_ARG(t); resolver_resolve(&nhs->dns_resolve, AF_INET, nhs->nbma_fqdn, nhrp_nhs_resolve_cb); return 0; } int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn) { struct nhrp_interface *nifp = ifp->info; struct nhrp_nhs *nhs; if (sockunion_family(proto_addr) != AF_UNSPEC && sockunion_family(proto_addr) != afi2family(afi)) return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH; list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) { if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC && sockunion_family(proto_addr) != AF_UNSPEC && sockunion_same(&nhs->proto_addr, proto_addr)) return NHRP_ERR_ENTRY_EXISTS; if (strcmp(nhs->nbma_fqdn, nbma_fqdn) == 0) return NHRP_ERR_ENTRY_EXISTS; } nhs = XMALLOC(MTYPE_NHRP_NHS, sizeof(struct nhrp_nhs)); if (!nhs) return NHRP_ERR_NO_MEMORY; *nhs = (struct nhrp_nhs) { .afi = afi, .ifp = ifp, .proto_addr = *proto_addr, .nbma_fqdn = strdup(nbma_fqdn), .reglist_head = LIST_INITIALIZER(nhs->reglist_head), }; list_add_tail(&nhs->nhslist_entry, &nifp->afi[afi].nhslist_head); THREAD_TIMER_MSEC_ON(master, nhs->t_resolve, nhrp_nhs_resolve, nhs, 1000); return NHRP_OK; } int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn) { struct nhrp_interface *nifp = ifp->info; struct nhrp_nhs *nhs, *nnhs; int ret = NHRP_ERR_ENTRY_NOT_FOUND; if (sockunion_family(proto_addr) != AF_UNSPEC && sockunion_family(proto_addr) != afi2family(afi)) return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH; list_for_each_entry_safe(nhs, nnhs, &nifp->afi[afi].nhslist_head, nhslist_entry) { if (!sockunion_same(&nhs->proto_addr, proto_addr)) continue; if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0) continue; nhrp_nhs_free(nhs); ret = NHRP_OK; } return ret; } int nhrp_nhs_free(struct nhrp_nhs *nhs) { struct nhrp_registration *r, *rn; list_for_each_entry_safe(r, rn, &nhs->reglist_head, reglist_entry) nhrp_reg_delete(r); THREAD_OFF(nhs->t_resolve); list_del(&nhs->nhslist_entry); free((void*) nhs->nbma_fqdn); XFREE(MTYPE_NHRP_NHS, nhs); return 0; } void nhrp_nhs_terminate(void) { struct interface *ifp; struct nhrp_interface *nifp; struct nhrp_nhs *nhs, *tmp; struct listnode *node; afi_t afi; for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { nifp = ifp->info; for (afi = 0; afi < AFI_MAX; afi++) { list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head, nhslist_entry) nhrp_nhs_free(nhs); } } } void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, void *), void *ctx) { struct nhrp_interface *nifp = ifp->info; struct nhrp_nhs *nhs; struct nhrp_registration *reg; list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) { if (!list_empty(&nhs->reglist_head)) { list_for_each_entry(reg, &nhs->reglist_head, reglist_entry) cb(nhs, reg, ctx); } else cb(nhs, 0, ctx); } } quagga-1.2.4/nhrpd/nhrp_packet.c000066400000000000000000000175641325323223500165550ustar00rootroot00000000000000/* NHRP packet handling functions * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include "nhrpd.h" #include "zbuf.h" #include "thread.h" #include "hash.h" #include "nhrp_protocol.h" #include "os.h" struct nhrp_reqid_pool nhrp_packet_reqid; static uint16_t family2proto(int family) { switch (family) { case AF_INET: return ETH_P_IP; case AF_INET6: return ETH_P_IPV6; } return 0; } static int proto2family(uint16_t proto) { switch (proto) { case ETH_P_IP: return AF_INET; case ETH_P_IPV6: return AF_INET6; } return AF_UNSPEC; } struct nhrp_packet_header *nhrp_packet_push( struct zbuf *zb, uint8_t type, const union sockunion *src_nbma, const union sockunion *src_proto, const union sockunion *dst_proto) { struct nhrp_packet_header *hdr; hdr = zbuf_push(zb, struct nhrp_packet_header); if (!hdr) return NULL; *hdr = (struct nhrp_packet_header) { .afnum = htons(family2afi(sockunion_family(src_nbma))), .protocol_type = htons(family2proto(sockunion_family(src_proto))), .version = NHRP_VERSION_RFC2332, .type = type, .hop_count = 64, .src_nbma_address_len = sockunion_get_addrlen(src_nbma), .src_protocol_address_len = sockunion_get_addrlen(src_proto), .dst_protocol_address_len = sockunion_get_addrlen(dst_proto), }; zbuf_put(zb, sockunion_get_addr(src_nbma), hdr->src_nbma_address_len); zbuf_put(zb, sockunion_get_addr(src_proto), hdr->src_protocol_address_len); zbuf_put(zb, sockunion_get_addr(dst_proto), hdr->dst_protocol_address_len); return hdr; } struct nhrp_packet_header *nhrp_packet_pull( struct zbuf *zb, union sockunion *src_nbma, union sockunion *src_proto, union sockunion *dst_proto) { struct nhrp_packet_header *hdr; hdr = zbuf_pull(zb, struct nhrp_packet_header); if (!hdr) return NULL; sockunion_set( src_nbma, afi2family(htons(hdr->afnum)), zbuf_pulln(zb, hdr->src_nbma_address_len + hdr->src_nbma_subaddress_len), hdr->src_nbma_address_len + hdr->src_nbma_subaddress_len); sockunion_set( src_proto, proto2family(htons(hdr->protocol_type)), zbuf_pulln(zb, hdr->src_protocol_address_len), hdr->src_protocol_address_len); sockunion_set( dst_proto, proto2family(htons(hdr->protocol_type)), zbuf_pulln(zb, hdr->dst_protocol_address_len), hdr->dst_protocol_address_len); return hdr; } uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len) { const uint16_t *pdu16 = (const uint16_t *) pdu; uint32_t csum = 0; int i; for (i = 0; i < len / 2; i++) csum += pdu16[i]; if (len & 1) csum += htons(pdu[len - 1]); while (csum & 0xffff0000) csum = (csum & 0xffff) + (csum >> 16); return (~csum) & 0xffff; } void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr) { unsigned short size; if (hdr->extension_offset) nhrp_ext_push(zb, hdr, NHRP_EXTENSION_END | NHRP_EXTENSION_FLAG_COMPULSORY); size = zb->tail - (uint8_t *)hdr; hdr->packet_size = htons(size); hdr->checksum = 0; hdr->checksum = nhrp_packet_calculate_checksum((uint8_t *) hdr, size); } struct nhrp_cie_header *nhrp_cie_push( struct zbuf *zb, uint8_t code, const union sockunion *nbma, const union sockunion *proto) { struct nhrp_cie_header *cie; cie = zbuf_push(zb, struct nhrp_cie_header); *cie = (struct nhrp_cie_header) { .code = code, }; if (nbma) { cie->nbma_address_len = sockunion_get_addrlen(nbma); zbuf_put(zb, sockunion_get_addr(nbma), cie->nbma_address_len); } if (proto) { cie->protocol_address_len = sockunion_get_addrlen(proto); zbuf_put(zb, sockunion_get_addr(proto), cie->protocol_address_len); } return cie; } struct nhrp_cie_header *nhrp_cie_pull( struct zbuf *zb, struct nhrp_packet_header *hdr, union sockunion *nbma, union sockunion *proto) { struct nhrp_cie_header *cie; cie = zbuf_pull(zb, struct nhrp_cie_header); if (!cie) return NULL; if (cie->nbma_address_len + cie->nbma_subaddress_len) { sockunion_set( nbma, afi2family(htons(hdr->afnum)), zbuf_pulln(zb, cie->nbma_address_len + cie->nbma_subaddress_len), cie->nbma_address_len + cie->nbma_subaddress_len); } else { sockunion_family(nbma) = AF_UNSPEC; } if (cie->protocol_address_len) { sockunion_set( proto, proto2family(htons(hdr->protocol_type)), zbuf_pulln(zb, cie->protocol_address_len), cie->protocol_address_len); } else { sockunion_family(proto) = AF_UNSPEC; } return cie; } struct nhrp_extension_header *nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type) { struct nhrp_extension_header *ext; ext = zbuf_push(zb, struct nhrp_extension_header); if (!ext) return NULL; if (!hdr->extension_offset) hdr->extension_offset = htons(zb->tail - (uint8_t*) hdr - sizeof(struct nhrp_extension_header)); *ext = (struct nhrp_extension_header) { .type = htons(type), .length = 0, }; return ext; } void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext) { ext->length = htons(zb->tail - (uint8_t*)ext - sizeof(struct nhrp_extension_header)); } struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, struct zbuf *payload) { struct nhrp_extension_header *ext; uint16_t plen; ext = zbuf_pull(zb, struct nhrp_extension_header); if (!ext) return NULL; plen = htons(ext->length); zbuf_init(payload, zbuf_pulln(zb, plen), plen, plen); return ext; } void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp) { /* Place holders for standard extensions */ nhrp_ext_push(zb, hdr, NHRP_EXTENSION_FORWARD_TRANSIT_NHS | NHRP_EXTENSION_FLAG_COMPULSORY); nhrp_ext_push(zb, hdr, NHRP_EXTENSION_REVERSE_TRANSIT_NHS | NHRP_EXTENSION_FLAG_COMPULSORY); nhrp_ext_push(zb, hdr, NHRP_EXTENSION_RESPONDER_ADDRESS | NHRP_EXTENSION_FLAG_COMPULSORY); } int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp, struct nhrp_extension_header *ext, struct zbuf *extpayload) { struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *ad = &nifp->afi[htons(hdr->afnum)]; struct nhrp_extension_header *dst; struct nhrp_cie_header *cie; uint16_t type; type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY; if (type == NHRP_EXTENSION_END) return 0; dst = nhrp_ext_push(zb, hdr, htons(ext->type)); if (!dst) goto err; switch (type) { case NHRP_EXTENSION_RESPONDER_ADDRESS: cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &ad->addr); if (!cie) goto err; cie->holding_time = htons(ad->holdtime); break; default: if (type & NHRP_EXTENSION_FLAG_COMPULSORY) goto err; case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: case NHRP_EXTENSION_REVERSE_TRANSIT_NHS: /* Supported compulsory extensions, and any * non-compulsory that is not explicitly handled, * should be just copied. */ zbuf_copy(zb, extpayload, zbuf_used(extpayload)); break; } nhrp_ext_complete(zb, dst); return 0; err: zbuf_set_werror(zb); return -1; } static int nhrp_packet_recvraw(struct thread *t) { int fd = THREAD_FD(t), ifindex; struct zbuf *zb; struct interface *ifp; struct nhrp_peer *p; union sockunion remote_nbma; uint8_t addr[64]; size_t len, addrlen; thread_add_read(master, nhrp_packet_recvraw, 0, fd); zb = zbuf_alloc(1500); if (!zb) return 0; len = zbuf_size(zb); addrlen = sizeof(addr); if (os_recvmsg(zb->buf, &len, &ifindex, addr, &addrlen) < 0) goto err; zb->head = zb->buf; zb->tail = zb->buf + len; switch (addrlen) { case 4: sockunion_set(&remote_nbma, AF_INET, addr, addrlen); break; default: goto err; } ifp = if_lookup_by_index(ifindex); if (!ifp) goto err; p = nhrp_peer_get(ifp, &remote_nbma); if (!p) goto err; nhrp_peer_recv(p, zb); nhrp_peer_unref(p); return 0; err: zbuf_free(zb); return 0; } int nhrp_packet_init(void) { thread_add_read(master, nhrp_packet_recvraw, 0, os_socket()); return 0; } quagga-1.2.4/nhrpd/nhrp_peer.c000066400000000000000000000566661325323223500162470ustar00rootroot00000000000000/* NHRP peer functions * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include "zebra.h" #include "memory.h" #include "thread.h" #include "hash.h" #include "nhrpd.h" #include "nhrp_protocol.h" #include "os.h" struct ipv6hdr { uint8_t priority_version; uint8_t flow_lbl[3]; uint16_t payload_len; uint8_t nexthdr; uint8_t hop_limit; struct in6_addr saddr; struct in6_addr daddr; }; static void nhrp_packet_debug(struct zbuf *zb, const char *dir); static void nhrp_peer_check_delete(struct nhrp_peer *p) { struct nhrp_interface *nifp = p->ifp->info; if (p->ref || notifier_active(&p->notifier_list)) return; THREAD_OFF(p->t_fallback); hash_release(nifp->peer_hash, p); nhrp_interface_notify_del(p->ifp, &p->ifp_notifier); nhrp_vc_notify_del(p->vc, &p->vc_notifier); XFREE(MTYPE_NHRP_PEER, p); } static int nhrp_peer_notify_up(struct thread *t) { struct nhrp_peer *p = THREAD_ARG(t); struct nhrp_vc *vc = p->vc; struct interface *ifp = p->ifp; struct nhrp_interface *nifp = ifp->info; p->t_fallback = NULL; if (nifp->enabled && (!nifp->ipsec_profile || vc->ipsec)) { p->online = 1; nhrp_peer_ref(p); notifier_call(&p->notifier_list, NOTIFY_PEER_UP); nhrp_peer_unref(p); } return 0; } static void __nhrp_peer_check(struct nhrp_peer *p) { struct nhrp_vc *vc = p->vc; struct interface *ifp = p->ifp; struct nhrp_interface *nifp = ifp->info; unsigned online; online = nifp->enabled && (!nifp->ipsec_profile || vc->ipsec); if (p->online != online) { THREAD_OFF(p->t_fallback); if (online && notifier_active(&p->notifier_list)) { /* If we requested the IPsec connection, delay * the up notification a bit to allow things * settle down. This allows IKE to install * SPDs and SAs. */ THREAD_TIMER_MSEC_ON( master, p->t_fallback, nhrp_peer_notify_up, p, 50); } else { nhrp_peer_ref(p); p->online = online; if (online) { notifier_call(&p->notifier_list, NOTIFY_PEER_UP); } else { p->requested = p->fallback_requested = 0; notifier_call(&p->notifier_list, NOTIFY_PEER_DOWN); } nhrp_peer_unref(p); } } } static void nhrp_peer_vc_notify(struct notifier_block *n, unsigned long cmd) { struct nhrp_peer *p = container_of(n, struct nhrp_peer, vc_notifier); switch (cmd) { case NOTIFY_VC_IPSEC_CHANGED: __nhrp_peer_check(p); break; case NOTIFY_VC_IPSEC_UPDATE_NBMA: nhrp_peer_ref(p); notifier_call(&p->notifier_list, NOTIFY_PEER_NBMA_CHANGING); nhrp_peer_unref(p); break; } } static void nhrp_peer_ifp_notify(struct notifier_block *n, unsigned long cmd) { struct nhrp_peer *p = container_of(n, struct nhrp_peer, ifp_notifier); struct nhrp_interface *nifp; struct nhrp_vc *vc; nhrp_peer_ref(p); switch (cmd) { case NOTIFY_INTERFACE_UP: case NOTIFY_INTERFACE_DOWN: __nhrp_peer_check(p); break; case NOTIFY_INTERFACE_NBMA_CHANGED: /* Source NBMA changed, rebind to new VC */ nifp = p->ifp->info; vc = nhrp_vc_get(&nifp->nbma, &p->vc->remote.nbma, 1); if (vc && p->vc != vc) { nhrp_vc_notify_del(p->vc, &p->vc_notifier); p->vc = vc; nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify); __nhrp_peer_check(p); } /* Fall-through to post config update */ case NOTIFY_INTERFACE_ADDRESS_CHANGED: notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED); break; case NOTIFY_INTERFACE_MTU_CHANGED: notifier_call(&p->notifier_list, NOTIFY_PEER_MTU_CHANGED); break; } nhrp_peer_unref(p); } static unsigned int nhrp_peer_key(void *peer_data) { struct nhrp_peer *p = peer_data; return sockunion_hash(&p->vc->remote.nbma); } static int nhrp_peer_cmp(const void *cache_data, const void *key_data) { const struct nhrp_peer *a = cache_data; const struct nhrp_peer *b = key_data; return a->ifp == b->ifp && a->vc == b->vc; } static void *nhrp_peer_create(void *data) { struct nhrp_peer *p, *key = data; p = XMALLOC(MTYPE_NHRP_PEER, sizeof(*p)); if (p) { *p = (struct nhrp_peer) { .ref = 0, .ifp = key->ifp, .vc = key->vc, .notifier_list = NOTIFIER_LIST_INITIALIZER(&p->notifier_list), }; nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify); nhrp_interface_notify_add(p->ifp, &p->ifp_notifier, nhrp_peer_ifp_notify); } return p; } struct nhrp_peer *nhrp_peer_get(struct interface *ifp, const union sockunion *remote_nbma) { struct nhrp_interface *nifp = ifp->info; struct nhrp_peer key, *p; struct nhrp_vc *vc; if (!nifp->peer_hash) { nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp); if (!nifp->peer_hash) return NULL; } vc = nhrp_vc_get(&nifp->nbma, remote_nbma, 1); if (!vc) return NULL; key.ifp = ifp; key.vc = vc; p = hash_get(nifp->peer_hash, &key, nhrp_peer_create); nhrp_peer_ref(p); if (p->ref == 1) __nhrp_peer_check(p); return p; } struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p) { if (p) p->ref++; return p; } void nhrp_peer_unref(struct nhrp_peer *p) { if (p) { p->ref--; nhrp_peer_check_delete(p); } } static int nhrp_peer_request_timeout(struct thread *t) { struct nhrp_peer *p = THREAD_ARG(t); struct nhrp_vc *vc = p->vc; struct interface *ifp = p->ifp; struct nhrp_interface *nifp = ifp->info; p->t_fallback = NULL; if (p->online) return 0; if (nifp->ipsec_fallback_profile && !p->prio && !p->fallback_requested) { p->fallback_requested = 1; vici_request_vc(nifp->ipsec_fallback_profile, &vc->local.nbma, &vc->remote.nbma, p->prio); THREAD_TIMER_ON(master, p->t_fallback, nhrp_peer_request_timeout, p, 30); } else { p->requested = p->fallback_requested = 0; } return 0; } int nhrp_peer_check(struct nhrp_peer *p, int establish) { struct nhrp_vc *vc = p->vc; struct interface *ifp = p->ifp; struct nhrp_interface *nifp = ifp->info; if (p->online) return 1; if (!establish) return 0; if (p->requested) return 0; if (!nifp->ipsec_profile) return 0; if (sockunion_family(&vc->local.nbma) == AF_UNSPEC) return 0; p->prio = establish > 1; p->requested = 1; vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, &vc->remote.nbma, p->prio); THREAD_TIMER_ON(master, p->t_fallback, nhrp_peer_request_timeout, p, (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30); return 0; } void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *n, notifier_fn_t fn) { notifier_add(n, &p->notifier_list, fn); } void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n) { notifier_del(n); nhrp_peer_check_delete(p); } void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb) { char buf[2][256]; nhrp_packet_debug(zb, "Send"); if (!p->online) return; debugf(NHRP_DEBUG_KERNEL, "PACKET: Send %s -> %s", sockunion2str(&p->vc->local.nbma, buf[0], sizeof buf[0]), sockunion2str(&p->vc->remote.nbma, buf[1], sizeof buf[1])); os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex, sockunion_get_addr(&p->vc->remote.nbma), sockunion_get_addrlen(&p->vc->remote.nbma)); zbuf_reset(zb); } static void nhrp_handle_resolution_req(struct nhrp_packet_parser *p) { struct zbuf *zb, payload; struct nhrp_packet_header *hdr; struct nhrp_cie_header *cie; struct nhrp_extension_header *ext; struct nhrp_interface *nifp; struct nhrp_peer *peer; if (!(p->if_ad->flags & NHRP_IFF_SHORTCUT)) { debugf(NHRP_DEBUG_COMMON, "Shortcuts disabled"); /* FIXME: Send error indication? */ return; } if (p->if_ad->network_id && p->route_type == NHRP_ROUTE_OFF_NBMA && p->route_prefix.prefixlen < 8) { debugf(NHRP_DEBUG_COMMON, "Shortcut to more generic than /8 dropped"); return; } debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Resolution Req"); if (nhrp_route_address(p->ifp, &p->src_proto, NULL, &peer) != NHRP_ROUTE_NBMA_NEXTHOP) return; #if 0 /* FIXME: Update requestors binding if CIE specifies holding time */ nhrp_cache_update_binding( NHRP_CACHE_CACHED, &p->src_proto, nhrp_peer_get(p->ifp, &p->src_nbma), htons(cie->holding_time)); #endif nifp = peer->ifp->info; /* Create reply */ zb = zbuf_alloc(1500); hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REPLY, &p->src_nbma, &p->src_proto, &p->dst_proto); /* Copied information from request */ hdr->flags = p->hdr->flags & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER|NHRP_FLAG_RESOLUTION_SOURCE_STABLE); hdr->flags |= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE | NHRP_FLAG_RESOLUTION_AUTHORATIVE); hdr->u.request_id = p->hdr->u.request_id; /* CIE payload */ cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &p->if_ad->addr); cie->holding_time = htons(p->if_ad->holdtime); cie->mtu = htons(p->if_ad->mtu); if (p->if_ad->network_id && p->route_type == NHRP_ROUTE_OFF_NBMA) cie->prefix_length = p->route_prefix.prefixlen; else cie->prefix_length = 8 * sockunion_get_addrlen(&p->if_ad->addr); /* Handle extensions */ while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) { switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { case NHRP_EXTENSION_NAT_ADDRESS: if (sockunion_family(&nifp->nat_nbma) == AF_UNSPEC) break; ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); if (!ext) goto err; cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nat_nbma, &p->if_ad->addr); if (!cie) goto err; nhrp_ext_complete(zb, ext); break; default: if (nhrp_ext_reply(zb, hdr, p->ifp, ext, &payload) < 0) goto err; break; } } nhrp_packet_complete(zb, hdr); nhrp_peer_send(peer, zb); err: nhrp_peer_unref(peer); zbuf_free(zb); } static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) { struct interface *ifp = p->ifp; struct zbuf *zb, payload; struct nhrp_packet_header *hdr; struct nhrp_cie_header *cie; struct nhrp_extension_header *ext; struct nhrp_cache *c; union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr, *nbma_natoa; int holdtime, prefix_len, hostprefix_len, natted = 0; size_t paylen; void *pay; debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Registration Req"); hostprefix_len = 8 * sockunion_get_addrlen(&p->if_ad->addr); if (!sockunion_same(&p->src_nbma, &p->peer->vc->remote.nbma)) natted = 1; /* Create reply */ zb = zbuf_alloc(1500); hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REPLY, &p->src_nbma, &p->src_proto, &p->if_ad->addr); /* Copied information from request */ hdr->flags = p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE | NHRP_FLAG_REGISTRATION_NAT); hdr->u.request_id = p->hdr->u.request_id; /* Copy payload CIEs */ paylen = zbuf_used(&p->payload); pay = zbuf_pushn(zb, paylen); if (!pay) goto err; memcpy(pay, zbuf_pulln(&p->payload, paylen), paylen); zbuf_init(&payload, pay, paylen, paylen); while ((cie = nhrp_cie_pull(&payload, hdr, &cie_nbma, &cie_proto)) != NULL) { prefix_len = cie->prefix_length; if (prefix_len == 0 || prefix_len >= hostprefix_len) prefix_len = hostprefix_len; if (prefix_len != hostprefix_len && !(p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) { cie->code = NHRP_CODE_BINDING_NON_UNIQUE; continue; } /* We currently support only unique prefix registrations */ if (prefix_len != hostprefix_len) { cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED; continue; } proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC) ? &p->src_proto : &cie_proto; nbma_addr = (sockunion_family(&cie_nbma) == AF_UNSPEC) ? &p->src_nbma : &cie_nbma; nbma_natoa = NULL; if (natted) { nbma_natoa = nbma_addr; nbma_addr = &p->peer->vc->remote.nbma; } holdtime = htons(cie->holding_time); if (!holdtime) holdtime = p->if_ad->holdtime; c = nhrp_cache_get(ifp, proto_addr, 1); if (!c) { cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES; continue; } if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime, nhrp_peer_ref(p->peer), htons(cie->mtu), nbma_natoa)) { cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED; continue; } cie->code = NHRP_CODE_SUCCESS; } /* Handle extensions */ while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) { switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { case NHRP_EXTENSION_NAT_ADDRESS: ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); if (!ext) goto err; zbuf_copy(zb, &payload, zbuf_used(&payload)); if (natted) { nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &p->peer->vc->remote.nbma, &p->src_proto); } nhrp_ext_complete(zb, ext); break; default: if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0) goto err; break; } } nhrp_packet_complete(zb, hdr); nhrp_peer_send(p->peer, zb); err: zbuf_free(zb); } static int parse_ether_packet(struct zbuf *zb, uint16_t protocol_type, union sockunion *src, union sockunion *dst) { switch (protocol_type) { case ETH_P_IP: { struct iphdr *iph = zbuf_pull(zb, struct iphdr); if (iph) { if (src) sockunion_set(src, AF_INET, (uint8_t*) &iph->saddr, sizeof(iph->saddr)); if (dst) sockunion_set(dst, AF_INET, (uint8_t*) &iph->daddr, sizeof(iph->daddr)); } } break; case ETH_P_IPV6: { struct ipv6hdr *iph = zbuf_pull(zb, struct ipv6hdr); if (iph) { if (src) sockunion_set(src, AF_INET6, (uint8_t*) &iph->saddr, sizeof(iph->saddr)); if (dst) sockunion_set(dst, AF_INET6, (uint8_t*) &iph->daddr, sizeof(iph->daddr)); } } break; default: return 0; } return 1; } void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, struct zbuf *pkt) { union sockunion dst; struct zbuf *zb, payload; struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad; struct nhrp_packet_header *hdr; struct nhrp_peer *p; char buf[2][SU_ADDRSTRLEN]; if (!nifp->enabled) return; payload = *pkt; if (!parse_ether_packet(&payload, protocol_type, &dst, NULL)) return; if (nhrp_route_address(ifp, &dst, NULL, &p) != NHRP_ROUTE_NBMA_NEXTHOP) return; if_ad = &nifp->afi[family2afi(sockunion_family(&dst))]; if (!(if_ad->flags & NHRP_IFF_REDIRECT)) { debugf(NHRP_DEBUG_COMMON, "Send Traffic Indication to %s about packet to %s ignored", sockunion2str(&p->vc->remote.nbma, buf[0], sizeof buf[0]), sockunion2str(&dst, buf[1], sizeof buf[1])); return; } debugf(NHRP_DEBUG_COMMON, "Send Traffic Indication to %s (online=%d) about packet to %s", sockunion2str(&p->vc->remote.nbma, buf[0], sizeof buf[0]), p->online, sockunion2str(&dst, buf[1], sizeof buf[1])); /* Create reply */ zb = zbuf_alloc(1500); hdr = nhrp_packet_push(zb, NHRP_PACKET_TRAFFIC_INDICATION, &nifp->nbma, &if_ad->addr, &dst); hdr->hop_count = 0; /* Payload is the packet causing indication */ zbuf_copy(zb, pkt, zbuf_used(pkt)); nhrp_packet_complete(zb, hdr); nhrp_peer_send(p, zb); nhrp_peer_unref(p); zbuf_free(zb); } static void nhrp_handle_error_ind(struct nhrp_packet_parser *pp) { struct zbuf origmsg = pp->payload; struct nhrp_packet_header *hdr; struct nhrp_reqid *reqid; union sockunion src_nbma, src_proto, dst_proto; char buf[2][SU_ADDRSTRLEN]; hdr = nhrp_packet_pull(&origmsg, &src_nbma, &src_proto, &dst_proto); if (!hdr) return; debugf(NHRP_DEBUG_COMMON, "Error Indication from %s about packet to %s ignored", sockunion2str(&pp->src_proto, buf[0], sizeof buf[0]), sockunion2str(&dst_proto, buf[1], sizeof buf[1])); reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id)); if (reqid) reqid->cb(reqid, pp); } static void nhrp_handle_traffic_ind(struct nhrp_packet_parser *p) { union sockunion dst; char buf[2][SU_ADDRSTRLEN]; if (!parse_ether_packet(&p->payload, htons(p->hdr->protocol_type), NULL, &dst)) return; debugf(NHRP_DEBUG_COMMON, "Traffic Indication from %s about packet to %s: %s", sockunion2str(&p->src_proto, buf[0], sizeof buf[0]), sockunion2str(&dst, buf[1], sizeof buf[1]), (p->if_ad->flags & NHRP_IFF_SHORTCUT) ? "trying shortcut" : "ignored"); if (p->if_ad->flags & NHRP_IFF_SHORTCUT) nhrp_shortcut_initiate(&dst); } enum packet_type_t { PACKET_UNKNOWN = 0, PACKET_REQUEST, PACKET_REPLY, PACKET_INDICATION, }; static struct { enum packet_type_t type; const char *name; void (*handler)(struct nhrp_packet_parser *); } packet_types[] = { [NHRP_PACKET_RESOLUTION_REQUEST] = { .type = PACKET_REQUEST, .name = "Resolution-Request", .handler = nhrp_handle_resolution_req, }, [NHRP_PACKET_RESOLUTION_REPLY] = { .type = PACKET_REPLY, .name = "Resolution-Reply", }, [NHRP_PACKET_REGISTRATION_REQUEST] = { .type = PACKET_REQUEST, .name = "Registration-Request", .handler = nhrp_handle_registration_request, }, [NHRP_PACKET_REGISTRATION_REPLY] = { .type = PACKET_REPLY, .name = "Registration-Reply", }, [NHRP_PACKET_PURGE_REQUEST] = { .type = PACKET_REQUEST, .name = "Purge-Request", }, [NHRP_PACKET_PURGE_REPLY] = { .type = PACKET_REPLY, .name = "Purge-Reply", }, [NHRP_PACKET_ERROR_INDICATION] = { .type = PACKET_INDICATION, .name = "Error-Indication", .handler = nhrp_handle_error_ind, }, [NHRP_PACKET_TRAFFIC_INDICATION] = { .type = PACKET_INDICATION, .name = "Traffic-Indication", .handler = nhrp_handle_traffic_ind, } }; static void nhrp_peer_forward(struct nhrp_peer *p, struct nhrp_packet_parser *pp) { struct zbuf *zb, extpl; struct nhrp_packet_header *hdr; struct nhrp_extension_header *ext, *dst; struct nhrp_cie_header *cie; struct nhrp_interface *nifp = pp->ifp->info; struct nhrp_afi_data *if_ad = pp->if_ad; union sockunion cie_nbma, cie_protocol; uint16_t type, len; if (pp->hdr->hop_count == 0) return; /* Create forward packet - copy header */ zb = zbuf_alloc(1500); hdr = nhrp_packet_push(zb, pp->hdr->type, &pp->src_nbma, &pp->src_proto, &pp->dst_proto); hdr->flags = pp->hdr->flags; hdr->hop_count = pp->hdr->hop_count - 1; hdr->u.request_id = pp->hdr->u.request_id; /* Copy payload */ zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload)); /* Copy extensions */ while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) { type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY; len = htons(ext->length); if (type == NHRP_EXTENSION_END) break; dst = nhrp_ext_push(zb, hdr, htons(ext->type)); if (!dst) goto err; switch (type) { case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: case NHRP_EXTENSION_REVERSE_TRANSIT_NHS: zbuf_put(zb, extpl.head, len); if ((type == NHRP_EXTENSION_REVERSE_TRANSIT_NHS) == (packet_types[hdr->type].type == PACKET_REPLY)) { /* Check NHS list for forwarding loop */ while ((cie = nhrp_cie_pull(&extpl, pp->hdr, &cie_nbma, &cie_protocol)) != NULL) { if (sockunion_same(&p->vc->remote.nbma, &cie_nbma)) goto err; } /* Append our selves to the list */ cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr); if (!cie) goto err; cie->holding_time = htons(if_ad->holdtime); } break; default: if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY) /* FIXME: RFC says to just copy, but not * append our selves to the transit NHS list */ goto err; case NHRP_EXTENSION_RESPONDER_ADDRESS: /* Supported compulsory extensions, and any * non-compulsory that is not explicitly handled, * should be just copied. */ zbuf_copy(zb, &extpl, len); break; } nhrp_ext_complete(zb, dst); } nhrp_packet_complete(zb, hdr); nhrp_peer_send(p, zb); zbuf_free(zb); return; err: nhrp_packet_debug(pp->pkt, "FWD-FAIL"); zbuf_free(zb); } static void nhrp_packet_debug(struct zbuf *zb, const char *dir) { char buf[2][SU_ADDRSTRLEN]; union sockunion src_nbma, src_proto, dst_proto; struct nhrp_packet_header *hdr; struct zbuf zhdr; int reply; if (likely(!(debug_flags & NHRP_DEBUG_COMMON))) return; zbuf_init(&zhdr, zb->buf, zb->tail-zb->buf, zb->tail-zb->buf); hdr = nhrp_packet_pull(&zhdr, &src_nbma, &src_proto, &dst_proto); sockunion2str(&src_proto, buf[0], sizeof buf[0]); sockunion2str(&dst_proto, buf[1], sizeof buf[1]); reply = packet_types[hdr->type].type == PACKET_REPLY; debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %s -> %s", dir, packet_types[hdr->type].name ? : "Unknown", hdr->type, reply ? buf[1] : buf[0], reply ? buf[0] : buf[1]); } static int proto2afi(uint16_t proto) { switch (proto) { case ETH_P_IP: return AFI_IP; case ETH_P_IPV6: return AFI_IP6; } return AF_UNSPEC; } struct nhrp_route_info { int local; struct interface *ifp; struct nhrp_vc *vc; }; void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) { char buf[2][SU_ADDRSTRLEN]; struct nhrp_packet_header *hdr; struct nhrp_vc *vc = p->vc; struct interface *ifp = p->ifp; struct nhrp_interface *nifp = ifp->info; struct nhrp_packet_parser pp; struct nhrp_peer *peer = NULL; struct nhrp_reqid *reqid; const char *info = NULL; union sockunion *target_addr; unsigned paylen, extoff, extlen, realsize; afi_t nbma_afi, proto_afi; debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %s -> %s", sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]), sockunion2str(&vc->local.nbma, buf[1], sizeof buf[1])); if (!p->online) { info = "peer not online"; goto drop; } if (nhrp_packet_calculate_checksum(zb->head, zbuf_used(zb)) != 0) { info = "bad checksum"; goto drop; } realsize = zbuf_used(zb); hdr = nhrp_packet_pull(zb, &pp.src_nbma, &pp.src_proto, &pp.dst_proto); if (!hdr) { info = "corrupt header"; goto drop; } pp.ifp = ifp; pp.pkt = zb; pp.hdr = hdr; pp.peer = p; nbma_afi = htons(hdr->afnum); proto_afi = proto2afi(htons(hdr->protocol_type)); if (hdr->type > ZEBRA_NUM_OF(packet_types) || hdr->version != NHRP_VERSION_RFC2332 || nbma_afi >= AFI_MAX || proto_afi == AF_UNSPEC || packet_types[hdr->type].type == PACKET_UNKNOWN || htons(hdr->packet_size) > realsize) { zlog_info("From %s: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)", sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]), (int) hdr->type, (int) hdr->version, (int) nbma_afi, (int) htons(hdr->protocol_type), (int) htons(hdr->packet_size), (int) realsize); goto drop; } pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[proto_afi]; extoff = htons(hdr->extension_offset); if (extoff) { if (extoff >= realsize) { info = "extoff larger than packet"; goto drop; } paylen = extoff - (zb->head - zb->buf); } else { paylen = zbuf_used(zb); } zbuf_init(&pp.payload, zbuf_pulln(zb, paylen), paylen, paylen); extlen = zbuf_used(zb); zbuf_init(&pp.extensions, zbuf_pulln(zb, extlen), extlen, extlen); if (!nifp->afi[proto_afi].network_id) { info = "nhrp not enabled"; goto drop; } nhrp_packet_debug(zb, "Recv"); /* FIXME: Check authentication here. This extension needs to be * pre-handled. */ /* Figure out if this is local */ target_addr = (packet_types[hdr->type].type == PACKET_REPLY) ? &pp.src_proto : &pp.dst_proto; if (sockunion_same(&pp.src_proto, &pp.dst_proto)) pp.route_type = NHRP_ROUTE_LOCAL; else pp.route_type = nhrp_route_address(pp.ifp, target_addr, &pp.route_prefix, &peer); switch (pp.route_type) { case NHRP_ROUTE_LOCAL: nhrp_packet_debug(zb, "!LOCAL"); if (packet_types[hdr->type].type == PACKET_REPLY) { reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id)); if (reqid) { reqid->cb(reqid, &pp); break; } else { nhrp_packet_debug(zb, "!UNKNOWN-REQID"); /* FIXME: send error-indication */ } } case NHRP_ROUTE_OFF_NBMA: if (packet_types[hdr->type].handler) { packet_types[hdr->type].handler(&pp); break; } break; case NHRP_ROUTE_NBMA_NEXTHOP: nhrp_peer_forward(peer, &pp); break; case NHRP_ROUTE_BLACKHOLE: break; } drop: if (info) { zlog_info("From %s: error: %s", sockunion2str(&vc->remote.nbma, buf[0], sizeof buf[0]), info); } if (peer) nhrp_peer_unref(peer); zbuf_free(zb); } quagga-1.2.4/nhrpd/nhrp_protocol.h000066400000000000000000000067251325323223500171510ustar00rootroot00000000000000/* nhrp_protocol.h - NHRP protocol definitions * * Copyright (c) 2007-2012 Timo Teräs * * This software is licensed under the MIT License. * See MIT-LICENSE.txt for additional details. */ #ifndef NHRP_PROTOCOL_H #define NHRP_PROTOCOL_H #include /* NHRP Ethernet protocol number */ #define ETH_P_NHRP 0x2001 /* NHRP Version */ #define NHRP_VERSION_RFC2332 1 /* NHRP Packet Types */ #define NHRP_PACKET_RESOLUTION_REQUEST 1 #define NHRP_PACKET_RESOLUTION_REPLY 2 #define NHRP_PACKET_REGISTRATION_REQUEST 3 #define NHRP_PACKET_REGISTRATION_REPLY 4 #define NHRP_PACKET_PURGE_REQUEST 5 #define NHRP_PACKET_PURGE_REPLY 6 #define NHRP_PACKET_ERROR_INDICATION 7 #define NHRP_PACKET_TRAFFIC_INDICATION 8 /* NHRP Extension Types */ #define NHRP_EXTENSION_FLAG_COMPULSORY 0x8000 #define NHRP_EXTENSION_END 0 #define NHRP_EXTENSION_PAYLOAD 0 #define NHRP_EXTENSION_RESPONDER_ADDRESS 3 #define NHRP_EXTENSION_FORWARD_TRANSIT_NHS 4 #define NHRP_EXTENSION_REVERSE_TRANSIT_NHS 5 #define NHRP_EXTENSION_AUTHENTICATION 7 #define NHRP_EXTENSION_VENDOR 8 #define NHRP_EXTENSION_NAT_ADDRESS 9 /* NHRP Error Indication Codes */ #define NHRP_ERROR_UNRECOGNIZED_EXTENSION 1 #define NHRP_ERROR_LOOP_DETECTED 2 #define NHRP_ERROR_PROTOCOL_ADDRESS_UNREACHABLE 6 #define NHRP_ERROR_PROTOCOL_ERROR 7 #define NHRP_ERROR_SDU_SIZE_EXCEEDED 8 #define NHRP_ERROR_INVALID_EXTENSION 9 #define NHRP_ERROR_INVALID_RESOLUTION_REPLY 10 #define NHRP_ERROR_AUTHENTICATION_FAILURE 11 #define NHRP_ERROR_HOP_COUNT_EXCEEDED 15 /* NHRP CIE Codes */ #define NHRP_CODE_SUCCESS 0 #define NHRP_CODE_ADMINISTRATIVELY_PROHIBITED 4 #define NHRP_CODE_INSUFFICIENT_RESOURCES 5 #define NHRP_CODE_NO_BINDING_EXISTS 11 #define NHRP_CODE_BINDING_NON_UNIQUE 13 #define NHRP_CODE_UNIQUE_ADDRESS_REGISTERED 14 /* NHRP Flags for Resolution request/reply */ #define NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER 0x8000 #define NHRP_FLAG_RESOLUTION_AUTHORATIVE 0x4000 #define NHRP_FLAG_RESOLUTION_DESTINATION_STABLE 0x2000 #define NHRP_FLAG_RESOLUTION_UNIQUE 0x1000 #define NHRP_FLAG_RESOLUTION_SOURCE_STABLE 0x0800 #define NHRP_FLAG_RESOLUTION_NAT 0x0002 /* NHRP Flags for Registration request/reply */ #define NHRP_FLAG_REGISTRATION_UNIQUE 0x8000 #define NHRP_FLAG_REGISTRATION_NAT 0x0002 /* NHRP Flags for Purge request/reply */ #define NHRP_FLAG_PURGE_NO_REPLY 0x8000 /* NHRP Authentication extension types (ala Cisco) */ #define NHRP_AUTHENTICATION_PLAINTEXT 0x00000001 /* NHRP Packet Structures */ struct nhrp_packet_header { /* Fixed header */ uint16_t afnum; uint16_t protocol_type; uint8_t snap[5]; uint8_t hop_count; uint16_t packet_size; uint16_t checksum; uint16_t extension_offset; uint8_t version; uint8_t type; uint8_t src_nbma_address_len; uint8_t src_nbma_subaddress_len; /* Mandatory header */ uint8_t src_protocol_address_len; uint8_t dst_protocol_address_len; uint16_t flags; union { uint32_t request_id; struct { uint16_t code; uint16_t offset; } error; } u; } __attribute__((packed)); struct nhrp_cie_header { uint8_t code; uint8_t prefix_length; uint16_t unused; uint16_t mtu; uint16_t holding_time; uint8_t nbma_address_len; uint8_t nbma_subaddress_len; uint8_t protocol_address_len; uint8_t preference; } __attribute__((packed)); struct nhrp_extension_header { uint16_t type; uint16_t length; } __attribute__((packed)); struct nhrp_cisco_authentication_extension { uint32_t type; uint8_t secret[8]; } __attribute__((packed)); #endif quagga-1.2.4/nhrpd/nhrp_route.c000066400000000000000000000246331325323223500164370ustar00rootroot00000000000000/* NHRP routing functions * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include "nhrpd.h" #include "table.h" #include "memory.h" #include "stream.h" #include "log.h" #include "zclient.h" static struct zclient *zclient; static struct route_table *zebra_rib[AFI_MAX]; struct route_info { union sockunion via; struct interface *ifp; struct interface *nhrp_ifp; }; static void nhrp_zebra_connected(struct zclient *zclient) { /* No real VRF support yet -- bind only to the default vrf */ zclient_send_requests (zclient, VRF_DEFAULT); } static struct route_node *nhrp_route_update_get(const struct prefix *p, int create) { struct route_node *rn; afi_t afi = family2afi(PREFIX_FAMILY(p)); if (!zebra_rib[afi]) return NULL; if (create) { rn = route_node_get(zebra_rib[afi], p); if (!rn->info) { rn->info = XCALLOC(MTYPE_NHRP_ROUTE, sizeof(struct route_info)); route_lock_node(rn); } return rn; } else { return route_node_lookup(zebra_rib[afi], p); } } static void nhrp_route_update_put(struct route_node *rn) { struct route_info *ri = rn->info; if (!ri->ifp && !ri->nhrp_ifp && sockunion_family(&ri->via) == AF_UNSPEC) { XFREE(MTYPE_NHRP_ROUTE, rn->info); rn->info = NULL; route_unlock_node(rn); } route_unlock_node(rn); } static void nhrp_route_update_zebra(const struct prefix *p, union sockunion *nexthop, struct interface *ifp) { struct route_node *rn; struct route_info *ri; rn = nhrp_route_update_get(p, (sockunion_family(nexthop) != AF_UNSPEC) || ifp); if (rn) { ri = rn->info; ri->via = *nexthop; ri->ifp = ifp; nhrp_route_update_put(rn); } } void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp) { struct route_node *rn; struct route_info *ri; rn = nhrp_route_update_get(p, ifp != NULL); if (rn) { ri = rn->info; ri->nhrp_ifp = ifp; nhrp_route_update_put(rn); } } void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu) { int flags = 0; if (zclient->sock < 0) return; switch (type) { case NHRP_CACHE_NEGATIVE: SET_FLAG(flags, ZEBRA_FLAG_REJECT); break; case NHRP_CACHE_DYNAMIC: case NHRP_CACHE_NHS: case NHRP_CACHE_STATIC: /* Regular route, so these are announced * to other routing daemons */ break; default: SET_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE); break; } SET_FLAG(flags, ZEBRA_FLAG_INTERNAL); if (p->family == AF_INET) { struct in_addr *nexthop_ipv4; struct zapi_ipv4 api; memset(&api, 0, sizeof(api)); api.flags = flags; api.type = ZEBRA_ROUTE_NHRP; api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if (nexthop) { nexthop_ipv4 = (struct in_addr *) sockunion_get_addr(nexthop); api.nexthop_num = 1; api.nexthop = &nexthop_ipv4; } if (ifp) { SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifp->ifindex; } if (mtu) { SET_FLAG(api.message, ZAPI_MESSAGE_MTU); api.mtu = mtu; } if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra send: IPv4 route %s %s/%d nexthop %s metric %u" " count %d dev %s", add ? "add" : "del", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, nexthop ? inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])) : "", api.metric, api.nexthop_num, ifp->name); } zapi_ipv4_route( add ? ZEBRA_IPV4_ROUTE_ADD : ZEBRA_IPV4_ROUTE_DELETE, zclient, (struct prefix_ipv4 *) p, &api); } else if (p->family == AF_INET6) { struct in6_addr *nexthop_ipv6; struct zapi_ipv6 api; memset(&api, 0, sizeof(api)); api.flags = flags; api.type = ZEBRA_ROUTE_NHRP; api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if (nexthop) { nexthop_ipv6 = (struct in6_addr *) sockunion_get_addr(nexthop); api.nexthop_num = 1; api.nexthop = &nexthop_ipv6; } if (ifp) { SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifp->ifindex; } if (mtu) { SET_FLAG(api.message, ZAPI_MESSAGE_MTU); api.mtu = mtu; } if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra send: IPv6 route %s %s/%d nexthop %s metric %u" " count %d dev %s", add ? "add" : "del", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, nexthop ? inet_ntop(AF_INET6, api.nexthop[0], buf[1], sizeof(buf[1])) : "", api.metric, api.nexthop_num, ifp->name); } zapi_ipv6_route( add ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE, zclient, (struct prefix_ipv6 *) p, &api); } } int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp = NULL; struct prefix prefix; union sockunion nexthop_addr; unsigned char message, nexthop_num, ifindex_num; unsigned ifindex; char buf[2][PREFIX_STRLEN]; int i, afaddrlen, added; s = zclient->ibuf; memset(&prefix, 0, sizeof(prefix)); sockunion_family(&nexthop_addr) = AF_UNSPEC; /* Type, flags, message. */ /*type =*/ stream_getc(s); /*flags =*/ stream_getc(s); message = stream_getc(s); /* Prefix */ switch (cmd) { case ZEBRA_IPV4_ROUTE_ADD: case ZEBRA_IPV4_ROUTE_DELETE: prefix.family = AF_INET; break; case ZEBRA_IPV6_ROUTE_ADD: case ZEBRA_IPV6_ROUTE_DELETE: prefix.family = AF_INET6; break; default: return -1; } afaddrlen = family2addrsize(prefix.family); prefix.prefixlen = stream_getc(s); stream_get(&prefix.u.val, s, PSIZE(prefix.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX)) { nexthop_num = stream_getc(s); for (i = 0; i < nexthop_num; i++) { stream_get(buf[0], s, afaddrlen); if (i == 0) sockunion_set(&nexthop_addr, prefix.family, (u_char*) buf[0], afaddrlen); } ifindex_num = stream_getc(s); for (i = 0; i < ifindex_num; i++) { ifindex = stream_getl(s); if (i == 0 && ifindex != IFINDEX_INTERNAL) ifp = if_lookup_by_index(ifindex); } } if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE)) /*distance =*/ stream_getc(s); if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC)) /*metric =*/ stream_getl(s); added = (cmd == ZEBRA_IPV4_ROUTE_ADD || cmd == ZEBRA_IPV6_ROUTE_ADD); debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %s via %s dev %s", added ? "add" : "del", prefix2str(&prefix, buf[0], sizeof buf[0]), sockunion2str(&nexthop_addr, buf[1], sizeof buf[1]), ifp ? ifp->name : "(none)"); nhrp_route_update_zebra(&prefix, &nexthop_addr, ifp); nhrp_shortcut_prefix_change(&prefix, !added); return 0; } int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p, union sockunion *via, struct interface **ifp) { struct route_node *rn; struct route_info *ri; struct prefix lookup; afi_t afi = family2afi(sockunion_family(addr)); char buf[PREFIX_STRLEN]; sockunion2hostprefix(addr, &lookup); rn = route_node_match(zebra_rib[afi], &lookup); if (!rn) return 0; ri = rn->info; if (ri->nhrp_ifp) { debugf(NHRP_DEBUG_ROUTE, "lookup %s: nhrp_if=%s", prefix2str(&lookup, buf, sizeof buf), ri->nhrp_ifp->name); if (via) sockunion_family(via) = AF_UNSPEC; if (ifp) *ifp = ri->nhrp_ifp; } else { debugf(NHRP_DEBUG_ROUTE, "lookup %s: zebra route dev %s", prefix2str(&lookup, buf, sizeof buf), ri->ifp ? ri->ifp->name : "(none)"); if (via) *via = ri->via; if (ifp) *ifp = ri->ifp; } if (p) *p = rn->p; route_unlock_node(rn); return 1; } enum nhrp_route_type nhrp_route_address(struct interface *in_ifp, union sockunion *addr, struct prefix *p, struct nhrp_peer **peer) { struct interface *ifp = in_ifp; struct nhrp_interface *nifp; struct nhrp_cache *c; union sockunion via[4]; uint32_t network_id = 0; afi_t afi = family2afi(sockunion_family(addr)); int i; if (ifp) { nifp = ifp->info; network_id = nifp->afi[afi].network_id; c = nhrp_cache_get(ifp, addr, 0); if (c && c->cur.type == NHRP_CACHE_LOCAL) { if (p) memset(p, 0, sizeof(*p)); return NHRP_ROUTE_LOCAL; } } for (i = 0; i < 4; i++) { if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp)) return NHRP_ROUTE_BLACKHOLE; if (ifp) { /* Departing from nbma network? */ nifp = ifp->info; if (network_id && network_id != nifp->afi[afi].network_id) return NHRP_ROUTE_OFF_NBMA; } if (sockunion_family(&via[i]) == AF_UNSPEC) break; /* Resolve via node, but return the prefix of first match */ addr = &via[i]; p = NULL; } if (ifp) { c = nhrp_cache_get(ifp, addr, 0); if (c && c->cur.type >= NHRP_CACHE_DYNAMIC) { if (p) memset(p, 0, sizeof(*p)); if (c->cur.type == NHRP_CACHE_LOCAL) return NHRP_ROUTE_LOCAL; if (peer) *peer = nhrp_peer_ref(c->cur.peer); return NHRP_ROUTE_NBMA_NEXTHOP; } } return NHRP_ROUTE_BLACKHOLE; } void nhrp_zebra_init(void) { zebra_rib[AFI_IP] = route_table_init(); zebra_rib[AFI_IP6] = route_table_init(); zclient = zclient_new(master); zclient->zebra_connected = nhrp_zebra_connected; zclient->interface_add = nhrp_interface_add; zclient->interface_delete = nhrp_interface_delete; zclient->interface_up = nhrp_interface_up; zclient->interface_down = nhrp_interface_down; zclient->interface_address_add = nhrp_interface_address_add; zclient->interface_address_delete = nhrp_interface_address_delete; zclient->ipv4_route_add = nhrp_route_read; zclient->ipv4_route_delete = nhrp_route_read; zclient->ipv6_route_add = nhrp_route_read; zclient->ipv6_route_delete = nhrp_route_read; zclient_init(zclient, ZEBRA_ROUTE_NHRP); zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_KERNEL, VRF_DEFAULT); zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_CONNECT, VRF_DEFAULT); zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_STATIC, VRF_DEFAULT); zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_RIP, VRF_DEFAULT); zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_OSPF, VRF_DEFAULT); zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_ISIS, VRF_DEFAULT); zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, ZEBRA_ROUTE_BGP, VRF_DEFAULT); } void nhrp_zebra_terminate(void) { zclient_stop(zclient); route_table_finish(zebra_rib[AFI_IP]); route_table_finish(zebra_rib[AFI_IP6]); } quagga-1.2.4/nhrpd/nhrp_shortcut.c000066400000000000000000000270301325323223500171460ustar00rootroot00000000000000/* NHRP shortcut related functions * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include "nhrpd.h" #include "table.h" #include "memory.h" #include "thread.h" #include "log.h" #include "nhrp_protocol.h" static struct route_table *shortcut_rib[AFI_MAX]; static int nhrp_shortcut_do_purge(struct thread *t); static void nhrp_shortcut_delete(struct nhrp_shortcut *s); static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s); static void nhrp_shortcut_check_use(struct nhrp_shortcut *s) { char buf[PREFIX_STRLEN]; if (s->expiring && s->cache && s->cache->used) { debugf(NHRP_DEBUG_ROUTE, "Shortcut %s used and expiring", prefix2str(s->p, buf, sizeof buf)); nhrp_shortcut_send_resolution_req(s); } } static int nhrp_shortcut_do_expire(struct thread *t) { struct nhrp_shortcut *s = THREAD_ARG(t); s->t_timer = NULL; THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, s->holding_time/3); s->expiring = 1; nhrp_shortcut_check_use(s); return 0; } static void nhrp_shortcut_cache_notify(struct notifier_block *n, unsigned long cmd) { struct nhrp_shortcut *s = container_of(n, struct nhrp_shortcut, cache_notifier); switch (cmd) { case NOTIFY_CACHE_UP: if (!s->route_installed) { nhrp_route_announce(1, s->type, s->p, NULL, &s->cache->remote_addr, 0); s->route_installed = 1; } break; case NOTIFY_CACHE_USED: nhrp_shortcut_check_use(s); break; case NOTIFY_CACHE_DOWN: case NOTIFY_CACHE_DELETE: if (s->route_installed) { nhrp_route_announce(0, NHRP_CACHE_INVALID, s->p, NULL, NULL, 0); s->route_installed = 0; } if (cmd == NOTIFY_CACHE_DELETE) nhrp_shortcut_delete(s); break; } } static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s, enum nhrp_cache_type type, struct nhrp_cache *c, int holding_time) { s->type = type; if (c != s->cache) { if (s->cache) { nhrp_cache_notify_del(s->cache, &s->cache_notifier); s->cache = NULL; } s->cache = c; if (s->cache) { nhrp_cache_notify_add(s->cache, &s->cache_notifier, nhrp_shortcut_cache_notify); if (s->cache->route_installed) { /* Force renewal of Zebra announce on prefix change */ s->route_installed = 0; nhrp_shortcut_cache_notify(&s->cache_notifier, NOTIFY_CACHE_UP); } } if (!s->cache || !s->cache->route_installed) nhrp_shortcut_cache_notify(&s->cache_notifier, NOTIFY_CACHE_DOWN); } if (s->type == NHRP_CACHE_NEGATIVE && !s->route_installed) { nhrp_route_announce(1, s->type, s->p, NULL, NULL, 0); s->route_installed = 1; } else if (s->type == NHRP_CACHE_INVALID && s->route_installed) { nhrp_route_announce(0, NHRP_CACHE_INVALID, s->p, NULL, NULL, 0); s->route_installed = 0; } THREAD_OFF(s->t_timer); if (holding_time) { s->expiring = 0; s->holding_time = holding_time; THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_expire, s, 2*holding_time/3); } } static void nhrp_shortcut_delete(struct nhrp_shortcut *s) { struct route_node *rn; afi_t afi = family2afi(PREFIX_FAMILY(s->p)); char buf[PREFIX_STRLEN]; THREAD_OFF(s->t_timer); nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); debugf(NHRP_DEBUG_ROUTE, "Shortcut %s purged", prefix2str(s->p, buf, sizeof buf)); nhrp_shortcut_update_binding(s, NHRP_CACHE_INVALID, NULL, 0); /* Delete node */ rn = route_node_lookup(shortcut_rib[afi], s->p); if (rn) { XFREE(MTYPE_NHRP_SHORTCUT, rn->info); rn->info = NULL; route_unlock_node(rn); route_unlock_node(rn); } } static int nhrp_shortcut_do_purge(struct thread *t) { struct nhrp_shortcut *s = THREAD_ARG(t); s->t_timer = NULL; nhrp_shortcut_delete(s); return 0; } static struct nhrp_shortcut *nhrp_shortcut_get(struct prefix *p) { struct nhrp_shortcut *s; struct route_node *rn; char buf[PREFIX_STRLEN]; afi_t afi = family2afi(PREFIX_FAMILY(p)); if (!shortcut_rib[afi]) return 0; rn = route_node_get(shortcut_rib[afi], p); if (!rn->info) { s = rn->info = XCALLOC(MTYPE_NHRP_SHORTCUT, sizeof(struct nhrp_shortcut)); s->type = NHRP_CACHE_INVALID; s->p = &rn->p; debugf(NHRP_DEBUG_ROUTE, "Shortcut %s created", prefix2str(s->p, buf, sizeof buf)); } else { s = rn->info; route_unlock_node(rn); } return s; } static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, void *arg) { struct nhrp_packet_parser *pp = arg; struct nhrp_shortcut *s = container_of(reqid, struct nhrp_shortcut, reqid); struct nhrp_shortcut *ps; struct nhrp_extension_header *ext; struct nhrp_cie_header *cie; struct nhrp_cache *c = NULL; union sockunion *proto, cie_proto, *nbma, *nbma_natoa, cie_nbma, nat_nbma; struct prefix prefix, route_prefix; struct zbuf extpl; char bufp[PREFIX_STRLEN], buf[3][SU_ADDRSTRLEN]; int holding_time = pp->if_ad->holdtime; nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); THREAD_OFF(s->t_timer); THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 1); if (pp->hdr->type != NHRP_PACKET_RESOLUTION_REPLY) { if (pp->hdr->type == NHRP_PACKET_ERROR_INDICATION && pp->hdr->u.error.code == NHRP_ERROR_PROTOCOL_ADDRESS_UNREACHABLE) { debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution: Protocol address unreachable"); nhrp_shortcut_update_binding(s, NHRP_CACHE_NEGATIVE, NULL, holding_time); } else { debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution failed"); } return; } /* Parse extensions */ memset(&nat_nbma, 0, sizeof nat_nbma); while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) { switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { case NHRP_EXTENSION_NAT_ADDRESS: nhrp_cie_pull(&extpl, pp->hdr, &nat_nbma, &cie_proto); break; } } /* Minor sanity check */ prefix2sockunion(s->p, &cie_proto); if (!sockunion_same(&cie_proto, &pp->dst_proto)) { debugf(NHRP_DEBUG_COMMON, "Shortcut: Warning dst_proto altered from %s to %s", sockunion2str(&cie_proto, buf[0], sizeof buf[0]), sockunion2str(&pp->dst_proto, buf[1], sizeof buf[1])); } /* One or more CIEs should be given as reply, we support only one */ cie = nhrp_cie_pull(&pp->payload, pp->hdr, &cie_nbma, &cie_proto); if (!cie || cie->code != NHRP_CODE_SUCCESS) { debugf(NHRP_DEBUG_COMMON, "Shortcut: CIE code %d", cie ? cie->code : -1); return; } proto = sockunion_family(&cie_proto) != AF_UNSPEC ? &cie_proto : &pp->dst_proto; if (cie->holding_time) holding_time = htons(cie->holding_time); prefix = *s->p; prefix.prefixlen = cie->prefix_length; /* Sanity check prefix length */ if (prefix.prefixlen >= 8*prefix_blen(&prefix) || prefix.prefixlen == 0) { prefix.prefixlen = 8*prefix_blen(&prefix); } else if (nhrp_route_address(NULL, &pp->dst_proto, &route_prefix, NULL) == NHRP_ROUTE_NBMA_NEXTHOP) { if (prefix.prefixlen < route_prefix.prefixlen) prefix.prefixlen = route_prefix.prefixlen; } debugf(NHRP_DEBUG_COMMON, "Shortcut: %s is at proto %s cie-nbma %s nat-nbma %s cie-holdtime %d", prefix2str(&prefix, bufp, sizeof bufp), sockunion2str(proto, buf[0], sizeof buf[0]), sockunion2str(&cie_nbma, buf[1], sizeof buf[1]), sockunion2str(&nat_nbma, buf[2], sizeof buf[2]), htons(cie->holding_time)); /* Update cache entry for the protocol to nbma binding */ if (sockunion_family(&nat_nbma) != AF_UNSPEC) { nbma = &nat_nbma; nbma_natoa = &cie_nbma; } else { nbma = &cie_nbma; nbma_natoa = NULL; } if (sockunion_family(nbma)) { c = nhrp_cache_get(pp->ifp, proto, 1); if (c) { nhrp_cache_update_binding( c, NHRP_CACHE_CACHED, holding_time, nhrp_peer_get(pp->ifp, nbma), htons(cie->mtu), nbma_natoa); } } /* Update shortcut entry for subnet to protocol gw binding */ if (c && !sockunion_same(proto, &pp->dst_proto)) { ps = nhrp_shortcut_get(&prefix); if (ps) { ps->addr = s->addr; nhrp_shortcut_update_binding(ps, NHRP_CACHE_CACHED, c, holding_time); } } debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution reply handled"); } static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) { struct zbuf *zb; struct nhrp_packet_header *hdr; struct interface *ifp; struct nhrp_interface *nifp; struct nhrp_peer *peer; if (nhrp_route_address(NULL, &s->addr, NULL, &peer) != NHRP_ROUTE_NBMA_NEXTHOP) return; if (s->type == NHRP_CACHE_INVALID || s->type == NHRP_CACHE_NEGATIVE) s->type = NHRP_CACHE_INCOMPLETE; ifp = peer->ifp; nifp = ifp->info; /* Create request */ zb = zbuf_alloc(1500); hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REQUEST, &nifp->nbma, &nifp->afi[family2afi(sockunion_family(&s->addr))].addr, &s->addr); hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid, nhrp_shortcut_recv_resolution_rep)); hdr->flags = htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER | NHRP_FLAG_RESOLUTION_AUTHORATIVE | NHRP_FLAG_RESOLUTION_SOURCE_STABLE); /* RFC2332 - One or zero CIEs, if CIE is present contains: * - Prefix length: widest acceptable prefix we accept (if U set, 0xff) * - MTU: MTU of the source station * - Holding Time: Max time to cache the source information * */ /* FIXME: Send holding time, and MTU */ nhrp_ext_request(zb, hdr, ifp); /* Cisco NAT detection extension */ hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT); nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); nhrp_packet_complete(zb, hdr); nhrp_peer_send(peer, zb); nhrp_peer_unref(peer); zbuf_free(zb); } void nhrp_shortcut_initiate(union sockunion *addr) { struct prefix p; struct nhrp_shortcut *s; sockunion2hostprefix(addr, &p); s = nhrp_shortcut_get(&p); if (s && s->type != NHRP_CACHE_INCOMPLETE) { s->addr = *addr; THREAD_OFF(s->t_timer); THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 30); nhrp_shortcut_send_resolution_req(s); } } void nhrp_shortcut_init(void) { shortcut_rib[AFI_IP] = route_table_init(); shortcut_rib[AFI_IP6] = route_table_init(); } void nhrp_shortcut_terminate(void) { route_table_finish(shortcut_rib[AFI_IP]); route_table_finish(shortcut_rib[AFI_IP6]); } void nhrp_shortcut_foreach(afi_t afi, void (*cb)(struct nhrp_shortcut *, void *), void *ctx) { struct route_table *rt = shortcut_rib[afi]; struct route_node *rn; route_table_iter_t iter; if (!rt) return; route_table_iter_init(&iter, rt); while ((rn = route_table_iter_next(&iter)) != NULL) { if (rn->info) cb(rn->info, ctx); } route_table_iter_cleanup(&iter); } struct purge_ctx { const struct prefix *p; int deleted; }; void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force) { THREAD_OFF(s->t_timer); nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); if (force) { /* Immediate purge on route with draw or pending shortcut */ THREAD_TIMER_MSEC_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 5); } else { /* Soft expire - force immediate renewal, but purge * in few seconds to make sure stale route is not * used too long. In practice most purges are caused * by hub bgp change, but target usually stays same. * This allows to keep nhrp route up, and to not * cause temporary rerouting via hubs causing latency * jitter. */ THREAD_TIMER_MSEC_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 3000); s->expiring = 1; nhrp_shortcut_check_use(s); } } static void nhrp_shortcut_purge_prefix(struct nhrp_shortcut *s, void *ctx) { struct purge_ctx *pctx = ctx; if (prefix_match(pctx->p, s->p)) nhrp_shortcut_purge(s, pctx->deleted || !s->cache); } void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted) { struct purge_ctx pctx = { .p = p, .deleted = deleted, }; nhrp_shortcut_foreach(family2afi(PREFIX_FAMILY(p)), nhrp_shortcut_purge_prefix, &pctx); } quagga-1.2.4/nhrpd/nhrp_vc.c000066400000000000000000000114501325323223500157020ustar00rootroot00000000000000/* NHRP virtual connection * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include "zebra.h" #include "memory.h" #include "stream.h" #include "hash.h" #include "thread.h" #include "jhash.h" #include "nhrpd.h" #include "os.h" struct child_sa { uint32_t id; struct nhrp_vc *vc; struct list_head childlist_entry; }; static struct hash *nhrp_vc_hash; static struct list_head childlist_head[512]; static unsigned int nhrp_vc_key(void *peer_data) { struct nhrp_vc *vc = peer_data; return jhash_2words( sockunion_hash(&vc->local.nbma), sockunion_hash(&vc->remote.nbma), 0); } static int nhrp_vc_cmp(const void *cache_data, const void *key_data) { const struct nhrp_vc *a = cache_data; const struct nhrp_vc *b = key_data; return sockunion_same(&a->local.nbma, &b->local.nbma) && sockunion_same(&a->remote.nbma, &b->remote.nbma); } static void *nhrp_vc_alloc(void *data) { struct nhrp_vc *vc, *key = data; vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc)); if (vc) { *vc = (struct nhrp_vc) { .local.nbma = key->local.nbma, .remote.nbma = key->remote.nbma, .notifier_list = NOTIFIER_LIST_INITIALIZER(&vc->notifier_list), }; } return vc; } static void nhrp_vc_free(void *data) { XFREE(MTYPE_NHRP_VC, data); } struct nhrp_vc *nhrp_vc_get(const union sockunion *src, const union sockunion *dst, int create) { struct nhrp_vc key; key.local.nbma = *src; key.remote.nbma = *dst; return hash_get(nhrp_vc_hash, &key, create ? nhrp_vc_alloc : 0); } static void nhrp_vc_check_delete(struct nhrp_vc *vc) { if (vc->updating || vc->ipsec || notifier_active(&vc->notifier_list)) return; hash_release(nhrp_vc_hash, vc); nhrp_vc_free(vc); } static void nhrp_vc_update(struct nhrp_vc *vc, long cmd) { vc->updating = 1; notifier_call(&vc->notifier_list, cmd); vc->updating = 0; nhrp_vc_check_delete(vc); } static void nhrp_vc_ipsec_reset(struct nhrp_vc *vc) { vc->local.id[0] = 0; vc->local.certlen = 0; vc->remote.id[0] = 0; vc->remote.certlen = 0; } int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) { char buf[2][SU_ADDRSTRLEN]; struct child_sa *sa = NULL, *lsa; uint32_t child_hash = child_id % ZEBRA_NUM_OF(childlist_head); int abort_migration = 0; list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) { if (lsa->id == child_id) { sa = lsa; break; } } if (!sa) { if (!vc) return 0; sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa)); if (!sa) return 0; *sa = (struct child_sa) { .id = child_id, .childlist_entry = LIST_INITIALIZER(sa->childlist_entry), .vc = NULL, }; list_add_tail(&sa->childlist_entry, &childlist_head[child_hash]); } if (sa->vc == vc) return 0; if (vc) { /* Attach first to new VC */ vc->ipsec++; nhrp_vc_update(vc, NOTIFY_VC_IPSEC_CHANGED); } if (sa->vc && vc) { /* Notify old VC of migration */ sa->vc->abort_migration = 0; debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s", sockunion2str(&sa->vc->remote.nbma, buf[0], sizeof buf[0]), sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1])); nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA); abort_migration = sa->vc->abort_migration; } if (sa->vc) { /* Deattach old VC */ sa->vc->ipsec--; if (!sa->vc->ipsec) nhrp_vc_ipsec_reset(sa->vc); nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED); } /* Update */ sa->vc = vc; if (!vc) { list_del(&sa->childlist_entry); XFREE(MTYPE_NHRP_VC, sa); } return abort_migration; } void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, notifier_fn_t action) { notifier_add(n, &vc->notifier_list, action); } void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n) { notifier_del(n); nhrp_vc_check_delete(vc); } struct nhrp_vc_iterator_ctx { void (*cb)(struct nhrp_vc *, void *); void *ctx; }; static void nhrp_vc_iterator(struct hash_backet *b, void *ctx) { struct nhrp_vc_iterator_ctx *ic = ctx; ic->cb(b->data, ic->ctx); } void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx) { struct nhrp_vc_iterator_ctx ic = { .cb = cb, .ctx = ctx, }; hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic); } void nhrp_vc_init(void) { size_t i; nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp); for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) list_init(&childlist_head[i]); } void nhrp_vc_reset(void) { struct child_sa *sa, *n; size_t i; for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) { list_for_each_entry_safe(sa, n, &childlist_head[i], childlist_entry) nhrp_vc_ipsec_updown(sa->id, 0); } } void nhrp_vc_terminate(void) { nhrp_vc_reset(); hash_clean(nhrp_vc_hash, nhrp_vc_free); } quagga-1.2.4/nhrpd/nhrp_vty.c000066400000000000000000000614231325323223500161210ustar00rootroot00000000000000/* NHRP vty handling * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include "zebra.h" #include "command.h" #include "zclient.h" #include "stream.h" #include "nhrpd.h" #include "netlink.h" static struct cmd_node zebra_node = { .node = ZEBRA_NODE, .prompt = "%s(config-router)# ", .vtysh = 1, }; static struct cmd_node nhrp_interface_node = { .node = INTERFACE_NODE, .prompt = "%s(config-if)# ", .vtysh = 1, }; #define NHRP_DEBUG_FLAGS_CMD "(all|common|event|interface|kernel|route|vici)" #define NHRP_DEBUG_FLAGS_STR \ "All messages\n" \ "Common messages (default)\n" \ "Event manager messages\n" \ "Interface messages\n" \ "Kernel messages\n" \ "Route messages\n" \ "VICI messages\n" static const struct message debug_flags_desc[] = { { NHRP_DEBUG_ALL, "all" }, { NHRP_DEBUG_COMMON, "common" }, { NHRP_DEBUG_IF, "interface" }, { NHRP_DEBUG_KERNEL, "kernel" }, { NHRP_DEBUG_ROUTE, "route" }, { NHRP_DEBUG_VICI, "vici" }, { NHRP_DEBUG_EVENT, "event" }, { 0, NULL }, }; static const struct message interface_flags_desc[] = { { NHRP_IFF_SHORTCUT, "shortcut" }, { NHRP_IFF_REDIRECT, "redirect" }, { NHRP_IFF_REG_NO_UNIQUE, "registration no-unique" }, { 0, NULL }, }; static int nhrp_vty_return(struct vty *vty, int ret) { static const char * const errmsgs[] = { [NHRP_ERR_FAIL] = "Command failed", [NHRP_ERR_NO_MEMORY] = "Out of memory", [NHRP_ERR_UNSUPPORTED_INTERFACE] = "NHRP not supported on this interface", [NHRP_ERR_NHRP_NOT_ENABLED] = "NHRP not enabled (set 'nhrp network-id' first)", [NHRP_ERR_ENTRY_EXISTS] = "Entry exists already", [NHRP_ERR_ENTRY_NOT_FOUND] = "Entry not found", [NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH] = "Protocol address family does not match command (ip/ipv6 mismatch)", }; const char *str = NULL; char buf[256]; if (ret == NHRP_OK) return CMD_SUCCESS; if (ret > 0 && ret <= (int)ZEBRA_NUM_OF(errmsgs)) if (errmsgs[ret]) str = errmsgs[ret]; if (!str) { str = buf; snprintf(buf, sizeof(buf), "Unknown error %d", ret); } vty_out (vty, "%% %s%s", str, VTY_NEWLINE); return CMD_WARNING; } static int toggle_flag( struct vty *vty, const struct message *flag_desc, const char *name, int on_off, unsigned *flags) { int i; for (i = 0; flag_desc[i].str != NULL; i++) { if (strcmp(flag_desc[i].str, name) != 0) continue; if (on_off) *flags |= flag_desc[i].key; else *flags &= ~flag_desc[i].key; return CMD_SUCCESS; } vty_out(vty, "%% Invalid value %s%s", name, VTY_NEWLINE); return CMD_WARNING; } #ifndef NO_DEBUG DEFUN(show_debugging_nhrp, show_debugging_nhrp_cmd, "show debugging nhrp", SHOW_STR "Debugging information\n" "NHRP configuration\n") { int i; vty_out(vty, "NHRP debugging status:%s", VTY_NEWLINE); for (i = 0; debug_flags_desc[i].str != NULL; i++) { if (debug_flags_desc[i].key == NHRP_DEBUG_ALL) continue; if (!(debug_flags_desc[i].key & debug_flags)) continue; vty_out(vty, " NHRP %s debugging is on%s", debug_flags_desc[i].str, VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN(debug_nhrp, debug_nhrp_cmd, "debug nhrp " NHRP_DEBUG_FLAGS_CMD, "Enable debug messages for specific or all parts.\n" "NHRP information\n" NHRP_DEBUG_FLAGS_STR) { return toggle_flag(vty, debug_flags_desc, argv[0], 1, &debug_flags); } DEFUN(no_debug_nhrp, no_debug_nhrp_cmd, "no debug nhrp " NHRP_DEBUG_FLAGS_CMD, NO_STR "Disable debug messages for specific or all parts.\n" "NHRP information\n" NHRP_DEBUG_FLAGS_STR) { return toggle_flag(vty, debug_flags_desc, argv[0], 0, &debug_flags); } #endif /* NO_DEBUG */ static int nhrp_config_write(struct vty *vty) { #ifndef NO_DEBUG if (debug_flags == NHRP_DEBUG_ALL) { vty_out(vty, "debug nhrp all%s", VTY_NEWLINE); } else { int i; for (i = 0; debug_flags_desc[i].str != NULL; i++) { if (debug_flags_desc[i].key == NHRP_DEBUG_ALL) continue; if (!(debug_flags & debug_flags_desc[i].key)) continue; vty_out(vty, "debug nhrp %s%s", debug_flags_desc[i].str, VTY_NEWLINE); } } vty_out(vty, "!%s", VTY_NEWLINE); #endif /* NO_DEBUG */ if (nhrp_event_socket_path) { vty_out(vty, "nhrp event socket %s%s", nhrp_event_socket_path, VTY_NEWLINE); } if (netlink_nflog_group) { vty_out(vty, "nhrp nflog-group %d%s", netlink_nflog_group, VTY_NEWLINE); } return 0; } #define IP_STR "IP information\n" #define IPV6_STR "IPv6 information\n" #define AFI_CMD "(ip|ipv6)" #define AFI_STR IP_STR IPV6_STR #define NHRP_STR "Next Hop Resolution Protocol functions\n" static afi_t cmd_to_afi(const char *cmd) { return strncmp(cmd, "ipv6", 4) == 0 ? AFI_IP6 : AFI_IP; } static const char *afi_to_cmd(afi_t afi) { if (afi == AFI_IP6) return "ipv6"; return "ip"; } DEFUN(nhrp_event_socket, nhrp_event_socket_cmd, "nhrp event socket SOCKET", NHRP_STR "Event Manager commands\n" "Event Manager unix socket path\n" "Unix path for the socket\n") { evmgr_set_socket(argv[0]); return CMD_SUCCESS; } DEFUN(no_nhrp_event_socket, no_nhrp_event_socket_cmd, "no nhrp event socket [SOCKET]", NO_STR NHRP_STR "Event Manager commands\n" "Event Manager unix socket path\n" "Unix path for the socket\n") { evmgr_set_socket(NULL); return CMD_SUCCESS; } DEFUN(nhrp_nflog_group, nhrp_nflog_group_cmd, "nhrp nflog-group <1-65535>", NHRP_STR "Specify NFLOG group number\n" "NFLOG group number\n") { uint32_t nfgroup; VTY_GET_INTEGER_RANGE("nflog-group", nfgroup, argv[0], 1, 65535); netlink_set_nflog_group(nfgroup); return CMD_SUCCESS; } DEFUN(no_nhrp_nflog_group, no_nhrp_nflog_group_cmd, "no nhrp nflog-group [<1-65535>]", NO_STR NHRP_STR "Specify NFLOG group number\n" "NFLOG group number\n") { netlink_set_nflog_group(0); return CMD_SUCCESS; } DEFUN(tunnel_protection, tunnel_protection_cmd, "tunnel protection vici profile PROFILE {fallback-profile FALLBACK}", "NHRP/GRE integration\n" "IPsec protection\n" "VICI (StrongSwan)\n" "IPsec profile\n" "IPsec profile name\n" "Fallback IPsec profile\n" "Fallback IPsec profile name\n") { struct interface *ifp = vty->index; nhrp_interface_set_protection(ifp, argv[0], argv[1]); return CMD_SUCCESS; } DEFUN(no_tunnel_protection, no_tunnel_protection_cmd, "no tunnel protection", NO_STR "NHRP/GRE integration\n" "IPsec protection\n") { struct interface *ifp = vty->index; nhrp_interface_set_protection(ifp, NULL, NULL); return CMD_SUCCESS; } DEFUN(tunnel_source, tunnel_source_cmd, "tunnel source INTERFACE", "NHRP/GRE integration\n" "Tunnel device binding tracking\n" "Interface name\n") { struct interface *ifp = vty->index; nhrp_interface_set_source(ifp, argv[0]); return CMD_SUCCESS; } DEFUN(no_tunnel_source, no_tunnel_source_cmd, "no tunnel source", "NHRP/GRE integration\n" "Tunnel device binding tracking\n" "Interface name\n") { struct interface *ifp = vty->index; nhrp_interface_set_source(ifp, NULL); return CMD_SUCCESS; } DEFUN(if_nhrp_network_id, if_nhrp_network_id_cmd, AFI_CMD " nhrp network-id <1-4294967295>", AFI_STR NHRP_STR "Enable NHRP and specify network-id\n" "System local ID to specify interface group\n") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; afi_t afi = cmd_to_afi(argv[0]); VTY_GET_INTEGER_RANGE("network-id", nifp->afi[afi].network_id, argv[1], 1, 4294967295); nhrp_interface_update(ifp); return CMD_SUCCESS; } DEFUN(if_no_nhrp_network_id, if_no_nhrp_network_id_cmd, "no " AFI_CMD " nhrp network-id [<1-4294967295>]", NO_STR AFI_STR NHRP_STR "Enable NHRP and specify network-id\n" "System local ID to specify interface group\n") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; afi_t afi = cmd_to_afi(argv[0]); nifp->afi[afi].network_id = 0; nhrp_interface_update(ifp); return CMD_SUCCESS; } DEFUN(if_nhrp_flags, if_nhrp_flags_cmd, AFI_CMD " nhrp (shortcut|redirect)", AFI_STR NHRP_STR "Allow shortcut establishment\n" "Send redirect notifications\n") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; afi_t afi = cmd_to_afi(argv[0]); return toggle_flag(vty, interface_flags_desc, argv[1], 1, &nifp->afi[afi].flags); } DEFUN(if_no_nhrp_flags, if_no_nhrp_flags_cmd, "no " AFI_CMD " nhrp (shortcut|redirect)", NO_STR AFI_STR NHRP_STR "Allow shortcut establishment\n" "Send redirect notifications\n") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; afi_t afi = cmd_to_afi(argv[0]); return toggle_flag(vty, interface_flags_desc, argv[1], 0, &nifp->afi[afi].flags); } DEFUN(if_nhrp_reg_flags, if_nhrp_reg_flags_cmd, AFI_CMD " nhrp registration (no-unique)", AFI_STR NHRP_STR "Registration configuration\n" "Don't set unique flag\n") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; afi_t afi = cmd_to_afi(argv[0]); char name[256]; snprintf(name, sizeof(name), "registration %s", argv[1]); return toggle_flag(vty, interface_flags_desc, name, 1, &nifp->afi[afi].flags); } DEFUN(if_no_nhrp_reg_flags, if_no_nhrp_reg_flags_cmd, "no " AFI_CMD " nhrp registration (no-unique)", NO_STR AFI_STR NHRP_STR "Registration configuration\n" "Don't set unique flag\n") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; afi_t afi = cmd_to_afi(argv[0]); char name[256]; snprintf(name, sizeof(name), "registration %s", argv[1]); return toggle_flag(vty, interface_flags_desc, name, 0, &nifp->afi[afi].flags); } DEFUN(if_nhrp_holdtime, if_nhrp_holdtime_cmd, AFI_CMD " nhrp holdtime <1-65000>", AFI_STR NHRP_STR "Specify NBMA address validity time\n" "Time in seconds that NBMA addresses are advertised valid\n") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; afi_t afi = cmd_to_afi(argv[0]); VTY_GET_INTEGER_RANGE("holdtime", nifp->afi[afi].holdtime, argv[1], 1, 65000); nhrp_interface_update(ifp); return CMD_SUCCESS; } DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd, "no " AFI_CMD " nhrp holdtime [1-65000]", NO_STR AFI_STR NHRP_STR "Specify NBMA address validity time\n" "Time in seconds that NBMA addresses are advertised valid\n") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; afi_t afi = cmd_to_afi(argv[0]); nifp->afi[afi].holdtime = NHRPD_DEFAULT_HOLDTIME; nhrp_interface_update(ifp); return CMD_SUCCESS; } DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd, "ip nhrp mtu (<576-1500>|opennhrp)", IP_STR NHRP_STR "Configure NHRP advertised MTU\n" "MTU value\n" "Advertise bound interface MTU similar to OpenNHRP") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; if (argv[0][0] == 'o') { nifp->afi[AFI_IP].configured_mtu = -1; } else { VTY_GET_INTEGER_RANGE("mtu", nifp->afi[AFI_IP].configured_mtu, argv[0], 576, 1500); } nhrp_interface_update_mtu(ifp, AFI_IP); return CMD_SUCCESS; } DEFUN(if_no_nhrp_mtu, if_no_nhrp_mtu_cmd, "no ip nhrp mtu [(<576-1500>|opennhrp)]", NO_STR IP_STR NHRP_STR "Configure NHRP advertised MTU\n" "MTU value\n" "Advertise bound interface MTU similar to OpenNHRP") { struct interface *ifp = vty->index; struct nhrp_interface *nifp = ifp->info; nifp->afi[AFI_IP].configured_mtu = 0; nhrp_interface_update_mtu(ifp, AFI_IP); return CMD_SUCCESS; } DEFUN(if_nhrp_map, if_nhrp_map_cmd, AFI_CMD " nhrp map (A.B.C.D|X:X::X:X) (A.B.C.D|local)", AFI_STR NHRP_STR "Nexthop Server configuration\n" "IPv4 protocol address\n" "IPv6 protocol address\n" "IPv4 NBMA address\n" "Handle protocol address locally\n") { struct interface *ifp = vty->index; afi_t afi = cmd_to_afi(argv[0]); union sockunion proto_addr, nbma_addr; struct nhrp_cache *c; if (str2sockunion(argv[1], &proto_addr) < 0 || afi2family(afi) != sockunion_family(&proto_addr)) return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH); c = nhrp_cache_get(ifp, &proto_addr, 1); if (!c) return nhrp_vty_return(vty, NHRP_ERR_FAIL); c->map = 1; if (strcmp(argv[2], "local") == 0) { nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL); } else{ if (str2sockunion(argv[2], &nbma_addr) < 0) return nhrp_vty_return(vty, NHRP_ERR_FAIL); nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0, nhrp_peer_get(ifp, &nbma_addr), 0, NULL); } return CMD_SUCCESS; } DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd, "no " AFI_CMD " nhrp map (A.B.C.D|X:X::X:X)", NO_STR AFI_STR NHRP_STR "Nexthop Server configuration\n" "IPv4 protocol address\n" "IPv6 protocol address\n") { struct interface *ifp = vty->index; afi_t afi = cmd_to_afi(argv[0]); union sockunion proto_addr; struct nhrp_cache *c; if (str2sockunion(argv[1], &proto_addr) < 0 || afi2family(afi) != sockunion_family(&proto_addr)) return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH); c = nhrp_cache_get(ifp, &proto_addr, 0); if (!c || !c->map) return nhrp_vty_return(vty, NHRP_ERR_ENTRY_NOT_FOUND); nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); return CMD_SUCCESS; } DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd, AFI_CMD " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)", AFI_STR NHRP_STR "Nexthop Server configuration\n" "IPv4 protocol address\n" "IPv6 protocol address\n" "Automatic detection of protocol address\n" "IPv4 NBMA address\n" "Fully qualified domain name for NBMA address(es)\n") { struct interface *ifp = vty->index; afi_t afi = cmd_to_afi(argv[0]); union sockunion proto_addr; int ret; if (str2sockunion(argv[1], &proto_addr) < 0) sockunion_family(&proto_addr) = AF_UNSPEC; ret = nhrp_nhs_add(ifp, afi, &proto_addr, argv[2]); return nhrp_vty_return(vty, ret); } DEFUN(if_no_nhrp_nhs, if_no_nhrp_nhs_cmd, "no " AFI_CMD " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)", NO_STR AFI_STR NHRP_STR "Nexthop Server configuration\n" "IPv4 protocol address\n" "IPv6 protocol address\n" "Automatic detection of protocol address\n" "IPv4 NBMA address\n" "Fully qualified domain name for NBMA address(es)\n") { struct interface *ifp = vty->index; afi_t afi = cmd_to_afi(argv[0]); union sockunion proto_addr; int ret; if (str2sockunion(argv[1], &proto_addr) < 0) sockunion_family(&proto_addr) = AF_UNSPEC; ret = nhrp_nhs_del(ifp, afi, &proto_addr, argv[2]); return nhrp_vty_return(vty, ret); } struct info_ctx { struct vty *vty; afi_t afi; int count; }; static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx) { struct info_ctx *ctx = pctx; struct vty *vty = ctx->vty; char buf[2][SU_ADDRSTRLEN]; if (ctx->afi != family2afi(sockunion_family(&c->remote_addr))) return; if (!ctx->count) { vty_out(vty, "%-8s %-8s %-24s %-24s %-6s %s%s", "Iface", "Type", "Protocol", "NBMA", "Flags", "Identity", VTY_NEWLINE); } ctx->count++; vty_out(ctx->vty, "%-8s %-8s %-24s %-24s %c%c%c %s%s", c->ifp->name, nhrp_cache_type_str[c->cur.type], sockunion2str(&c->remote_addr, buf[0], sizeof buf[0]), c->cur.peer ? sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1], sizeof buf[1]) : "-", c->used ? 'U' : ' ', c->t_timeout ? 'T' : ' ', c->t_auth ? 'A' : ' ', c->cur.peer ? c->cur.peer->vc->remote.id : "-", VTY_NEWLINE); } static void show_ip_nhrp_nhs(struct nhrp_nhs *n, struct nhrp_registration *reg, void *pctx) { struct info_ctx *ctx = pctx; struct vty *vty = ctx->vty; char buf[2][SU_ADDRSTRLEN]; if (!ctx->count) { vty_out(vty, "%-8s %-24s %-16s %-16s%s", "Iface", "FQDN", "NBMA", "Protocol", VTY_NEWLINE); } ctx->count++; vty_out(vty, "%-8s %-24s %-16s %-16s%s", n->ifp->name, n->nbma_fqdn, (reg && reg->peer) ? sockunion2str(®->peer->vc->remote.nbma, buf[0], sizeof buf[0]) : "-", sockunion2str(reg ? ®->proto_addr : &n->proto_addr, buf[1], sizeof buf[1]), VTY_NEWLINE); } static void show_ip_nhrp_shortcut(struct nhrp_shortcut *s, void *pctx) { struct info_ctx *ctx = pctx; struct nhrp_cache *c; struct vty *vty = ctx->vty; char buf1[PREFIX_STRLEN], buf2[SU_ADDRSTRLEN]; if (!ctx->count) { vty_out(vty, "%-8s %-24s %-24s %s%s", "Type", "Prefix", "Via", "Identity", VTY_NEWLINE); } ctx->count++; c = s->cache; vty_out(ctx->vty, "%-8s %-24s %-24s %s%s", nhrp_cache_type_str[s->type], prefix2str(s->p, buf1, sizeof buf1), c ? sockunion2str(&c->remote_addr, buf2, sizeof buf2) : "", (c && c->cur.peer) ? c->cur.peer->vc->remote.id : "", VTY_NEWLINE); } static void show_ip_opennhrp_cache(struct nhrp_cache *c, void *pctx) { struct info_ctx *ctx = pctx; struct vty *vty = ctx->vty; char buf[SU_ADDRSTRLEN]; if (ctx->afi != family2afi(sockunion_family(&c->remote_addr))) return; vty_out(ctx->vty, "Type: %s%s" "Flags:%s%s%s" "Protocol-Address: %s/%zu%s", nhrp_cache_type_str[c->cur.type], VTY_NEWLINE, (c->cur.peer && c->cur.peer->online) ? " up": "", c->used ? " used": "", VTY_NEWLINE, sockunion2str(&c->remote_addr, buf, sizeof buf), 8 * family2addrsize(sockunion_family(&c->remote_addr)), VTY_NEWLINE); if (c->cur.peer) { vty_out(ctx->vty, "NBMA-Address: %s%s", sockunion2str(&c->cur.peer->vc->remote.nbma, buf, sizeof buf), VTY_NEWLINE); } if (sockunion_family(&c->cur.remote_nbma_natoa) != AF_UNSPEC) { vty_out(ctx->vty, "NBMA-NAT-OA-Address: %s%s", sockunion2str(&c->cur.remote_nbma_natoa, buf, sizeof buf), VTY_NEWLINE); } vty_out(ctx->vty, "%s", VTY_NEWLINE); } DEFUN(show_ip_nhrp, show_ip_nhrp_cmd, "show " AFI_CMD " nhrp (cache|nhs|shortcut|opennhrp|)", SHOW_STR AFI_STR "NHRP information\n" "Forwarding cache information\n" "Next hop server information\n" "Shortcut information\n" "opennhrpctl style cache dump\n") { struct listnode *node; struct interface *ifp; struct info_ctx ctx = { .vty = vty, .afi = cmd_to_afi(argv[0]), }; if (!argv[1] || argv[1][0] == 'c') { for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) nhrp_cache_foreach(ifp, show_ip_nhrp_cache, &ctx); } else if (argv[1][0] == 'n') { for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) nhrp_nhs_foreach(ifp, ctx.afi, show_ip_nhrp_nhs, &ctx); } else if (argv[1][0] == 's') { nhrp_shortcut_foreach(ctx.afi, show_ip_nhrp_shortcut, &ctx); } else { vty_out(vty, "Status: ok%s%s", VTY_NEWLINE, VTY_NEWLINE); ctx.count++; for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) nhrp_cache_foreach(ifp, show_ip_opennhrp_cache, &ctx); } if (!ctx.count) { vty_out(vty, "%% No entries%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } static void show_dmvpn_entry(struct nhrp_vc *vc, void *ctx) { struct vty *vty = ctx; char buf[2][SU_ADDRSTRLEN]; vty_out(vty, "%-24s %-24s %c %-4d %-24s%s", sockunion2str(&vc->local.nbma, buf[0], sizeof buf[0]), sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1]), notifier_active(&vc->notifier_list) ? 'n' : ' ', vc->ipsec, vc->remote.id, VTY_NEWLINE); } DEFUN(show_dmvpn, show_dmvpn_cmd, "show dmvpn", SHOW_STR "DMVPN information\n") { vty_out(vty, "%-24s %-24s %-6s %-4s %-24s%s", "Src", "Dst", "Flags", "SAs", "Identity", VTY_NEWLINE); nhrp_vc_foreach(show_dmvpn_entry, vty); return CMD_SUCCESS; } static void clear_nhrp_cache(struct nhrp_cache *c, void *data) { struct info_ctx *ctx = data; if (c->cur.type <= NHRP_CACHE_CACHED) { nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); ctx->count++; } } static void clear_nhrp_shortcut(struct nhrp_shortcut *s, void *data) { struct info_ctx *ctx = data; nhrp_shortcut_purge(s, 1); ctx->count++; } DEFUN(clear_nhrp, clear_nhrp_cmd, "clear " AFI_CMD " nhrp (cache|shortcut)", CLEAR_STR AFI_STR NHRP_STR "Dynamic cache entries\n" "Shortcut entries\n") { struct listnode *node; struct interface *ifp; struct info_ctx ctx = { .vty = vty, .afi = cmd_to_afi(argv[0]), .count = 0, }; if (!argv[1] || argv[1][0] == 'c') { for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) nhrp_cache_foreach(ifp, clear_nhrp_cache, &ctx); } else { nhrp_shortcut_foreach(ctx.afi, clear_nhrp_shortcut, &ctx); } if (!ctx.count) { vty_out(vty, "%% No entries%s", VTY_NEWLINE); return CMD_WARNING; } vty_out(vty, "%% %d entries cleared%s", ctx.count, VTY_NEWLINE); return CMD_SUCCESS; } struct write_map_ctx { struct vty *vty; int family; const char *aficmd; }; static void interface_config_write_nhrp_map(struct nhrp_cache *c, void *data) { struct write_map_ctx *ctx = data; struct vty *vty = ctx->vty; char buf[2][SU_ADDRSTRLEN]; if (!c->map) return; if (sockunion_family(&c->remote_addr) != ctx->family) return; vty_out(vty, " %s nhrp map %s %s%s", ctx->aficmd, sockunion2str(&c->remote_addr, buf[0], sizeof buf[0]), c->cur.type == NHRP_CACHE_LOCAL ? "local" : sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1], sizeof buf[1]), VTY_NEWLINE); } static int interface_config_write(struct vty *vty) { struct write_map_ctx mapctx; struct listnode *node; struct interface *ifp; struct nhrp_interface *nifp; struct nhrp_nhs *nhs; const char *aficmd; afi_t afi; char buf[SU_ADDRSTRLEN]; int i; for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); if (ifp->desc) vty_out(vty, " description %s%s", ifp->desc, VTY_NEWLINE); nifp = ifp->info; if (nifp->ipsec_profile) { vty_out(vty, " tunnel protection vici profile %s", nifp->ipsec_profile); if (nifp->ipsec_fallback_profile) vty_out(vty, " fallback-profile %s", nifp->ipsec_fallback_profile); vty_out(vty, "%s", VTY_NEWLINE); } if (nifp->source) vty_out(vty, " tunnel source %s%s", nifp->source, VTY_NEWLINE); for (afi = 0; afi < AFI_MAX; afi++) { struct nhrp_afi_data *ad = &nifp->afi[afi]; aficmd = afi_to_cmd(afi); if (ad->network_id) vty_out(vty, " %s nhrp network-id %u%s", aficmd, ad->network_id, VTY_NEWLINE); if (ad->holdtime != NHRPD_DEFAULT_HOLDTIME) vty_out(vty, " %s nhrp holdtime %u%s", aficmd, ad->holdtime, VTY_NEWLINE); if (ad->configured_mtu < 0) vty_out(vty, " %s nhrp mtu opennhrp%s", aficmd, VTY_NEWLINE); else if (ad->configured_mtu) vty_out(vty, " %s nhrp mtu %u%s", aficmd, ad->configured_mtu, VTY_NEWLINE); for (i = 0; interface_flags_desc[i].str != NULL; i++) { if (!(ad->flags & interface_flags_desc[i].key)) continue; vty_out(vty, " %s nhrp %s%s", aficmd, interface_flags_desc[i].str, VTY_NEWLINE); } mapctx = (struct write_map_ctx) { .vty = vty, .family = afi2family(afi), .aficmd = aficmd, }; nhrp_cache_foreach(ifp, interface_config_write_nhrp_map, &mapctx); list_for_each_entry(nhs, &ad->nhslist_head, nhslist_entry) { vty_out(vty, " %s nhrp nhs %s nbma %s%s", aficmd, sockunion_family(&nhs->proto_addr) == AF_UNSPEC ? "dynamic" : sockunion2str(&nhs->proto_addr, buf, sizeof buf), nhs->nbma_fqdn, VTY_NEWLINE); } } vty_out (vty, "!%s", VTY_NEWLINE); } return 0; } void nhrp_config_init(void) { install_node(&zebra_node, nhrp_config_write); install_default(ZEBRA_NODE); /* global commands */ install_element(VIEW_NODE, &show_debugging_nhrp_cmd); install_element(VIEW_NODE, &show_ip_nhrp_cmd); install_element(VIEW_NODE, &show_dmvpn_cmd); install_element(ENABLE_NODE, &show_debugging_nhrp_cmd); install_element(ENABLE_NODE, &show_ip_nhrp_cmd); install_element(ENABLE_NODE, &show_dmvpn_cmd); install_element(ENABLE_NODE, &clear_nhrp_cmd); install_element(ENABLE_NODE, &debug_nhrp_cmd); install_element(ENABLE_NODE, &no_debug_nhrp_cmd); install_element(CONFIG_NODE, &debug_nhrp_cmd); install_element(CONFIG_NODE, &no_debug_nhrp_cmd); install_element(CONFIG_NODE, &nhrp_event_socket_cmd); install_element(CONFIG_NODE, &no_nhrp_event_socket_cmd); install_element(CONFIG_NODE, &nhrp_nflog_group_cmd); install_element(CONFIG_NODE, &no_nhrp_nflog_group_cmd); /* interface specific commands */ install_node(&nhrp_interface_node, interface_config_write); install_default(INTERFACE_NODE); install_element(CONFIG_NODE, &interface_cmd); install_element(CONFIG_NODE, &no_interface_cmd); install_element(INTERFACE_NODE, &interface_cmd); install_element(INTERFACE_NODE, &no_interface_cmd); install_element(INTERFACE_NODE, &tunnel_protection_cmd); install_element(INTERFACE_NODE, &no_tunnel_protection_cmd); install_element(INTERFACE_NODE, &tunnel_source_cmd); install_element(INTERFACE_NODE, &no_tunnel_source_cmd); install_element(INTERFACE_NODE, &if_nhrp_network_id_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd); install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd); install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_nhrp_flags_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_flags_cmd); install_element(INTERFACE_NODE, &if_nhrp_reg_flags_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd); install_element(INTERFACE_NODE, &if_nhrp_map_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_map_cmd); install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd); } quagga-1.2.4/nhrpd/nhrpd.h000066400000000000000000000306031325323223500153640ustar00rootroot00000000000000/* NHRP daemon internal structures and function prototypes * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute 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. */ #ifndef NHRPD_H #define NHRPD_H #include "list.h" #include "zbuf.h" #include "zclient.h" #include "debug.h" #define NHRPD_DEFAULT_HOLDTIME 7200 #define NHRP_VTY_PORT 2612 #define NHRP_DEFAULT_CONFIG "nhrpd.conf" extern struct thread_master *master; enum { NHRP_OK = 0, NHRP_ERR_FAIL, NHRP_ERR_NO_MEMORY, NHRP_ERR_UNSUPPORTED_INTERFACE, NHRP_ERR_NHRP_NOT_ENABLED, NHRP_ERR_ENTRY_EXISTS, NHRP_ERR_ENTRY_NOT_FOUND, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH, }; struct notifier_block; typedef void (*notifier_fn_t)(struct notifier_block *, unsigned long); struct notifier_block { struct list_head notifier_entry; notifier_fn_t action; }; struct notifier_list { struct list_head notifier_head; }; #define NOTIFIER_LIST_INITIALIZER(l) \ { .notifier_head = LIST_INITIALIZER((l)->notifier_head) } static inline void notifier_init(struct notifier_list *l) { list_init(&l->notifier_head); } static inline void notifier_add(struct notifier_block *n, struct notifier_list *l, notifier_fn_t action) { n->action = action; list_add_tail(&n->notifier_entry, &l->notifier_head); } static inline void notifier_del(struct notifier_block *n) { list_del(&n->notifier_entry); } static inline void notifier_call(struct notifier_list *l, int cmd) { struct notifier_block *n, *nn; list_for_each_entry_safe(n, nn, &l->notifier_head, notifier_entry) n->action(n, cmd); } static inline int notifier_active(struct notifier_list *l) { return !list_empty(&l->notifier_head); } struct resolver_query { void (*callback)(struct resolver_query *, int n, union sockunion *); }; void resolver_init(void); void resolver_resolve(struct resolver_query *query, int af, const char *hostname, void (*cb)(struct resolver_query *, int, union sockunion *)); void nhrp_zebra_init(void); void nhrp_zebra_terminate(void); struct zbuf; struct nhrp_vc; struct nhrp_cache; struct nhrp_nhs; struct nhrp_interface; #define MAX_ID_LENGTH 64 #define MAX_CERT_LENGTH 2048 enum nhrp_notify_type { NOTIFY_INTERFACE_UP, NOTIFY_INTERFACE_DOWN, NOTIFY_INTERFACE_CHANGED, NOTIFY_INTERFACE_ADDRESS_CHANGED, NOTIFY_INTERFACE_NBMA_CHANGED, NOTIFY_INTERFACE_MTU_CHANGED, NOTIFY_VC_IPSEC_CHANGED, NOTIFY_VC_IPSEC_UPDATE_NBMA, NOTIFY_PEER_UP, NOTIFY_PEER_DOWN, NOTIFY_PEER_IFCONFIG_CHANGED, NOTIFY_PEER_MTU_CHANGED, NOTIFY_PEER_NBMA_CHANGING, NOTIFY_CACHE_UP, NOTIFY_CACHE_DOWN, NOTIFY_CACHE_DELETE, NOTIFY_CACHE_USED, NOTIFY_CACHE_BINDING_CHANGE, }; struct nhrp_vc { struct notifier_list notifier_list; uint8_t ipsec; uint8_t updating; uint8_t abort_migration; struct nhrp_vc_peer { union sockunion nbma; char id[MAX_ID_LENGTH]; uint16_t certlen; uint8_t cert[MAX_CERT_LENGTH]; } local, remote; }; enum nhrp_route_type { NHRP_ROUTE_BLACKHOLE, NHRP_ROUTE_LOCAL, NHRP_ROUTE_NBMA_NEXTHOP, NHRP_ROUTE_OFF_NBMA, }; struct nhrp_peer { unsigned int ref; unsigned online : 1; unsigned requested : 1; unsigned fallback_requested : 1; unsigned prio : 1; struct notifier_list notifier_list; struct interface *ifp; struct nhrp_vc *vc; struct thread *t_fallback; struct notifier_block vc_notifier, ifp_notifier; }; struct nhrp_packet_parser { struct interface *ifp; struct nhrp_afi_data *if_ad; struct nhrp_peer *peer; struct zbuf *pkt; struct zbuf payload; struct zbuf extensions; struct nhrp_packet_header *hdr; enum nhrp_route_type route_type; struct prefix route_prefix; union sockunion src_nbma, src_proto, dst_proto; }; struct nhrp_reqid_pool { struct hash *reqid_hash; uint32_t next_request_id; }; struct nhrp_reqid { uint32_t request_id; void (*cb)(struct nhrp_reqid *, void *); }; extern struct nhrp_reqid_pool nhrp_packet_reqid; extern struct nhrp_reqid_pool nhrp_event_reqid; enum nhrp_cache_type { NHRP_CACHE_INVALID = 0, NHRP_CACHE_INCOMPLETE, NHRP_CACHE_NEGATIVE, NHRP_CACHE_CACHED, NHRP_CACHE_DYNAMIC, NHRP_CACHE_NHS, NHRP_CACHE_STATIC, NHRP_CACHE_LOCAL, NHRP_CACHE_NUM_TYPES }; extern const char * const nhrp_cache_type_str[]; extern unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES]; struct nhrp_cache { struct interface *ifp; union sockunion remote_addr; unsigned map : 1; unsigned used : 1; unsigned route_installed : 1; unsigned nhrp_route_installed : 1; struct notifier_block peer_notifier; struct notifier_block newpeer_notifier; struct notifier_list notifier_list; struct nhrp_reqid eventid; struct thread *t_timeout; struct thread *t_auth; struct { enum nhrp_cache_type type; union sockunion remote_nbma_natoa; struct nhrp_peer *peer; time_t expires; uint32_t mtu; } cur, new; }; struct nhrp_shortcut { struct prefix *p; union sockunion addr; struct nhrp_reqid reqid; struct thread *t_timer; enum nhrp_cache_type type; unsigned int holding_time; unsigned route_installed : 1; unsigned expiring : 1; struct nhrp_cache *cache; struct notifier_block cache_notifier; }; struct nhrp_nhs { struct interface *ifp; struct list_head nhslist_entry; unsigned hub : 1; afi_t afi; union sockunion proto_addr; const char *nbma_fqdn; /* IP-address or FQDN */ struct thread *t_resolve; struct resolver_query dns_resolve; struct list_head reglist_head; }; struct nhrp_registration { struct list_head reglist_entry; struct thread *t_register; struct nhrp_nhs *nhs; struct nhrp_reqid reqid; unsigned int timeout; unsigned mark : 1; union sockunion proto_addr; struct nhrp_peer *peer; struct notifier_block peer_notifier; }; #define NHRP_IFF_SHORTCUT 0x0001 #define NHRP_IFF_REDIRECT 0x0002 #define NHRP_IFF_REG_NO_UNIQUE 0x0100 struct nhrp_interface { struct interface *ifp; unsigned enabled : 1; char *ipsec_profile, *ipsec_fallback_profile, *source; union sockunion nbma; union sockunion nat_nbma; unsigned int linkidx; uint32_t grekey; struct hash *peer_hash; struct hash *cache_hash; struct notifier_list notifier_list; struct interface *nbmaifp; struct notifier_block nbmanifp_notifier; struct nhrp_afi_data { unsigned flags; unsigned short configured : 1; union sockunion addr; uint32_t network_id; short configured_mtu; unsigned short mtu; unsigned int holdtime; struct list_head nhslist_head; } afi[AFI_MAX]; }; int sock_open_unix(const char *path); void nhrp_interface_init(void); void nhrp_interface_update(struct interface *ifp); void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi); int nhrp_interface_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); int nhrp_interface_delete(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); int nhrp_interface_up(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); int nhrp_interface_down(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); int nhrp_interface_address_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); int nhrp_interface_address_delete(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id); void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn); void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n); void nhrp_interface_set_protection(struct interface *ifp, const char *profile, const char *fallback_profile); void nhrp_interface_set_source(struct interface *ifp, const char *ifname); int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn); int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn); int nhrp_nhs_free(struct nhrp_nhs *nhs); void nhrp_nhs_terminate(void); void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, void *), void *ctx); void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp); void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu); int nhrp_route_read(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id); int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p, union sockunion *via, struct interface **ifp); enum nhrp_route_type nhrp_route_address(struct interface *in_ifp, union sockunion *addr, struct prefix *p, struct nhrp_peer **peer); void nhrp_config_init(void); void nhrp_shortcut_init(void); void nhrp_shortcut_terminate(void); void nhrp_shortcut_initiate(union sockunion *addr); void nhrp_shortcut_foreach(afi_t afi, void (*cb)(struct nhrp_shortcut *, void *), void *ctx); void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force); void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted); struct nhrp_cache *nhrp_cache_get(struct interface *ifp, union sockunion *remote_addr, int create); void nhrp_cache_foreach(struct interface *ifp, void (*cb)(struct nhrp_cache *, void *), void *ctx); void nhrp_cache_set_used(struct nhrp_cache *, int); int nhrp_cache_update_binding(struct nhrp_cache *, enum nhrp_cache_type type, int holding_time, struct nhrp_peer *p, uint32_t mtu, union sockunion *nbma_natoa); void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *, notifier_fn_t); void nhrp_cache_notify_del(struct nhrp_cache *c, struct notifier_block *); void nhrp_vc_init(void); void nhrp_vc_terminate(void); struct nhrp_vc *nhrp_vc_get(const union sockunion *src, const union sockunion *dst, int create); int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc); void nhrp_vc_notify_add(struct nhrp_vc *, struct notifier_block *, notifier_fn_t); void nhrp_vc_notify_del(struct nhrp_vc *, struct notifier_block *); void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx); void nhrp_vc_reset(void); void vici_init(void); void vici_terminate(void); void vici_request_vc(const char *profile, union sockunion *src, union sockunion *dst, int prio); extern const char *nhrp_event_socket_path; void evmgr_init(void); void evmgr_terminate(void); void evmgr_set_socket(const char *socket); void evmgr_notify(const char *name, struct nhrp_cache *c, void (*cb)(struct nhrp_reqid *, void *)); struct nhrp_packet_header *nhrp_packet_push( struct zbuf *zb, uint8_t type, const union sockunion *src_nbma, const union sockunion *src_proto, const union sockunion *dst_proto); void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr); uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len); struct nhrp_packet_header *nhrp_packet_pull( struct zbuf *zb, union sockunion *src_nbma, union sockunion *src_proto, union sockunion *dst_proto); struct nhrp_cie_header *nhrp_cie_push( struct zbuf *zb, uint8_t code, const union sockunion *nbma, const union sockunion *proto); struct nhrp_cie_header *nhrp_cie_pull( struct zbuf *zb, struct nhrp_packet_header *hdr, union sockunion *nbma, union sockunion *proto); struct nhrp_extension_header *nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type); void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext); struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, struct zbuf *payload); void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *); int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp, struct nhrp_extension_header *ext, struct zbuf *extpayload); uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *, struct nhrp_reqid *r, void (*cb)(struct nhrp_reqid *, void *)); void nhrp_reqid_free(struct nhrp_reqid_pool *, struct nhrp_reqid *r); struct nhrp_reqid *nhrp_reqid_lookup(struct nhrp_reqid_pool *, uint32_t reqid); int nhrp_packet_init(void); struct nhrp_peer *nhrp_peer_get(struct interface *ifp, const union sockunion *remote_nbma); struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p); void nhrp_peer_unref(struct nhrp_peer *p); int nhrp_peer_check(struct nhrp_peer *p, int establish); void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *, notifier_fn_t); void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *); void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb); void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb); void nhrp_peer_send_indication(struct interface *ifp, uint16_t, struct zbuf *); #endif quagga-1.2.4/nhrpd/os.h000066400000000000000000000004331325323223500146700ustar00rootroot00000000000000 int os_socket(void); int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, size_t addrlen); int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr, size_t *addrlen); int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af); quagga-1.2.4/nhrpd/reqid.c000066400000000000000000000021211325323223500153420ustar00rootroot00000000000000#include "zebra.h" #include "hash.h" #include "nhrpd.h" static unsigned int nhrp_reqid_key(void *data) { struct nhrp_reqid *r = data; return r->request_id; } static int nhrp_reqid_cmp(const void *data, const void *key) { const struct nhrp_reqid *a = data, *b = key; return a->request_id == b->request_id; } uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *p, struct nhrp_reqid *r, void (*cb)(struct nhrp_reqid *, void *)) { if (!p->reqid_hash) { p->reqid_hash = hash_create(nhrp_reqid_key, nhrp_reqid_cmp); p->next_request_id = 1; } if (r->cb != cb) { r->request_id = p->next_request_id; if (++p->next_request_id == 0) p->next_request_id = 1; r->cb = cb; hash_get(p->reqid_hash, r, hash_alloc_intern); } return r->request_id; } void nhrp_reqid_free(struct nhrp_reqid_pool *p, struct nhrp_reqid *r) { if (r->cb) { hash_release(p->reqid_hash, r); r->cb = NULL; } } struct nhrp_reqid *nhrp_reqid_lookup(struct nhrp_reqid_pool *p, uint32_t reqid) { struct nhrp_reqid key; if (!p->reqid_hash) return 0; key.request_id = reqid; return hash_lookup(p->reqid_hash, &key); } quagga-1.2.4/nhrpd/resolver.c000066400000000000000000000114671325323223500161140ustar00rootroot00000000000000/* C-Ares integration to Quagga mainloop * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include #include "vector.h" #include "thread.h" #include "nhrpd.h" struct resolver_state { ares_channel channel; struct thread *timeout; vector read_threads, write_threads; }; static struct resolver_state state; #define THREAD_RUNNING ((struct thread *)-1) static void resolver_update_timeouts(struct resolver_state *r); static int resolver_cb_timeout(struct thread *t) { struct resolver_state *r = THREAD_ARG(t); r->timeout = THREAD_RUNNING; ares_process(r->channel, NULL, NULL); r->timeout = NULL; resolver_update_timeouts(r); return 0; } static int resolver_cb_socket_readable(struct thread *t) { struct resolver_state *r = THREAD_ARG(t); int fd = THREAD_FD(t); vector_set_index(r->read_threads, fd, THREAD_RUNNING); ares_process_fd(r->channel, fd, ARES_SOCKET_BAD); if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) { t = NULL; THREAD_READ_ON(master, t, resolver_cb_socket_readable, r, fd); vector_set_index(r->read_threads, fd, t); } resolver_update_timeouts(r); return 0; } static int resolver_cb_socket_writable(struct thread *t) { struct resolver_state *r = THREAD_ARG(t); int fd = THREAD_FD(t); vector_set_index(r->write_threads, fd, THREAD_RUNNING); ares_process_fd(r->channel, ARES_SOCKET_BAD, fd); if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) { t = NULL; THREAD_WRITE_ON(master, t, resolver_cb_socket_writable, r, fd); vector_set_index(r->write_threads, fd, t); } resolver_update_timeouts(r); return 0; } static void resolver_update_timeouts(struct resolver_state *r) { struct timeval *tv, tvbuf; if (r->timeout == THREAD_RUNNING) return; THREAD_OFF(r->timeout); tv = ares_timeout(r->channel, NULL, &tvbuf); if (tv) { unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000; THREAD_TIMER_MSEC_ON(master, r->timeout, resolver_cb_timeout, r, timeoutms); } } static void ares_socket_cb(void *data, ares_socket_t fd, int readable, int writable) { struct resolver_state *r = (struct resolver_state *) data; struct thread *t; if (readable) { t = vector_lookup_ensure(r->read_threads, fd); if (!t) { THREAD_READ_ON(master, t, resolver_cb_socket_readable, r, fd); vector_set_index(r->read_threads, fd, t); } } else { t = vector_lookup(r->read_threads, fd); if (t) { if (t != THREAD_RUNNING) { THREAD_OFF(t); } vector_unset(r->read_threads, fd); } } if (writable) { t = vector_lookup_ensure(r->write_threads, fd); if (!t) { THREAD_READ_ON(master, t, resolver_cb_socket_writable, r, fd); vector_set_index(r->write_threads, fd, t); } } else { t = vector_lookup(r->write_threads, fd); if (t) { if (t != THREAD_RUNNING) { THREAD_OFF(t); } vector_unset(r->write_threads, fd); } } } void resolver_init(void) { struct ares_options ares_opts; state.read_threads = vector_init(1); state.write_threads = vector_init(1); ares_opts = (struct ares_options) { .sock_state_cb = &ares_socket_cb, .sock_state_cb_data = &state, .timeout = 2, .tries = 3, }; ares_init_options(&state.channel, &ares_opts, ARES_OPT_SOCK_STATE_CB | ARES_OPT_TIMEOUT | ARES_OPT_TRIES); } static void ares_address_cb(void *arg, int status, int timeouts, struct hostent *he) { struct resolver_query *query = (struct resolver_query *) arg; union sockunion addr[16]; size_t i; if (status != ARES_SUCCESS) { debugf(NHRP_DEBUG_COMMON, "[%p] Resolving failed", query); query->callback(query, -1, NULL); query->callback = NULL; return; } for (i = 0; he->h_addr_list[i] != NULL && i < ZEBRA_NUM_OF(addr); i++) { memset(&addr[i], 0, sizeof(addr[i])); addr[i].sa.sa_family = he->h_addrtype; switch (he->h_addrtype) { case AF_INET: memcpy(&addr[i].sin.sin_addr, (uint8_t *) he->h_addr_list[i], he->h_length); break; case AF_INET6: memcpy(&addr[i].sin6.sin6_addr, (uint8_t *) he->h_addr_list[i], he->h_length); break; } } debugf(NHRP_DEBUG_COMMON, "[%p] Resolved with %d results", query, (int) i); query->callback(query, i, &addr[0]); query->callback = NULL; } void resolver_resolve(struct resolver_query *query, int af, const char *hostname, void (*callback)(struct resolver_query *, int, union sockunion *)) { if (query->callback != NULL) { zlog_err("Trying to resolve '%s', but previous query was not finished yet", hostname); return; } debugf(NHRP_DEBUG_COMMON, "[%p] Resolving '%s'", query, hostname); query->callback = callback; ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query); resolver_update_timeouts(&state); } quagga-1.2.4/nhrpd/vici.c000066400000000000000000000312251325323223500151770ustar00rootroot00000000000000/* strongSwan VICI protocol implementation for NHRP * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include "thread.h" #include "zbuf.h" #include "log.h" #include "nhrpd.h" #include "vici.h" #define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) struct blob { char *ptr; int len; }; static int blob_equal(const struct blob *b, const char *str) { if (b->len != (int) strlen(str)) return 0; return memcmp(b->ptr, str, b->len) == 0; } static int blob2buf(const struct blob *b, char *buf, size_t n) { if (b->len >= (int) n) return 0; memcpy(buf, b->ptr, b->len); buf[b->len] = 0; return 1; } struct vici_conn { struct thread *t_reconnect, *t_read, *t_write; struct zbuf ibuf; struct zbuf_queue obuf; int fd; uint8_t ibuf_data[VICI_MAX_MSGLEN]; }; struct vici_message_ctx { const char *sections[8]; int nsections; }; static int vici_reconnect(struct thread *t); static void vici_submit_request(struct vici_conn *vici, const char *name, ...); static void vici_zbuf_puts(struct zbuf *obuf, const char *str) { size_t len = strlen(str); zbuf_put8(obuf, len); zbuf_put(obuf, str, len); } static void vici_connection_error(struct vici_conn *vici) { nhrp_vc_reset(); THREAD_OFF(vici->t_read); THREAD_OFF(vici->t_write); zbuf_reset(&vici->ibuf); zbufq_reset(&vici->obuf); close(vici->fd); vici->fd = -1; THREAD_TIMER_ON(master, vici->t_reconnect, vici_reconnect, vici, 2); } static void vici_parse_message( struct vici_conn *vici, struct zbuf *msg, void (*parser)(struct vici_message_ctx *ctx, enum vici_type_t msgtype, const struct blob *key, const struct blob *val), struct vici_message_ctx *ctx) { uint8_t *type; struct blob key; struct blob val; while ((type = zbuf_may_pull(msg, uint8_t)) != NULL) { switch (*type) { case VICI_SECTION_START: key.len = zbuf_get8(msg); key.ptr = zbuf_pulln(msg, key.len); debugf(NHRP_DEBUG_VICI, "VICI: Section start '%.*s'", key.len, key.ptr); parser(ctx, *type, &key, NULL); ctx->nsections++; break; case VICI_SECTION_END: debugf(NHRP_DEBUG_VICI, "VICI: Section end"); parser(ctx, *type, NULL, NULL); ctx->nsections--; break; case VICI_KEY_VALUE: key.len = zbuf_get8(msg); key.ptr = zbuf_pulln(msg, key.len); val.len = zbuf_get_be16(msg); val.ptr = zbuf_pulln(msg, val.len); debugf(NHRP_DEBUG_VICI, "VICI: Key '%.*s'='%.*s'", key.len, key.ptr, val.len, val.ptr); parser(ctx, *type, &key, &val); break; case VICI_LIST_START: key.len = zbuf_get8(msg); key.ptr = zbuf_pulln(msg, key.len); debugf(NHRP_DEBUG_VICI, "VICI: List start '%.*s'", key.len, key.ptr); break; case VICI_LIST_ITEM: val.len = zbuf_get_be16(msg); val.ptr = zbuf_pulln(msg, val.len); debugf(NHRP_DEBUG_VICI, "VICI: List item: '%.*s'", val.len, val.ptr); parser(ctx, *type, &key, &val); break; case VICI_LIST_END: debugf(NHRP_DEBUG_VICI, "VICI: List end"); break; default: debugf(NHRP_DEBUG_VICI, "VICI: Unsupported message component type %d", *type); return; } } } struct handle_sa_ctx { struct vici_message_ctx msgctx; int event; int child_ok; int kill_ikesa; uint32_t child_uniqueid, ike_uniqueid; struct { union sockunion host; struct blob id, cert; } local, remote; }; static void parse_sa_message( struct vici_message_ctx *ctx, enum vici_type_t msgtype, const struct blob *key, const struct blob *val) { struct handle_sa_ctx *sactx = container_of(ctx, struct handle_sa_ctx, msgctx); struct nhrp_vc *vc; char buf[512]; switch (msgtype) { case VICI_SECTION_START: if (ctx->nsections == 3) { /* Begin of child-sa section, reset child vars */ sactx->child_uniqueid = 0; sactx->child_ok = 0; } break; case VICI_SECTION_END: if (ctx->nsections == 3) { /* End of child-sa section, update nhrp_vc */ int up = sactx->child_ok || sactx->event == 1; if (up) { vc = nhrp_vc_get(&sactx->local.host, &sactx->remote.host, up); if (vc) { blob2buf(&sactx->local.id, vc->local.id, sizeof(vc->local.id)); if (blob2buf(&sactx->local.cert, (char*)vc->local.cert, sizeof(vc->local.cert))) vc->local.certlen = sactx->local.cert.len; blob2buf(&sactx->remote.id, vc->remote.id, sizeof(vc->remote.id)); if (blob2buf(&sactx->remote.cert, (char*)vc->remote.cert, sizeof(vc->remote.cert))) vc->remote.certlen = sactx->remote.cert.len; sactx->kill_ikesa |= nhrp_vc_ipsec_updown(sactx->child_uniqueid, vc); } } else { nhrp_vc_ipsec_updown(sactx->child_uniqueid, 0); } } break; default: switch (key->ptr[0]) { case 'l': if (blob_equal(key, "local-host") && ctx->nsections == 1) { if (blob2buf(val, buf, sizeof(buf))) str2sockunion(buf, &sactx->local.host); } else if (blob_equal(key, "local-id") && ctx->nsections == 1) { sactx->local.id = *val; } else if (blob_equal(key, "local-cert-data") && ctx->nsections == 1) { sactx->local.cert = *val; } break; case 'r': if (blob_equal(key, "remote-host") && ctx->nsections == 1) { if (blob2buf(val, buf, sizeof(buf))) str2sockunion(buf, &sactx->remote.host); } else if (blob_equal(key, "remote-id") && ctx->nsections == 1) { sactx->remote.id = *val; } else if (blob_equal(key, "remote-cert-data") && ctx->nsections == 1) { sactx->remote.cert = *val; } break; case 'u': if (blob_equal(key, "uniqueid") && blob2buf(val, buf, sizeof(buf))) { if (ctx->nsections == 3) sactx->child_uniqueid = strtoul(buf, NULL, 0); else if (ctx->nsections == 1) sactx->ike_uniqueid = strtoul(buf, NULL, 0); } break; case 's': if (blob_equal(key, "state") && ctx->nsections == 3) { sactx->child_ok = (sactx->event == 0 && (blob_equal(val, "INSTALLED") || blob_equal(val, "REKEYED"))); } break; } break; } } static void parse_cmd_response( struct vici_message_ctx *ctx, enum vici_type_t msgtype, const struct blob *key, const struct blob *val) { char buf[512]; switch (msgtype) { case VICI_KEY_VALUE: if (blob_equal(key, "errmsg") && blob2buf(val, buf, sizeof(buf))) zlog_err("VICI: strongSwan: %s", buf); break; default: break; } } static void vici_recv_sa(struct vici_conn *vici, struct zbuf *msg, int event) { char buf[32]; struct handle_sa_ctx ctx = { .event = event, }; vici_parse_message(vici, msg, parse_sa_message, &ctx.msgctx); if (ctx.kill_ikesa && ctx.ike_uniqueid) { debugf(NHRP_DEBUG_COMMON, "VICI: Deleting IKE_SA %u", ctx.ike_uniqueid); snprintf(buf, sizeof buf, "%u", ctx.ike_uniqueid); vici_submit_request( vici, "terminate", VICI_KEY_VALUE, "ike-id", strlen(buf), buf, VICI_END); } } static void vici_recv_message(struct vici_conn *vici, struct zbuf *msg) { uint32_t msglen; uint8_t msgtype; struct blob name; msglen = zbuf_get_be32(msg); msgtype = zbuf_get8(msg); debugf(NHRP_DEBUG_VICI, "VICI: Message %d, %d bytes", msgtype, msglen); switch (msgtype) { case VICI_EVENT: name.len = zbuf_get8(msg); name.ptr = zbuf_pulln(msg, name.len); debugf(NHRP_DEBUG_VICI, "VICI: Event '%.*s'", name.len, name.ptr); if (blob_equal(&name, "list-sa") || blob_equal(&name, "child-updown") || blob_equal(&name, "child-rekey")) vici_recv_sa(vici, msg, 0); else if (blob_equal(&name, "child-state-installed") || blob_equal(&name, "child-state-rekeyed")) vici_recv_sa(vici, msg, 1); else if (blob_equal(&name, "child-state-destroying")) vici_recv_sa(vici, msg, 2); break; case VICI_CMD_RESPONSE: vici_parse_message(vici, msg, parse_cmd_response, 0); break; case VICI_EVENT_UNKNOWN: case VICI_CMD_UNKNOWN: zlog_err("VICI: StrongSwan does not support mandatory events (unpatched?)"); break; case VICI_EVENT_CONFIRM: break; default: zlog_notice("VICI: Unrecognized message type %d", msgtype); break; } } static int vici_read(struct thread *t) { struct vici_conn *vici = THREAD_ARG(t); struct zbuf *ibuf = &vici->ibuf; struct zbuf pktbuf; vici->t_read = NULL; if (zbuf_read(ibuf, vici->fd, (size_t) -1) < 0) { vici_connection_error(vici); return 0; } /* Process all messages in buffer */ do { uint32_t *hdrlen = zbuf_may_pull(ibuf, uint32_t); if (!hdrlen) break; if (!zbuf_may_pulln(ibuf, ntohl(*hdrlen))) { zbuf_reset_head(ibuf, hdrlen); break; } /* Handle packet */ zbuf_init(&pktbuf, hdrlen, htonl(*hdrlen)+4, htonl(*hdrlen)+4); vici_recv_message(vici, &pktbuf); } while (1); THREAD_READ_ON(master, vici->t_read, vici_read, vici, vici->fd); return 0; } static int vici_write(struct thread *t) { struct vici_conn *vici = THREAD_ARG(t); int r; vici->t_write = NULL; r = zbufq_write(&vici->obuf, vici->fd); if (r > 0) { THREAD_WRITE_ON(master, vici->t_write, vici_write, vici, vici->fd); } else if (r < 0) { vici_connection_error(vici); } return 0; } static void vici_submit(struct vici_conn *vici, struct zbuf *obuf) { if (vici->fd < 0) { zbuf_free(obuf); return; } zbufq_queue(&vici->obuf, obuf); THREAD_WRITE_ON(master, vici->t_write, vici_write, vici, vici->fd); } static void vici_submit_request(struct vici_conn *vici, const char *name, ...) { struct zbuf *obuf; uint32_t *hdrlen; va_list va; size_t len; int type; obuf = zbuf_alloc(256); if (!obuf) return; hdrlen = zbuf_push(obuf, uint32_t); zbuf_put8(obuf, VICI_CMD_REQUEST); vici_zbuf_puts(obuf, name); va_start(va, name); for (type = va_arg(va, int); type != VICI_END; type = va_arg(va, int)) { zbuf_put8(obuf, type); switch (type) { case VICI_KEY_VALUE: vici_zbuf_puts(obuf, va_arg(va, const char *)); len = va_arg(va, size_t); zbuf_put_be16(obuf, len); zbuf_put(obuf, va_arg(va, void *), len); break; case VICI_END: break; default: break; } } va_end(va); *hdrlen = htonl(zbuf_used(obuf) - 4); vici_submit(vici, obuf); } static void vici_register_event(struct vici_conn *vici, const char *name) { struct zbuf *obuf; uint32_t *hdrlen; uint8_t namelen; namelen = strlen(name); obuf = zbuf_alloc(4 + 1 + 1 + namelen); if (!obuf) return; hdrlen = zbuf_push(obuf, uint32_t); zbuf_put8(obuf, VICI_EVENT_REGISTER); zbuf_put8(obuf, namelen); zbuf_put(obuf, name, namelen); *hdrlen = htonl(zbuf_used(obuf) - 4); vici_submit(vici, obuf); } static int vici_reconnect(struct thread *t) { struct vici_conn *vici = THREAD_ARG(t); int fd; vici->t_reconnect = NULL; if (vici->fd >= 0) return 0; fd = sock_open_unix("/var/run/charon.vici"); if (fd < 0) { zlog_warn("%s: failure connecting VICI socket: %s", __PRETTY_FUNCTION__, strerror(errno)); THREAD_TIMER_ON(master, vici->t_reconnect, vici_reconnect, vici, 2); return 0; } debugf(NHRP_DEBUG_COMMON, "VICI: Connected"); vici->fd = fd; THREAD_READ_ON(master, vici->t_read, vici_read, vici, vici->fd); /* Send event subscribtions */ //vici_register_event(vici, "child-updown"); //vici_register_event(vici, "child-rekey"); vici_register_event(vici, "child-state-installed"); vici_register_event(vici, "child-state-rekeyed"); vici_register_event(vici, "child-state-destroying"); vici_register_event(vici, "list-sa"); vici_submit_request(vici, "list-sas", VICI_END); return 0; } static struct vici_conn vici_connection; void vici_init(void) { struct vici_conn *vici = &vici_connection; vici->fd = -1; zbuf_init(&vici->ibuf, vici->ibuf_data, sizeof(vici->ibuf_data), 0); zbufq_init(&vici->obuf); THREAD_TIMER_MSEC_ON(master, vici->t_reconnect, vici_reconnect, vici, 10); } void vici_terminate(void) { } void vici_request_vc(const char *profile, union sockunion *src, union sockunion *dst, int prio) { struct vici_conn *vici = &vici_connection; char buf[2][SU_ADDRSTRLEN]; sockunion2str(src, buf[0], sizeof buf[0]); sockunion2str(dst, buf[1], sizeof buf[1]); vici_submit_request( vici, "initiate", VICI_KEY_VALUE, "child", strlen(profile), profile, VICI_KEY_VALUE, "timeout", (size_t) 2, "-1", VICI_KEY_VALUE, "async", (size_t) 1, "1", VICI_KEY_VALUE, "init-limits", (size_t) 1, prio ? "0" : "1", VICI_KEY_VALUE, "my-host", strlen(buf[0]), buf[0], VICI_KEY_VALUE, "other-host", strlen(buf[1]), buf[1], VICI_END); } int sock_open_unix(const char *path) { int ret, fd; struct sockaddr_un addr; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) return -1; memset(&addr, 0, sizeof (struct sockaddr_un)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, path, strlen (path)); ret = connect(fd, (struct sockaddr *) &addr, sizeof(addr.sun_family) + strlen(addr.sun_path)); if (ret < 0) { close(fd); return -1; } fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); return fd; } quagga-1.2.4/nhrpd/vici.h000066400000000000000000000007021325323223500152000ustar00rootroot00000000000000 enum vici_type_t { VICI_START = 0, VICI_SECTION_START = 1, VICI_SECTION_END = 2, VICI_KEY_VALUE = 3, VICI_LIST_START = 4, VICI_LIST_ITEM = 5, VICI_LIST_END = 6, VICI_END = 7 }; enum vici_operation_t { VICI_CMD_REQUEST = 0, VICI_CMD_RESPONSE, VICI_CMD_UNKNOWN, VICI_EVENT_REGISTER, VICI_EVENT_UNREGISTER, VICI_EVENT_CONFIRM, VICI_EVENT_UNKNOWN, VICI_EVENT, }; #define VICI_MAX_MSGLEN (512*1024) quagga-1.2.4/nhrpd/zbuf.c000066400000000000000000000101631325323223500152110ustar00rootroot00000000000000/* Stream/packet buffer API implementation * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute 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. */ #define _GNU_SOURCE #include #include #include #include "zassert.h" #include "zbuf.h" #include "memory.h" #include "memtypes.h" #include "nhrpd.h" #define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) struct zbuf *zbuf_alloc(size_t size) { struct zbuf *zb; zb = XMALLOC(MTYPE_STREAM_DATA, sizeof(*zb) + size); if (!zb) return NULL; zbuf_init(zb, zb+1, size, 0); zb->allocated = 1; return zb; } void zbuf_init(struct zbuf *zb, void *buf, size_t len, size_t datalen) { *zb = (struct zbuf) { .buf = buf, .end = (uint8_t *)buf + len, .head = buf, .tail = (uint8_t *)buf + datalen, }; } void zbuf_free(struct zbuf *zb) { if (zb->allocated) XFREE(MTYPE_STREAM_DATA, zb); } void zbuf_reset(struct zbuf *zb) { zb->head = zb->tail = zb->buf; zb->error = 0; } void zbuf_reset_head(struct zbuf *zb, void *ptr) { zassert((void*)zb->buf <= ptr && ptr <= (void*)zb->tail); zb->head = ptr; } static void zbuf_remove_headroom(struct zbuf *zb) { ssize_t headroom = zbuf_headroom(zb); if (!headroom) return; memmove(zb->buf, zb->head, zbuf_used(zb)); zb->head -= headroom; zb->tail -= headroom; } ssize_t zbuf_read(struct zbuf *zb, int fd, size_t maxlen) { ssize_t r; if (zb->error) return -3; zbuf_remove_headroom(zb); if (maxlen > zbuf_tailroom(zb)) maxlen = zbuf_tailroom(zb); r = read(fd, zb->tail, maxlen); if (r > 0) zb->tail += r; else if (r == 0) r = -2; else if (r < 0 && ERRNO_IO_RETRY(errno)) r = 0; return r; } ssize_t zbuf_write(struct zbuf *zb, int fd) { ssize_t r; if (zb->error) return -3; r = write(fd, zb->head, zbuf_used(zb)); if (r > 0) { zb->head += r; if (zb->head == zb->tail) zbuf_reset(zb); } else if (r == 0) r = -2; else if (r < 0 && ERRNO_IO_RETRY(errno)) r = 0; return r; } ssize_t zbuf_recv(struct zbuf *zb, int fd) { ssize_t r; if (zb->error) return -3; zbuf_remove_headroom(zb); r = recv(fd, zb->tail, zbuf_tailroom(zb), 0); if (r > 0) zb->tail += r; else if (r == 0) r = -2; else if (r < 0 && ERRNO_IO_RETRY(errno)) r = 0; return r; } ssize_t zbuf_send(struct zbuf *zb, int fd) { ssize_t r; if (zb->error) return -3; r = send(fd, zb->head, zbuf_used(zb), 0); if (r >= 0) zbuf_reset(zb); return r; } void *zbuf_may_pull_until(struct zbuf *zb, const char *sep, struct zbuf *msg) { size_t seplen = strlen(sep), len; uint8_t *ptr; ptr = memmem(zb->head, zbuf_used(zb), sep, seplen); if (!ptr) return NULL; len = ptr - zb->head + seplen; zbuf_init(msg, zbuf_pulln(zb, len), len, len); return msg->head; } void zbufq_init(struct zbuf_queue *zbq) { *zbq = (struct zbuf_queue) { .queue_head = LIST_INITIALIZER(zbq->queue_head), }; } void zbufq_reset(struct zbuf_queue *zbq) { struct zbuf *buf, *bufn; list_for_each_entry_safe(buf, bufn, &zbq->queue_head, queue_list) { list_del(&buf->queue_list); zbuf_free(buf); } } void zbufq_queue(struct zbuf_queue *zbq, struct zbuf *zb) { list_add_tail(&zb->queue_list, &zbq->queue_head); } int zbufq_write(struct zbuf_queue *zbq, int fd) { struct iovec iov[16]; struct zbuf *zb, *zbn; ssize_t r; size_t iovcnt = 0; list_for_each_entry_safe(zb, zbn, &zbq->queue_head, queue_list) { iov[iovcnt++] = (struct iovec) { .iov_base = zb->head, .iov_len = zbuf_used(zb), }; if (iovcnt >= ZEBRA_NUM_OF(iov)) break; } r = writev(fd, iov, iovcnt); if (r < 0) return r; list_for_each_entry_safe(zb, zbn, &zbq->queue_head, queue_list) { if (r < (ssize_t)zbuf_used(zb)) { zb->head += r; return 1; } r -= zbuf_used(zb); list_del(&zb->queue_list); zbuf_free(zb); } return 0; } void zbuf_copy(struct zbuf *zdst, struct zbuf *zsrc, size_t len) { const void *src; void *dst; dst = zbuf_pushn(zdst, len); src = zbuf_pulln(zsrc, len); if (!dst || !src) return; memcpy(dst, src, len); } quagga-1.2.4/nhrpd/zbuf.h000066400000000000000000000105701325323223500152200ustar00rootroot00000000000000/* Stream/packet buffer API * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute 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. */ #ifndef ZBUF_H #define ZBUF_H #include #include #include #include #include "zassert.h" #include "list.h" struct zbuf { struct list_head queue_list; unsigned allocated : 1; unsigned error : 1; uint8_t *buf, *end; uint8_t *head, *tail; }; struct zbuf_queue { struct list_head queue_head; }; struct zbuf *zbuf_alloc(size_t size); void zbuf_init(struct zbuf *zb, void *buf, size_t len, size_t datalen); void zbuf_free(struct zbuf *zb); static inline size_t zbuf_size(struct zbuf *zb) { return zb->end - zb->buf; } static inline size_t zbuf_used(struct zbuf *zb) { return zb->tail - zb->head; } static inline size_t zbuf_tailroom(struct zbuf *zb) { return zb->end - zb->tail; } static inline size_t zbuf_headroom(struct zbuf *zb) { return zb->head - zb->buf; } void zbuf_reset(struct zbuf *zb); void zbuf_reset_head(struct zbuf *zb, void *ptr); ssize_t zbuf_read(struct zbuf *zb, int fd, size_t maxlen); ssize_t zbuf_write(struct zbuf *zb, int fd); ssize_t zbuf_recv(struct zbuf *zb, int fd); ssize_t zbuf_send(struct zbuf *zb, int fd); static inline void zbuf_set_rerror(struct zbuf *zb) { zb->error = 1; zb->head = zb->tail; } static inline void zbuf_set_werror(struct zbuf *zb) { zb->error = 1; zb->tail = zb->end; } static inline void *__zbuf_pull(struct zbuf *zb, size_t size, int error) { void *head = zb->head; if (size > zbuf_used(zb)) { if (error) zbuf_set_rerror(zb); return NULL; } zb->head += size; return head; } #define zbuf_pull(zb, type) ((type *)__zbuf_pull(zb, sizeof(type), 1)) #define zbuf_pulln(zb, sz) ((void *)__zbuf_pull(zb, sz, 1)) #define zbuf_may_pull(zb, type) ((type *)__zbuf_pull(zb, sizeof(type), 0)) #define zbuf_may_pulln(zb, sz) ((void *)__zbuf_pull(zb, sz, 0)) void *zbuf_may_pull_until(struct zbuf *zb, const char *sep, struct zbuf *msg); static inline void zbuf_get(struct zbuf *zb, void *dst, size_t len) { void *src = zbuf_pulln(zb, len); if (src) memcpy(dst, src, len); } static inline uint8_t zbuf_get8(struct zbuf *zb) { uint8_t *src = zbuf_pull(zb, uint8_t); if (src) return *src; return 0; } static inline uint32_t zbuf_get32(struct zbuf *zb) { struct unaligned32 { uint32_t value; } __attribute__((packed)); struct unaligned32 *v = zbuf_pull(zb, struct unaligned32); if (v) return v->value; return 0; } static inline uint16_t zbuf_get_be16(struct zbuf *zb) { struct unaligned16 { uint16_t value; } __attribute__((packed)); struct unaligned16 *v = zbuf_pull(zb, struct unaligned16); if (v) return be16toh(v->value); return 0; } static inline uint32_t zbuf_get_be32(struct zbuf *zb) { return be32toh(zbuf_get32(zb)); } static inline void *__zbuf_push(struct zbuf *zb, size_t size, int error) { void *tail = zb->tail; if (size > zbuf_tailroom(zb)) { if (error) zbuf_set_werror(zb); return NULL; } zb->tail += size; return tail; } #define zbuf_push(zb, type) ((type *)__zbuf_push(zb, sizeof(type), 1)) #define zbuf_pushn(zb, sz) ((void *)__zbuf_push(zb, sz, 1)) #define zbuf_may_push(zb, type) ((type *)__zbuf_may_push(zb, sizeof(type), 0)) #define zbuf_may_pushn(zb, sz) ((void *)__zbuf_push(zb, sz, 0)) static inline void zbuf_put(struct zbuf *zb, const void *src, size_t len) { void *dst = zbuf_pushn(zb, len); if (dst) memcpy(dst, src, len); } static inline void zbuf_put8(struct zbuf *zb, uint8_t val) { uint8_t *dst = zbuf_push(zb, uint8_t); if (dst) *dst = val; } static inline void zbuf_put_be16(struct zbuf *zb, uint16_t val) { struct unaligned16 { uint16_t value; } __attribute__((packed)); struct unaligned16 *v = zbuf_push(zb, struct unaligned16); if (v) v->value = htobe16(val); } static inline void zbuf_put_be32(struct zbuf *zb, uint32_t val) { struct unaligned32 { uint32_t value; } __attribute__((packed)); struct unaligned32 *v = zbuf_push(zb, struct unaligned32); if (v) v->value = htobe32(val); } void zbuf_copy(struct zbuf *zb, struct zbuf *src, size_t len); void zbufq_init(struct zbuf_queue *); void zbufq_reset(struct zbuf_queue *); void zbufq_queue(struct zbuf_queue *, struct zbuf *); int zbufq_write(struct zbuf_queue *, int); #endif quagga-1.2.4/nhrpd/znl.c000066400000000000000000000064211325323223500150500ustar00rootroot00000000000000/* Netlink helpers for zbuf * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include "znl.h" #define ZNL_ALIGN(len) (((len)+3) & ~3) void *znl_push(struct zbuf *zb, size_t n) { return zbuf_pushn(zb, ZNL_ALIGN(n)); } void *znl_pull(struct zbuf *zb, size_t n) { return zbuf_pulln(zb, ZNL_ALIGN(n)); } struct nlmsghdr *znl_nlmsg_push(struct zbuf *zb, uint16_t type, uint16_t flags) { struct nlmsghdr *n; n = znl_push(zb, sizeof(*n)); if (!n) return NULL; *n = (struct nlmsghdr) { .nlmsg_type = type, .nlmsg_flags = flags, }; return n; } void znl_nlmsg_complete(struct zbuf *zb, struct nlmsghdr *n) { n->nlmsg_len = zb->tail - (uint8_t*)n; } struct nlmsghdr *znl_nlmsg_pull(struct zbuf *zb, struct zbuf *payload) { struct nlmsghdr *n; size_t plen; n = znl_pull(zb, sizeof(*n)); if (!n) return NULL; plen = n->nlmsg_len - sizeof(*n); zbuf_init(payload, znl_pull(zb, plen), plen, plen); zbuf_may_pulln(zb, ZNL_ALIGN(plen) - plen); return n; } struct rtattr *znl_rta_push(struct zbuf *zb, uint16_t type, const void *val, size_t len) { struct rtattr *rta; uint8_t *dst; rta = znl_push(zb, ZNL_ALIGN(sizeof(*rta)) + ZNL_ALIGN(len)); if (!rta) return NULL; *rta = (struct rtattr) { .rta_type = type, .rta_len = ZNL_ALIGN(sizeof(*rta)) + len, }; dst = (uint8_t *)(rta+1); memcpy(dst, val, len); memset(dst+len, 0, ZNL_ALIGN(len) - len); return rta; } struct rtattr *znl_rta_push_u32(struct zbuf *zb, uint16_t type, uint32_t val) { return znl_rta_push(zb, type, &val, sizeof(val)); } struct rtattr *znl_rta_nested_push(struct zbuf *zb, uint16_t type) { struct rtattr *rta; rta = znl_push(zb, sizeof(*rta)); if (!rta) return NULL; *rta = (struct rtattr) { .rta_type = type, }; return rta; } void znl_rta_nested_complete(struct zbuf *zb, struct rtattr *rta) { size_t len = zb->tail - (uint8_t*) rta; size_t align = ZNL_ALIGN(len) - len; if (align) { void *dst = zbuf_pushn(zb, align); if (dst) memset(dst, 0, align); } rta->rta_len = len; } struct rtattr *znl_rta_pull(struct zbuf *zb, struct zbuf *payload) { struct rtattr *rta; size_t plen; rta = znl_pull(zb, sizeof(*rta)); if (!rta) return NULL; if (rta->rta_len > sizeof(*rta)) { plen = rta->rta_len - sizeof(*rta); zbuf_init(payload, znl_pull(zb, plen), plen, plen); } else { zbuf_init(payload, NULL, 0, 0); } return rta; } int znl_open(int protocol, int groups) { struct sockaddr_nl addr; int fd, buf = 128 * 1024; fd = socket(AF_NETLINK, SOCK_RAW, protocol); if (fd < 0) return -1; fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); fcntl(fd, F_SETFD, FD_CLOEXEC); if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf, sizeof(buf)) < 0) goto error; memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; addr.nl_groups = groups; if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) goto error; return fd; error: close(fd); return -1; } quagga-1.2.4/nhrpd/znl.h000066400000000000000000000021071325323223500150520ustar00rootroot00000000000000/* Netlink helpers for zbuf * Copyright (c) 2014-2015 Timo Teräs * * This file is free software: you may copy, redistribute and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. */ #include "zbuf.h" #define ZNL_BUFFER_SIZE 8192 void *znl_push(struct zbuf *zb, size_t n); void *znl_pull(struct zbuf *zb, size_t n); struct nlmsghdr *znl_nlmsg_push(struct zbuf *zb, uint16_t type, uint16_t flags); void znl_nlmsg_complete(struct zbuf *zb, struct nlmsghdr *n); struct nlmsghdr *znl_nlmsg_pull(struct zbuf *zb, struct zbuf *payload); struct rtattr *znl_rta_push(struct zbuf *zb, uint16_t type, const void *val, size_t len); struct rtattr *znl_rta_push_u32(struct zbuf *zb, uint16_t type, uint32_t val); struct rtattr *znl_rta_nested_push(struct zbuf *zb, uint16_t type); void znl_rta_nested_complete(struct zbuf *zb, struct rtattr *rta); struct rtattr *znl_rta_pull(struct zbuf *zb, struct zbuf *payload); int znl_open(int protocol, int groups); quagga-1.2.4/ospf6d/000077500000000000000000000000001325323223500141645ustar00rootroot00000000000000quagga-1.2.4/ospf6d/Makefile.am000066400000000000000000000017761325323223500162330ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libospf6.a sbin_PROGRAMS = ospf6d 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.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ospf6d.conf.sample quagga-1.2.4/ospf6d/Makefile.in000066400000000000000000000644761325323223500162520ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ospf6d$(EXEEXT) subdir = ospf6d ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libospf6_a_AR = $(AR) $(ARFLAGS) 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) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" 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.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES) DIST_SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libospf6.a 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.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ospf6d.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ospf6d/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ospf6d/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libospf6.a: $(libospf6_a_OBJECTS) $(libospf6_a_DEPENDENCIES) $(EXTRA_libospf6_a_DEPENDENCIES) $(AM_V_at)-rm -f libospf6.a $(AM_V_AR)$(libospf6_a_AR) libospf6.a $(libospf6_a_OBJECTS) $(libospf6_a_LIBADD) $(AM_V_at)$(RANLIB) libospf6.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ospf6d$(EXEEXT): $(ospf6d_OBJECTS) $(ospf6d_DEPENDENCIES) $(EXTRA_ospf6d_DEPENDENCIES) @rm -f ospf6d$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ospf6d_OBJECTS) $(ospf6d_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) 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_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@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/ospf6d/README000066400000000000000000000061341325323223500150500ustar00rootroot00000000000000 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. Depends on interface bandwidth by default. 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. auto-cost reference-bandwidth COST Sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain. Sample configuration is in ospf6d.conf.sample. -- Yasuhiro Ohara Kunihiro Ishiguro quagga-1.2.4/ospf6d/ospf6_abr.c000066400000000000000000000675231325323223500162260ustar00rootroot00000000000000/* * 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) { struct listnode *node; struct ospf6_area *oa; int area_count = 0; for (ALL_LIST_ELEMENTS_RO (o->area_list, node, oa)) 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; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa)) { /* 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, *nro; struct ospf6_lsa *old; struct listnode *node, *nnode; /* Withdraw all summary prefixes previously originated */ for (ro = ospf6_route_head (area->summary_prefix); ro; ro = nro) { nro = 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 = nro) { nro = 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 (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa)) /* 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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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 >= OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("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_debug ("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 != OSPF_AREA_BACKBONE || ! IS_AREA_TRANSIT (area))) { if (is_debug) { prefix2str (&range->prefix, buf, sizeof (buf)); zlog_debug ("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_debug ("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_debug ("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; quagga_gettime (QUAGGA_CLK_MONOTONIC, &summary->changed); } 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); } static 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) { struct listnode *node, *nnode; 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 (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) 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; struct ospf6_inter_prefix_lsa *prefix_lsa = NULL; struct ospf6_inter_router_lsa *router_lsa = NULL; memset (&prefix, 0, sizeof (prefix)); if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX)) { is_debug++; zlog_debug ("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); if (is_debug) 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)) { if (IS_OSPF6_DEBUG_EXAMIN (INTER_ROUTER)) { is_debug++; zlog_debug ("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); if (is_debug) 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 && ! CHECK_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED)) old = route; route = ospf6_route_next (route); } /* (1) if cost == LSInfinity or if the LSA is MaxAge */ if (cost == OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("cost is LS_INFINITY, ignore"); if (old) ospf6_route_remove (old, table); return; } if (OSPF6_LSA_IS_MAXAGE (lsa)) { if (is_debug) zlog_debug ("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_debug ("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 */ /* or if the NU bit is set in the prefix */ if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { range = ospf6_route_lookup (&prefix, oa->range_table); if (range) { if (is_debug) zlog_debug ("Prefix is equal to address range, ignore"); if (old) ospf6_route_remove (old, table); return; } if (CHECK_FLAG (prefix_lsa->prefix.prefix_options, OSPF6_PREFIX_OPTION_NU) || CHECK_FLAG (prefix_lsa->prefix.prefix_options, OSPF6_PREFIX_OPTION_LA)) { if (is_debug) zlog_debug ("Prefix has NU/LA bit set, ignore"); if (old) ospf6_route_remove (old, table); return; } } if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) { /* To pass test suites */ if (! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_R) || ! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_V6)) { if (is_debug) zlog_debug ("Prefix has NU/LA bit set, 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_debug ("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_debug ("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; struct listnode *node, *nnode; u_int16_t type; for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) { type = htons (OSPF6_LSTYPE_INTER_ROUTER); 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 (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 */ static char * ospf6_inter_area_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_inter_prefix_lsa *prefix_lsa; struct in6_addr in6; if (lsa != NULL) { prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); if (buf) { inet_ntop (AF_INET6, &in6, buf, buflen); sprintf (&buf[strlen(buf)], "/%d", prefix_lsa->prefix.prefix_length); } } return (buf); } static int ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_inter_prefix_lsa *prefix_lsa; char buf[INET6_ADDRSTRLEN]; 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); vty_out (vty, " Prefix: %s%s", ospf6_inter_area_prefix_lsa_get_prefix_str (lsa, buf, sizeof(buf), 0), VNL); return 0; } static char * ospf6_inter_area_router_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_inter_router_lsa *router_lsa; if (lsa != NULL) { router_lsa = (struct ospf6_inter_router_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (buf) inet_ntop (AF_INET, &router_lsa->router_id, buf, buflen); } return (buf); } static 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 (void) { 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", "IAP", ospf6_inter_area_prefix_lsa_show, ospf6_inter_area_prefix_lsa_get_prefix_str, }; struct ospf6_lsa_handler inter_router_handler = { OSPF6_LSTYPE_INTER_ROUTER, "Inter-Router", "IAR", ospf6_inter_area_router_lsa_show, ospf6_inter_area_router_lsa_get_prefix_str, }; void ospf6_abr_init (void) { ospf6_install_lsa_handler (&inter_prefix_handler); ospf6_install_lsa_handler (&inter_router_handler); } quagga-1.2.4/ospf6d/ospf6_abr.h000066400000000000000000000050571325323223500162250ustar00rootroot00000000000000/* * 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 /* for struct ospf6_route */ #include "ospf6_route.h" /* for struct ospf6_prefix */ #include "ospf6_proto.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 */ #define OSPF6_INTER_PREFIX_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ struct ospf6_inter_prefix_lsa { u_int32_t metric; struct ospf6_prefix prefix; }; /* Inter-Area-Router-LSA */ #define OSPF6_INTER_ROUTER_LSA_FIX_SIZE 12U 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); } extern int ospf6_is_router_abr (struct ospf6 *o); extern void ospf6_abr_enable_area (struct ospf6_area *oa); extern void ospf6_abr_disable_area (struct ospf6_area *oa); extern void ospf6_abr_originate_summary_to_area (struct ospf6_route *route, struct ospf6_area *area); extern void ospf6_abr_originate_summary (struct ospf6_route *route); extern void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa); extern void ospf6_abr_examin_brouter (u_int32_t router_id); extern void ospf6_abr_reimport (struct ospf6_area *oa); extern int config_write_ospf6_debug_abr (struct vty *vty); extern void install_element_ospf6_debug_abr (void); extern int ospf6_abr_config_write (struct vty *vty); extern void ospf6_abr_init (void); #endif /*OSPF6_ABR_H*/ quagga-1.2.4/ospf6d/ospf6_area.c000066400000000000000000000526401325323223500163640ustar00rootroot00000000000000/* * 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 */ static 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_debug ("Examin %s", lsa->name); zlog_debug ("Schedule SPF Calculation for %s", OSPF6_AREA (lsa->lsdb->data)->name); } ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6), ospf6_lsadd_to_spf_reason(lsa)); 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; } } static 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_debug ("LSA disappearing: %s", lsa->name); zlog_debug ("Schedule SPF Calculation for %s", OSPF6_AREA (lsa->lsdb->data)->name); } ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6), ospf6_lsremove_to_spf_reason(lsa)); 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; } } static 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); } static 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 (AREA, SPF_RESULTS); oa->spf_table->scope = oa; oa->route_table = OSPF6_ROUTE_TABLE_CREATE (AREA, ROUTES); oa->route_table->scope = oa; 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 (AREA, PREFIX_RANGES); oa->range_table->scope = oa; oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_PREFIXES); oa->summary_prefix->scope = oa; oa->summary_router = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_ROUTERS); oa->summary_router->scope = oa; /* set default options */ if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER)) { OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_V6); OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_R); } else { OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); } OSPF6_OPT_SET (oa->options, OSPF6_OPT_E); 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) { struct 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); /* The ospf6_interface structs store configuration * information which should not be lost/reset when * deleting an area. * So just detach the interface from the area and * keep it around. */ for (ALL_LIST_ELEMENTS_RO (oa->if_list, n, oi)) oi->area = NULL; list_delete (oa->if_list); ospf6_lsdb_delete (oa->lsdb); ospf6_lsdb_delete (oa->lsdb_self); ospf6_spf_table_finish (oa->spf_table); ospf6_route_table_delete (oa->spf_table); ospf6_route_table_delete (oa->route_table); 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; struct listnode *n; for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, n, oa)) if (oa->area_id == area_id) return oa; return (struct ospf6_area *) NULL; } static 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) { struct listnode *node, *nnode; struct ospf6_interface *oi; SET_FLAG (oa->flag, OSPF6_AREA_ENABLE); for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) ospf6_interface_enable (oi); ospf6_abr_enable_area (oa); } void ospf6_area_disable (struct ospf6_area *oa) { struct listnode *node, *nnode; struct ospf6_interface *oi; UNSET_FLAG (oa->flag, OSPF6_AREA_ENABLE); for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) ospf6_interface_disable (oi); ospf6_abr_disable_area (oa); ospf6_lsdb_remove_all (oa->lsdb); ospf6_lsdb_remove_all (oa->lsdb_self); ospf6_spf_table_finish(oa->spf_table); ospf6_route_remove_all(oa->route_table); THREAD_OFF (oa->thread_spf_calculation); THREAD_OFF (oa->thread_route_calculation); THREAD_OFF (oa->thread_router_lsa); THREAD_OFF (oa->thread_intra_prefix_lsa); } void ospf6_area_show (struct vty *vty, struct ospf6_area *oa) { struct 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 (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi)) 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); } if (range->rnode) { vty_out (vty, "Range already defined: %s%s", argv[-1], VNL); return CMD_WARNING; } 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) { struct listnode *node; struct ospf6_area *oa; struct ospf6_route *range; char buf[128]; for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { 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); } if (PREFIX_NAME_IN (oa)) vty_out (vty, " area %s filter-list prefix %s in%s", oa->name, PREFIX_NAME_IN (oa), VNL); if (PREFIX_NAME_OUT (oa)) vty_out (vty, " area %s filter-list prefix %s out%s", oa->name, PREFIX_NAME_OUT (oa), VNL); if (IMPORT_NAME (oa)) vty_out (vty, " area %s import-list %s%s", oa->name, IMPORT_NAME (oa), VNL); if (EXPORT_NAME (oa)) vty_out (vty, " area %s export-list %s%s", oa->name, EXPORT_NAME (oa), 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[0]); if (strncmp (argv[1], "in", 2) == 0) { PREFIX_LIST_IN (area) = plist; if (PREFIX_NAME_IN (area)) free (PREFIX_NAME_IN (area)); PREFIX_NAME_IN (area) = strdup (argv[0]); 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[0]); 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; OSPF6_CMD_AREA_GET (argv[0], area); argc--; argv++; if (strncmp (argv[1], "in", 2) == 0) { if (PREFIX_NAME_IN (area)) if (strcmp (PREFIX_NAME_IN (area), argv[0]) != 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[0]) != 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 calculation\n" "Show SPF tree\n") { struct listnode *node; struct ospf6_area *oa; struct ospf6_vertex *root; struct ospf6_route *route; struct prefix prefix; OSPF6_CMD_CHECK_RUNNING (); ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { 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 calculation\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_CMD_CHECK_RUNNING (); 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 calculation\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; OSPF6_CMD_CHECK_RUNNING (); 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 (NONE, SPF_RESULTS); 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 (void) { 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 (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); } quagga-1.2.4/ospf6d/ospf6_area.h000066400000000000000000000066761325323223500164010ustar00rootroot00000000000000/* * 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 */ struct 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; u_int32_t spf_calculation; /* SPF calculation count */ 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 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 */ extern int ospf6_area_cmp (void *va, void *vb); extern struct ospf6_area *ospf6_area_create (u_int32_t, struct ospf6 *); extern void ospf6_area_delete (struct ospf6_area *); extern struct ospf6_area *ospf6_area_lookup (u_int32_t, struct ospf6 *); extern void ospf6_area_enable (struct ospf6_area *); extern void ospf6_area_disable (struct ospf6_area *); extern void ospf6_area_show (struct vty *, struct ospf6_area *); extern void ospf6_area_config_write (struct vty *vty); extern void ospf6_area_init (void); #endif /* OSPF_AREA_H */ quagga-1.2.4/ospf6d/ospf6_asbr.c000066400000000000000000001255021325323223500164010ustar00rootroot00000000000000/* * 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; #define ZROUTE_NAME(x) zebra_route_string(x) /* AS External LSA origination */ static void ospf6_as_external_lsa_originate (struct ospf6_route *route) { char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; struct ospf6_lsa *lsa; struct ospf6_external_info *info = route->route_option; struct ospf6_as_external_lsa *as_external_lsa; char buf[64]; caddr_t p; if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE (AS_EXTERNAL)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("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 (&info->forwarding)) 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 */ if (info->tag) SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T); else 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, &info->forwarding, sizeof (struct in6_addr)); p += sizeof (struct in6_addr); } /* External Route Tag */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) { route_tag_t network_order = htonl(info->tag); memcpy (p, &network_order, sizeof(network_order)); p += sizeof(network_order); } /* 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); } static route_tag_t ospf6_as_external_lsa_get_tag (struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; ptrdiff_t tag_offset; route_tag_t network_order; if (!lsa) return 0; external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (!CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T)) return 0; tag_offset = sizeof(*external) + OSPF6_PREFIX_SPACE(external->prefix.prefix_length); if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) tag_offset += sizeof(struct in6_addr); memcpy(&network_order, (caddr_t)external + tag_offset, sizeof(network_order)); return ntohl(network_order); } 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_debug ("Calculate AS-External route for %s", lsa->name); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore self-originated AS-External-LSA"); return; } if (OSPF6_ASBR_METRIC (external) == OSPF_LS_INFINITY) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore LSA with LSInfinity Metric"); return; } if (CHECK_FLAG(external->prefix.prefix_options, OSPF6_PREFIX_OPTION_NU)) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore LSA with NU bit set 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_debug ("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; } route->path.tag = ospf6_as_external_lsa_get_tag (lsa); 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_debug ("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, *nroute; char buf[64]; external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Withdraw AS-External route for %s", lsa->name); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("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_debug ("AS-External route %s not found", buf); } return; } for (ospf6_route_lock (route); route && ospf6_route_is_prefix (&prefix, route); route = nroute) { nroute = 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_debug ("AS-External route remove: %s", buf); } ospf6_route_remove (route, ospf6->route_table); } if (route != NULL) ospf6_route_unlock (route); } void ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry) { struct ospf6_lsa *lsa; u_int16_t type; u_int32_t router; if (! CHECK_FLAG (asbr_entry->flag, OSPF6_ROUTE_BEST)) { char buf[16]; inet_ntop (AF_INET, &ADV_ROUTER_IN_PREFIX (&asbr_entry->prefix), buf, sizeof (buf)); zlog_info ("ignore non-best path: lsentry %s add", buf); return; } 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); } } void ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry) { struct ospf6_lsa *lsa; u_int16_t type; u_int32_t router; 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); } /* redistribute function */ static void ospf6_asbr_routemap_set (int type, const 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); } static 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; } static void ospf6_asbr_routemap_update (const 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; } static void ospf6_asbr_redistribute_set (int type) { ospf6_zebra_redistribute (type); } static 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); } ospf6_asbr_routemap_unset (type); } void ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop, route_tag_t tag) { 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]; struct listnode *lnode, *lnnode; struct ospf6_area *oa; if (! ospf6_zebra_is_redistribute (type)) return; if (IS_OSPF6_DEBUG_ASBR) { prefix2str (prefix, pbuf, sizeof (pbuf)); zlog_debug ("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; tinfo.ifindex = ifindex; tinfo.tag = tag; ret = route_map_apply (ospf6->rmap[type].map, prefix, RMAP_OSPF6, &troute); if (ret == RMAP_DENYMATCH) { if (IS_OSPF6_DEBUG_ASBR) zlog_debug ("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->tag = tinfo.tag; } else { /* If there is no route-map, simply update the tag */ info->tag = tag; } 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_debug ("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 *) XCALLOC (MTYPE_OSPF6_EXTERNAL_INFO, 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->tag = tinfo.tag; } else { /* If there is no route-map, simply set the tag */ info->tag = tag; } 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_debug ("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 (ALL_LIST_ELEMENTS (ospf6->area_list, lnode, lnnode, oa)) OSPF6_ROUTER_LSA_SCHEDULE (oa); } void ospf6_asbr_redistribute_remove (int type, ifindex_t 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]; struct listnode *lnode, *lnnode; 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_debug ("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_debug ("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_debug ("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 (ALL_LIST_ELEMENTS (ospf6->area_list, lnode, lnnode, oa)) OSPF6_ROUTER_LSA_SCHEDULE (oa); } DEFUN (ospf6_redistribute, ospf6_redistribute_cmd, "redistribute " QUAGGA_REDIST_STR_OSPF6D, "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; ospf6_asbr_redistribute_unset (type); ospf6_asbr_redistribute_set (type); return CMD_SUCCESS; } DEFUN (ospf6_redistribute_routemap, ospf6_redistribute_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_OSPF6D " route-map WORD", "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D "Route map reference\n" "Route map name\n" ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; 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 " QUAGGA_REDIST_STR_OSPF6D, NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; ospf6_asbr_redistribute_unset (type); return CMD_SUCCESS; } ALIAS (no_ospf6_redistribute, no_ospf6_redistribute_route_map_cmd, "no redistribute " QUAGGA_REDIST_STR_OSPF6D " route-map WORD", NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D "Route map reference\n" "Route map name\n") 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; } static 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 */ static 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); } static void * ospf6_routemap_rule_match_address_prefixlist_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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, }; /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return zero. */ static route_map_result_t ospf6_routemap_rule_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct interface *ifp; struct ospf6_external_info *ei; if (type == RMAP_OSPF6) { ei = ((struct ospf6_route *) object)->route_option; ifp = if_lookup_by_name ((char *)rule); if (ifp != NULL && ei->ifindex == ifp->ifindex) return RMAP_MATCH; } return RMAP_NOMATCH; } /* Route map `interface' match statement. `arg' should be interface name. */ static void * ospf6_routemap_rule_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `interface' value. */ static void ospf6_routemap_rule_match_interface_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for interface matching. */ struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = { "interface", ospf6_routemap_rule_match_interface, ospf6_routemap_rule_match_interface_compile, ospf6_routemap_rule_match_interface_free }; /* Match function for matching route tags */ static route_map_result_t ospf6_routemap_rule_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag = rule; struct ospf6_route *route = object; struct ospf6_external_info *info = route->route_option; if (type == RMAP_OSPF6 && info->tag == *tag) return RMAP_MATCH; return RMAP_NOMATCH; } static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = { "tag", ospf6_routemap_rule_match_tag, route_map_rule_tag_compile, route_map_rule_tag_free, }; static 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; } static void * ospf6_routemap_rule_set_metric_type_compile (const char *arg) { if (strcmp (arg, "type-2") && strcmp (arg, "type-1")) return NULL; return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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, }; static 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; } static void * ospf6_routemap_rule_set_metric_compile (const char *arg) { u_int32_t metric; char *endp; metric = strtoul (arg, &endp, 0); if (metric > OSPF_LS_INFINITY || *endp != '\0') return NULL; return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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, }; static 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; } static void * ospf6_routemap_rule_set_forwarding_compile (const char *arg) { struct in6_addr a; if (inet_pton (AF_INET6, arg, &a) != 1) return NULL; return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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, }; static route_map_result_t ospf6_routemap_rule_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag = rule; struct ospf6_route *route = object; struct ospf6_external_info *info = route->route_option; if (type != RMAP_OSPF6) return RMAP_OKAY; info->tag = *tag; return RMAP_OKAY; } static struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = { "tag", ospf6_routemap_rule_set_tag, route_map_rule_tag_compile, route_map_rule_tag_free, }; static int route_map_command_status (struct vty *vty, int ret) { if (! ret) return CMD_SUCCESS; switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "OSPF6 Can't find rule.%s", VNL); break; case RMAP_COMPILE_ERROR: vty_out (vty, "OSPF6 Argument is malformed.%s", VNL); break; default: vty_out (vty, "OSPF6 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); } /* "match interface" */ DEFUN (ospf6_routemap_match_interface, ospf6_routemap_match_interface_cmd, "match interface WORD", MATCH_STR "Match first hop interface of route\n" "Interface name\n") { return route_map_add_match ((struct route_map_index *) vty->index, "interface", argv[0]); } /* "no match interface WORD" */ DEFUN (ospf6_routemap_no_match_interface, ospf6_routemap_no_match_interface_cmd, "no match interface", NO_STR MATCH_STR "Match first hop interface of route\n") { int ret = route_map_delete_match ((struct route_map_index *) vty->index, "interface", (argc == 0) ? NULL : argv[0]); return route_map_command_status (vty, ret); } ALIAS (ospf6_routemap_no_match_interface, ospf6_routemap_no_match_interface_val_cmd, "no match interface WORD", NO_STR MATCH_STR "Match first hop interface of route\n" "Interface name\n") /* add "match tag" */ DEFUN (ospf6_routemap_match_tag, ospf6_routemap_match_tag_cmd, "match tag <1-4294967295>", MATCH_STR "Tag value for routing protocol\n" "Tag value\n") { int ret = route_map_add_match ((struct route_map_index *) vty->index, "tag", argv[0]); return route_map_command_status (vty, ret); } /* delete "match tag" */ DEFUN (ospf6_routemap_no_match_tag, ospf6_routemap_no_match_tag_cmd, "no match tag", NO_STR MATCH_STR "Tag value for routing protocol\n") { int ret = route_map_delete_match ((struct route_map_index *) vty->index, "tag", argc ? argv[0] : NULL); return route_map_command_status (vty, ret); } ALIAS (ospf6_routemap_no_match_tag, ospf6_routemap_no_match_tag_val_cmd, "no match tag <1-4294967295>", NO_STR MATCH_STR "Tag value for routing protocol\n" "Tag value\n") /* 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", NO_STR SET_STR "Metric value for destination routing protocol\n") { int ret = 0; if (argc == 0) ret = route_map_delete_set ((struct route_map_index *) vty->index, "metric", NULL); else ret = route_map_delete_set ((struct route_map_index *) vty->index, "metric", argv[0]); return route_map_command_status (vty, ret); } 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") /* 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); } /* add "set tag" */ DEFUN (ospf6_routemap_set_tag, ospf6_routemap_set_tag_cmd, "set tag <1-4294967295>", "Set value\n" "Tag value for routing protocol\n" "Tag value\n") { int ret = route_map_add_set ((struct route_map_index *) vty->index, "tag", argv[0]); return route_map_command_status (vty, ret); } /* delete "set tag" */ DEFUN (ospf6_routemap_no_set_tag, ospf6_routemap_no_set_tag_cmd, "no set tag", NO_STR "Set value\n" "Tag value for routing protocol\n") { int ret = route_map_delete_set ((struct route_map_index *) vty->index, "tag", argc ? argv[0] : NULL); return route_map_command_status (vty, ret); } ALIAS (ospf6_routemap_no_set_tag, ospf6_routemap_no_set_tag_val_cmd, "no set tag <1-4294967295>", NO_STR "Set value\n" "Tag value for routing protocol\n" "Tag value\n") static void ospf6_routemap_init (void) { 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_match (&ospf6_routemap_rule_match_interface_cmd); route_map_install_match (&ospf6_routemap_rule_match_tag_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); route_map_install_set (&ospf6_routemap_rule_set_tag_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); /* Match interface */ install_element (RMAP_NODE, &ospf6_routemap_match_interface_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_val_cmd); /* Match tag */ install_element (RMAP_NODE, &ospf6_routemap_match_tag_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_tag_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_tag_val_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); install_element (RMAP_NODE, &no_set_metric_val_cmd); /* Forwarding address */ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd); /* Tag */ install_element (RMAP_NODE, &ospf6_routemap_set_tag_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_tag_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_tag_val_cmd); } /* Display functions */ static char * ospf6_as_external_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_as_external_lsa *external; struct in6_addr in6; int prefix_length = 0; if (lsa) { external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (pos == 0) { ospf6_prefix_in6_addr (&in6, &external->prefix); prefix_length = external->prefix.prefix_length; } else { in6 = *((struct in6_addr *) ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) + OSPF6_PREFIX_SPACE (external->prefix.prefix_length))); } if (buf) { inet_ntop (AF_INET6, &in6, buf, buflen); if (prefix_length) sprintf (&buf[strlen(buf)], "/%d", prefix_length); } } return (buf); } static int ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; char buf[64]; 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); vty_out (vty, " Prefix: %s%s", ospf6_as_external_lsa_get_prefix_str (lsa, buf, sizeof(buf), 0), VNL); /* Forwarding-Address */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) { vty_out (vty, " Forwarding-Address: %s%s", ospf6_as_external_lsa_get_prefix_str (lsa, buf, sizeof(buf), 1), VNL); } /* Tag */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T)) { vty_out (vty, " Tag: %u%s", ospf6_as_external_lsa_get_tag (lsa), VNL); } return 0; } static 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, "%c %-32s %-15s type-%d %5lu %s%s", zebra_route_char(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_CMD_CHECK_RUNNING (); 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", "ASE", ospf6_as_external_lsa_show, ospf6_as_external_lsa_get_prefix_str }; void ospf6_asbr_init (void) { ospf6_routemap_init (); ospf6_install_lsa_handler (&as_external_handler); install_element (VIEW_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); install_element (OSPF6_NODE, &no_ospf6_redistribute_route_map_cmd); } void ospf6_asbr_redistribute_reset (void) { int type; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { if (type == ZEBRA_ROUTE_OSPF6) continue; if (ospf6_zebra_is_redistribute (type)) ospf6_asbr_redistribute_unset(type); } } void ospf6_asbr_terminate (void) { route_map_finish (); } 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); } quagga-1.2.4/ospf6d/ospf6_asbr.h000066400000000000000000000062511325323223500164050ustar00rootroot00000000000000/* * 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 /* for struct ospf6_prefix */ #include "ospf6_proto.h" /* for struct ospf6_lsa */ #include "ospf6_lsa.h" /* for struct ospf6_route */ #include "ospf6_route.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; route_tag_t tag; ifindex_t ifindex; }; /* AS-External-LSA */ #define OSPF6_AS_EXTERNAL_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ 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); } extern void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa); extern void ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa); extern void ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry); extern int ospf6_asbr_is_asbr (struct ospf6 *o); extern void ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop, route_tag_t tag); extern void ospf6_asbr_redistribute_remove (int type, ifindex_t ifindex, struct prefix *prefix); extern int ospf6_redistribute_config_write (struct vty *vty); extern void ospf6_asbr_init (void); extern void ospf6_asbr_redistribute_reset (void); extern void ospf6_asbr_terminate (void); extern int config_write_ospf6_debug_asbr (struct vty *vty); extern void install_element_ospf6_debug_asbr (void); #endif /* OSPF6_ASBR_H */ quagga-1.2.4/ospf6d/ospf6_flood.c000066400000000000000000000754721325323223500165670ustar00rootroot00000000000000/* * 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_debug ("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, OSPF_LS_REFRESH_TIME); if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type)) { zlog_debug ("LSA Originate:"); ospf6_lsa_header_print (lsa); } ospf6_install_lsa (lsa); ospf6_flood (NULL, 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 timeval now; struct ospf6_lsa *old; if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) zlog_debug ("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); THREAD_OFF (old->refresh); ospf6_flood_clear (old); } quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); if (! OSPF6_LSA_IS_MAXAGE (lsa)) lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa, OSPF_LSA_MAXAGE + lsa->birth.tv_sec - now.tv_sec); else lsa->expire = NULL; if (OSPF6_LSA_IS_SEQWRAP(lsa) && ! (CHECK_FLAG(lsa->flag,OSPF6_LSA_SEQWRAPPED) && lsa->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))) { if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) zlog_debug("lsa install wrapping: sequence 0x%x", ntohl(lsa->header->seqnum)); SET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED); /* in lieu of premature_aging, since we do not want to recreate this lsa * and/or mess with timers etc, we just want to wrap the sequence number * and reflood the lsa before continuing. * NOTE: Flood needs to be called right after this function call, by the * caller */ lsa->header->seqnum = htonl (OSPF_MAX_SEQUENCE_NUMBER); lsa->header->age = htons (OSPF_LSA_MAXAGE); ospf6_lsa_checksum (lsa->header); } /* 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 */ static void ospf6_flood_interface (struct ospf6_neighbor *from, struct ospf6_lsa *lsa, struct ospf6_interface *oi) { struct listnode *node, *nnode; 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_debug ("Flooding on %s: %s", oi->interface->name, lsa->name); } /* (1) For each neighbor */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { if (is_debug) zlog_debug ("To neighbor %s", on->name); /* (a) if neighbor state < Exchange, examin next */ if (on->state < OSPF6_NEIGHBOR_EXCHANGE) { if (is_debug) zlog_debug ("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_debug ("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_debug ("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_debug ("Requesting is older, 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_debug ("Requesting the same, remove it, next neighbor"); if (req == on->last_ls_req) { ospf6_lsa_unlock (req); on->last_ls_req = NULL; } ospf6_lsdb_remove (req, on->request_list); ospf6_check_nbr_loading (on); continue; } /* If the new LSA is more recent, delete from request-list */ if (ospf6_lsa_compare (lsa, req) < 0) { if (is_debug) zlog_debug ("Received is newer, remove requesting"); if (req == on->last_ls_req) { ospf6_lsa_unlock (req); on->last_ls_req = NULL; } ospf6_lsdb_remove (req, on->request_list); ospf6_check_nbr_loading (on); /* fall through */ } } } /* (c) If the new LSA was received from this neighbor, examin next neighbor */ if (from == on) { if (is_debug) zlog_debug ("Received is from the neighbor, next neighbor"); continue; } /* (d) add retrans-list, schedule retransmission */ if (is_debug) zlog_debug ("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_timer (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_debug ("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_debug ("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) { if (oi->state == OSPF6_INTERFACE_BDR) { if (is_debug) zlog_debug ("Received is from the I/F, itself BDR, next interface"); return; } SET_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK); } /* (5) flood the LSA out the interface. */ if (is_debug) zlog_debug ("Schedule flooding for the interface"); if ((oi->type == OSPF_IFTYPE_BROADCAST) || (oi->type == OSPF_IFTYPE_POINTOPOINT)) { 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 (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { THREAD_OFF (on->thread_send_lsupdate); on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); } } } static void ospf6_flood_area (struct ospf6_neighbor *from, struct ospf6_lsa *lsa, struct ospf6_area *oa) { struct listnode *node, *nnode; struct ospf6_interface *oi; for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) { 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); } } static void ospf6_flood_process (struct ospf6_neighbor *from, struct ospf6_lsa *lsa, struct ospf6 *process) { struct listnode *node, *nnode; struct ospf6_area *oa; for (ALL_LIST_ELEMENTS (process->area_list, node, nnode, oa)) { 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); } static void ospf6_flood_clear_interface (struct ospf6_lsa *lsa, struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on; struct ospf6_lsa *rem; for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { 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_debug ("Remove %s from retrans_list of %s", rem->name, on->name); ospf6_decrement_retrans_count (rem); ospf6_lsdb_remove (rem, on->retrans_list); } } } static void ospf6_flood_clear_area (struct ospf6_lsa *lsa, struct ospf6_area *oa) { struct listnode *node, *nnode; struct ospf6_interface *oi; for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) { 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); } } static void ospf6_flood_clear_process (struct ospf6_lsa *lsa, struct ospf6 *process) { struct listnode *node, *nnode; struct ospf6_area *oa; for (ALL_LIST_ELEMENTS (process->area_list, node, nnode, oa)) { 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 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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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 () */ } static 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; struct 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 (ALL_LIST_ELEMENTS_RO (process->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on)) 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; 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_debug ("LSA Receive from %s", from->name); ospf6_lsa_header_print (new); } /* (1) LSA Checksum */ if (! ospf6_lsa_checksum_valid (new->header)) { if (is_debug) zlog_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &old->installed, &res); if (res.tv_sec < (OSPF_MIN_LS_ARRIVAL / 1000)) { if (is_debug) zlog_debug ("LSA can't be updated within MinLSArrival, discard"); ospf6_lsa_delete (new); return; /* examin next lsa */ } } quagga_gettime (QUAGGA_CLK_MONOTONIC, &new->received); if (is_debug) zlog_debug ("Install, Flood, Possibly acknowledge the received LSA"); /* Remove older copies of this LSA from retx lists */ if (old) ospf6_flood_clear (old); /* (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); /* (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_debug ("Newer instance of the self-originated LSA"); zlog_debug ("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_debug ("Received is not newer, on the neighbor's request-list"); zlog_debug ("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_debug ("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_debug ("It is on the neighbor's retrans-list."); zlog_debug ("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_debug ("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 (OSPF_MAX_SEQUENCE_NUMBER)) { if (is_debug) { zlog_debug ("The LSA is in Seqnumber Wrapping"); zlog_debug ("MaxAge & MaxSeqNum, discard"); } ospf6_lsa_delete (new); return; } /* Otherwise, Send database copy of this LSA to this neighbor */ { if (is_debug) { zlog_debug ("Database copy is more recent."); zlog_debug ("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 (void) { 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); } quagga-1.2.4/ospf6d/ospf6_flood.h000066400000000000000000000047261325323223500165660ustar00rootroot00000000000000/* * 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 */ extern struct ospf6_lsdb *ospf6_get_scoped_lsdb (struct ospf6_lsa *lsa); extern struct ospf6_lsdb *ospf6_get_scoped_lsdb_self (struct ospf6_lsa *lsa); /* origination & purging */ extern void ospf6_lsa_originate (struct ospf6_lsa *lsa); extern void ospf6_lsa_originate_process (struct ospf6_lsa *lsa, struct ospf6 *process); extern void ospf6_lsa_originate_area (struct ospf6_lsa *lsa, struct ospf6_area *oa); extern void ospf6_lsa_originate_interface (struct ospf6_lsa *lsa, struct ospf6_interface *oi); extern void ospf6_lsa_purge (struct ospf6_lsa *lsa); /* access method to retrans_count */ extern void ospf6_increment_retrans_count (struct ospf6_lsa *lsa); extern void ospf6_decrement_retrans_count (struct ospf6_lsa *lsa); /* flooding & clear flooding */ extern void ospf6_flood_clear (struct ospf6_lsa *lsa); extern void ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa); /* receive & install */ extern void ospf6_receive_lsa (struct ospf6_neighbor *from, struct ospf6_lsa_header *header); extern void ospf6_install_lsa (struct ospf6_lsa *lsa); extern int config_write_ospf6_debug_flood (struct vty *vty); extern void install_element_ospf6_debug_flood (void); #endif /* OSPF6_FLOOD_H */ quagga-1.2.4/ospf6d/ospf6_interface.c000066400000000000000000001473521325323223500174210ustar00rootroot00000000000000/* * 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 "ospf6_snmp.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_interface = 0; const char *ospf6_interface_state_str[] = { "None", "Down", "Loopback", "Waiting", "PointToPoint", "DROther", "BDR", "DR", NULL }; struct ospf6_interface * ospf6_interface_lookup_by_ifindex (ifindex_t 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; } /* schedule routing table recalculation */ static void ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa, unsigned int reason) { struct ospf6_interface *oi; if (lsa == NULL) return; oi = lsa->lsdb->data; switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_LINK: if (oi->state == OSPF6_INTERFACE_DR) OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); ospf6_spf_schedule (oi->area->ospf6, reason); break; default: break; } } static void ospf6_interface_lsdb_hook_add (struct ospf6_lsa *lsa) { ospf6_interface_lsdb_hook(lsa, ospf6_lsadd_to_spf_reason(lsa)); } static void ospf6_interface_lsdb_hook_remove (struct ospf6_lsa *lsa) { ospf6_interface_lsdb_hook(lsa, ospf6_lsremove_to_spf_reason(lsa)); } static u_char ospf6_default_iftype(struct interface *ifp) { if (if_is_pointopoint (ifp)) return OSPF_IFTYPE_POINTOPOINT; else if (if_is_loopback (ifp)) return OSPF_IFTYPE_LOOPBACK; else return OSPF_IFTYPE_BROADCAST; } static u_int32_t ospf6_interface_get_cost (struct ospf6_interface *oi) { /* If all else fails, use default OSPF cost */ u_int32_t cost; u_int32_t bw, refbw; bw = oi->interface->bandwidth ? oi->interface->bandwidth : OSPF6_INTERFACE_BANDWIDTH; refbw = ospf6 ? ospf6->ref_bandwidth : OSPF6_REFERENCE_BANDWIDTH; /* A specifed ip ospf cost overrides a calculated one. */ if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST)) cost = oi->cost; else { cost = (u_int32_t) ((double)refbw / (double)bw + (double)0.5); if (cost < 1) cost = 1; else if (cost > UINT32_MAX) cost = UINT32_MAX; } return cost; } static void ospf6_interface_recalculate_cost (struct ospf6_interface *oi) { u_int32_t newcost; newcost = ospf6_interface_get_cost (oi); if (newcost == oi->cost) return; oi->cost = newcost; /* 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); } } /* Create new ospf6 interface structure */ struct ospf6_interface * ospf6_interface_create (struct interface *ifp) { struct ospf6_interface *oi; unsigned int iobuflen; oi = (struct ospf6_interface *) XCALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface)); if (!oi) { 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 = OSPF6_INTERFACE_INSTANCE_ID; oi->transdelay = OSPF6_INTERFACE_TRANSDELAY; oi->priority = OSPF6_INTERFACE_PRIORITY; oi->hello_interval = OSPF_HELLO_INTERVAL_DEFAULT; oi->dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; oi->rxmt_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; oi->type = ospf6_default_iftype (ifp); oi->state = OSPF6_INTERFACE_DOWN; oi->flag = 0; oi->mtu_ignore = 0; /* Try to adjust I/O buffer size with IfMtu */ oi->ifmtu = ifp->mtu6; iobuflen = ospf6_iobuf_size (ifp->mtu6); if (oi->ifmtu > iobuflen) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("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_add; oi->lsdb->hook_remove = ospf6_interface_lsdb_hook_remove; oi->lsdb_self = ospf6_lsdb_create (oi); oi->route_connected = OSPF6_ROUTE_TABLE_CREATE (INTERFACE, CONNECTED_ROUTES); oi->route_connected->scope = oi; /* link both */ oi->interface = ifp; ifp->info = oi; /* Compute cost. */ oi->cost = ospf6_interface_get_cost(oi); return oi; } void ospf6_interface_delete (struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on; for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) 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); ospf6_interface_state_update (oi->interface); } void ospf6_interface_disable (struct ospf6_interface *oi) { SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); thread_execute (master, interface_down, oi, 0); ospf6_lsdb_remove_all (oi->lsdb); ospf6_lsdb_remove_all (oi->lsdb_self); 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); THREAD_OFF (oi->thread_network_lsa); THREAD_OFF (oi->thread_link_lsa); THREAD_OFF (oi->thread_intra_prefix_lsa); } static struct in6_addr * ospf6_interface_get_linklocal_address (struct interface *ifp) { struct listnode *n; struct connected *c; struct in6_addr *l = (struct in6_addr *) NULL; /* for each connected address */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, n, c)) { /* 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; unsigned 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->mtu6; iobuflen = ospf6_iobuf_size (ifp->mtu6); if (oi->ifmtu > iobuflen) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", ifp->name, iobuflen); oi->ifmtu = iobuflen; } /* interface start */ ospf6_interface_state_update(oi->interface); } 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 (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) return; if (if_is_operative (ifp) && (ospf6_interface_get_linklocal_address(oi->interface) || if_is_loopback(oi->interface))) 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; struct listnode *node, *nnode; 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; if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) return; /* update "route to advertise" interface route table */ ospf6_route_remove_all (oi->route_connected); for (ALL_LIST_ELEMENTS (oi->interface->connected, node, nnode, c)) { 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_debug ("%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_debug ("Interface state change %s: %s -> %s", oi->interface->name, ospf6_interface_state_str[prev_state], ospf6_interface_state_str[next_state]); } oi->state_change++; if ((prev_state == OSPF6_INTERFACE_DR || prev_state == OSPF6_INTERFACE_BDR) && (next_state != OSPF6_INTERFACE_DR && next_state != OSPF6_INTERFACE_BDR)) ospf6_sso (oi->interface->ifindex, &alldrouters6, IPV6_LEAVE_GROUP); if ((prev_state != OSPF6_INTERFACE_DR && prev_state != OSPF6_INTERFACE_BDR) && (next_state == OSPF6_INTERFACE_DR || next_state == OSPF6_INTERFACE_BDR)) ospf6_sso (oi->interface->ifindex, &alldrouters6, IPV6_JOIN_GROUP); 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); } #ifdef HAVE_SNMP /* Terminal state or regression */ if ((next_state == OSPF6_INTERFACE_POINTTOPOINT) || (next_state == OSPF6_INTERFACE_DROTHER) || (next_state == OSPF6_INTERFACE_BDR) || (next_state == OSPF6_INTERFACE_DR) || (next_state < prev_state)) ospf6TrapIfStateChange (oi); #endif } /* 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) { struct listnode *node, *nnode; 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 (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) bdrouter = better_bdrouter (bdrouter, on); best_bdrouter = bdrouter; bdrouter = better_bdrouter (best_bdrouter, &myself); /* Electing DR (3) */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) 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_debug ("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 (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, node, on)) { 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_debug ("Interface Event %s: [InterfaceUp]", oi->interface->name); /* check physical interface is up */ if (! if_is_operative (oi->interface)) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s is down, can't execute [InterfaceUp]", oi->interface->name); return 0; } /* check interface has a link-local address */ if (! (ospf6_interface_get_linklocal_address(oi->interface) || if_is_loopback(oi->interface))) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s has no link local address, can't execute [InterfaceUp]", oi->interface->name); return 0; } /* Recompute cost */ ospf6_interface_recalculate_cost (oi); /* if already enabled, do nothing */ if (oi->state > OSPF6_INTERFACE_DOWN) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s already enabled", oi->interface->name); return 0; } /* If no area assigned, return */ if (oi->area == NULL) { zlog_debug ("%s: Not scheduleing Hello for %s as there is no area assigned yet", __func__, oi->interface->name); return 0; } /* Join AllSPFRouters */ if (ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP) < 0) { if (oi->sso_try_cnt++ < OSPF6_INTERFACE_SSO_RETRY_MAX) { zlog_info("Scheduling %s for sso retry, trial count: %d", oi->interface->name, oi->sso_try_cnt); thread_add_timer (master, interface_up, oi, OSPF6_INTERFACE_SSO_RETRY_INT); } return 0; } oi->sso_try_cnt = 0; /* Reset on success */ /* Update interface route */ ospf6_interface_connected_route_update (oi->interface); /* Schedule Hello */ if (! CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) oi->thread_send_hello = thread_add_event (master, ospf6_hello_send, oi, 0); /* decide next interface state */ if ((if_is_pointopoint (oi->interface)) || (oi->type == OSPF_IFTYPE_POINTOPOINT)) { 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_debug ("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_debug ("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_debug ("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 interface_down (struct thread *thread) { struct ospf6_interface *oi; struct listnode *node, *nnode; struct ospf6_neighbor *on; oi = (struct ospf6_interface *) THREAD_ARG (thread); assert (oi && oi->interface); if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface Event %s: [InterfaceDown]", oi->interface->name); /* Stop Hellos */ THREAD_OFF (oi->thread_send_hello); /* Leave AllSPFRouters */ if (oi->state > OSPF6_INTERFACE_DOWN) ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_LEAVE_GROUP); ospf6_interface_state_change (OSPF6_INTERFACE_DOWN, oi); for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) ospf6_neighbor_delete (on); list_delete_all_node (oi->neighbor_list); /* When interface state is reset, also reset information about * DR election, as it is no longer valid. */ oi->drouter = oi->prev_drouter = htonl(0); oi->bdrouter = oi->prev_bdrouter = htonl(0); return 0; } /* show specified interface structure */ static int ospf6_interface_show (struct vty *vty, struct interface *ifp) { struct ospf6_interface *oi; struct connected *c; struct prefix *p; struct listnode *i; char strbuf[64], drouter[32], bdrouter[32]; const char *updown[3] = {"down", "up", NULL}; const 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_operative (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 (ALL_LIST_ELEMENTS_RO (ifp->connected, i, c)) { 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->mtu6, VNL); vty_out (vty, " MTU mismatch detection: %s%s", oi->mtu_ignore ? "disabled" : "enabled", VNL); inet_ntop (AF_INET, &oi->area->area_id, strbuf, sizeof (strbuf)); vty_out (vty, " Area ID %s, Cost %u%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); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); 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; struct 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 (ALL_LIST_ELEMENTS_RO (iflist, i, ifp)) 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 "Display 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 "Display 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" ) { struct listnode *i; struct ospf6_interface *oi; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp)) { 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 "Display 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 "Display 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; unsigned int ifmtu, iobuflen; struct listnode *node, *nnode; 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->mtu6 != 0 && ifp->mtu6 < ifmtu) { vty_out (vty, "%s's ospf6 ifmtu cannot go beyond physical mtu (%d)%s", ifp->name, ifp->mtu6, 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 (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { 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; unsigned int iobuflen; struct listnode *node, *nnode; 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 (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { 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; unsigned long int lcost; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); lcost = strtol (argv[0], NULL, 10); if (lcost > UINT32_MAX) { vty_out (vty, "Cost %ld is out of range%s", lcost, VNL); return CMD_WARNING; } if (oi->cost == lcost) return CMD_SUCCESS; oi->cost = lcost; SET_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST); ospf6_interface_recalculate_cost(oi); return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_cost, no_ipv6_ospf6_cost_cmd, "no ipv6 ospf6 cost", NO_STR IP6_STR OSPF6_STR "Calculate interface cost from bandwidth\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_NOAUTOCOST); ospf6_interface_recalculate_cost(oi); return CMD_SUCCESS; } DEFUN (auto_cost_reference_bandwidth, 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 ospf6 *o = vty->index; struct ospf6_area *oa; struct ospf6_interface *oi; struct listnode *i, *j; u_int32_t refbw; 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) == o->ref_bandwidth) return CMD_SUCCESS; o->ref_bandwidth = refbw * 1000; for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) ospf6_interface_recalculate_cost (oi); return CMD_SUCCESS; } DEFUN (no_auto_cost_reference_bandwidth, no_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 ospf6 *o = vty->index; struct ospf6_area *oa; struct ospf6_interface *oi; struct listnode *i, *j; if (o->ref_bandwidth == OSPF6_REFERENCE_BANDWIDTH) return CMD_SUCCESS; o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) ospf6_interface_recalculate_cost (oi); 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 && (oi->state == OSPF6_INTERFACE_DROTHER || oi->state == OSPF6_INTERFACE_BDR || oi->state == OSPF6_INTERFACE_DR)) 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; struct listnode *node, *nnode; 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 (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { 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_mtu_ignore, ipv6_ospf6_mtu_ignore_cmd, "ipv6 ospf6 mtu-ignore", IP6_STR OSPF6_STR "Ignore MTU mismatch on 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); oi->mtu_ignore = 1; return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_mtu_ignore, no_ipv6_ospf6_mtu_ignore_cmd, "no ipv6 ospf6 mtu-ignore", NO_STR IP6_STR OSPF6_STR "Ignore MTU mismatch on 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); oi->mtu_ignore = 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); if (oi->area) { 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); if (oi->area) { 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 (ipv6_ospf6_network, ipv6_ospf6_network_cmd, "ipv6 ospf6 network (broadcast|point-to-point)", IP6_STR OSPF6_STR "Network Type\n" "Specify OSPFv6 broadcast network\n" "Specify OSPF6 point-to-point network\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 (strncmp (argv[0], "b", 1) == 0) { if (oi->type == OSPF_IFTYPE_BROADCAST) return CMD_SUCCESS; oi->type = OSPF_IFTYPE_BROADCAST; } else if (strncmp (argv[0], "point-to-p", 10) == 0) { if (oi->type == OSPF_IFTYPE_POINTOPOINT) { return CMD_SUCCESS; } oi->type = OSPF_IFTYPE_POINTOPOINT; } /* Reset the interface */ thread_add_event (master, interface_down, oi, 0); thread_add_event (master, interface_up, oi, 0); return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_network, no_ipv6_ospf6_network_cmd, "no ipv6 ospf6 network", NO_STR IP6_STR OSPF6_STR "Network Type\n" "Default to whatever interface type system specifies" ) { struct ospf6_interface *oi; struct interface *ifp; int type; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) { return CMD_SUCCESS; } type = ospf6_default_iftype (ifp); if (oi->type == type) { return CMD_SUCCESS; } oi->type = type; /* Reset the interface */ thread_add_event (master, interface_down, oi, 0); thread_add_event (master, interface_up, oi, 0); return CMD_SUCCESS; } static int config_write_ospf6_interface (struct vty *vty) { struct listnode *i; struct ospf6_interface *oi; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp)) { 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->mtu6 != oi->ifmtu) vty_out (vty, " ipv6 ospf6 ifmtu %d%s", oi->ifmtu, VNL); if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST)) vty_out (vty, " ipv6 ospf6 cost %d%s", oi->cost, VNL); if (oi->hello_interval != OSPF6_INTERFACE_HELLO_INTERVAL) vty_out (vty, " ipv6 ospf6 hello-interval %d%s", oi->hello_interval, VNL); if (oi->dead_interval != OSPF6_INTERFACE_DEAD_INTERVAL) vty_out (vty, " ipv6 ospf6 dead-interval %d%s", oi->dead_interval, VNL); if (oi->rxmt_interval != OSPF6_INTERFACE_RXMT_INTERVAL) vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s", oi->rxmt_interval, VNL); if (oi->priority != OSPF6_INTERFACE_PRIORITY) vty_out (vty, " ipv6 ospf6 priority %d%s", oi->priority, VNL); if (oi->transdelay != OSPF6_INTERFACE_TRANSDELAY) vty_out (vty, " ipv6 ospf6 transmit-delay %d%s", oi->transdelay, VNL); if (oi->instance_id != OSPF6_INTERFACE_INSTANCE_ID) 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); if (oi->mtu_ignore) vty_out (vty, " ipv6 ospf6 mtu-ignore%s", VNL); if (oi->type == OSPF_IFTYPE_POINTOPOINT) vty_out (vty, " ipv6 ospf6 network point-to-point%s", VNL); else if (oi->type == OSPF_IFTYPE_BROADCAST) vty_out (vty, " ipv6 ospf6 network broadcast%s", VNL); vty_out (vty, "!%s", VNL); } return 0; } static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */ }; void ospf6_interface_init (void) { /* 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 (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, &no_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_mtu_ignore_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_mtu_ignore_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_network_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_network_cmd); /* reference bandwidth commands */ install_element (OSPF6_NODE, &auto_cost_reference_bandwidth_cmd); install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd); } /* Clear the specified interface structure */ static void ospf6_interface_clear (struct vty *vty, struct interface *ifp) { struct ospf6_interface *oi; if (!if_is_operative (ifp)) return; if (ifp->info == NULL) return; oi = (struct ospf6_interface *) ifp->info; if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s: clear by reset", ifp->name); /* Reset the interface */ thread_add_event (master, interface_down, oi, 0); thread_add_event (master, interface_up, oi, 0); } /* Clear interface */ DEFUN (clear_ipv6_ospf6_interface, clear_ipv6_ospf6_interface_cmd, "clear ipv6 ospf6 interface [IFNAME]", CLEAR_STR IP6_STR OSPF6_STR INTERFACE_STR IFNAME_STR ) { struct interface *ifp; struct listnode *node; if (argc == 0) /* Clear all the ospfv3 interfaces. */ { for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ospf6_interface_clear (vty, ifp); } else /* Interface name is specified. */ { if ((ifp = if_lookup_by_name (argv[0])) == NULL) { vty_out (vty, "No such Interface: %s%s", argv[0], VNL); return CMD_WARNING; } ospf6_interface_clear (vty, ifp); } return CMD_SUCCESS; } void install_element_ospf6_clear_interface (void) { install_element (ENABLE_NODE, &clear_ipv6_ospf6_interface_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 (void) { 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); } quagga-1.2.4/ospf6d/ospf6_interface.h000066400000000000000000000115251325323223500174160ustar00rootroot00000000000000/* * 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 */ struct 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; /* Network Type */ u_char type; /* Router Priority */ u_char priority; /* Time Interval */ u_int16_t hello_interval; u_int16_t dead_interval; u_int32_t rxmt_interval; u_int32_t state_change; /* Cost */ u_int32_t cost; /* I/F MTU */ u_int32_t ifmtu; /* Interface State */ u_char state; /* Interface socket setting trial counter, resets on success */ u_char sso_try_cnt; /* OSPF6 Interface flag */ char flag; /* MTU mismatch check */ u_char mtu_ignore; /* 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 const char *ospf6_interface_state_str[]; /* flags */ #define OSPF6_INTERFACE_DISABLE 0x01 #define OSPF6_INTERFACE_PASSIVE 0x02 #define OSPF6_INTERFACE_NOAUTOCOST 0x04 /* default values */ #define OSPF6_INTERFACE_HELLO_INTERVAL 10 #define OSPF6_INTERFACE_DEAD_INTERVAL 40 #define OSPF6_INTERFACE_RXMT_INTERVAL 5 #define OSPF6_INTERFACE_COST 1 #define OSPF6_INTERFACE_PRIORITY 1 #define OSPF6_INTERFACE_TRANSDELAY 1 #define OSPF6_INTERFACE_INSTANCE_ID 0 #define OSPF6_INTERFACE_BANDWIDTH 10000 /* Kbps */ #define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */ #define OSPF6_INTERFACE_SSO_RETRY_INT 1 #define OSPF6_INTERFACE_SSO_RETRY_MAX 5 /* Function Prototypes */ extern struct ospf6_interface *ospf6_interface_lookup_by_ifindex (int); extern struct ospf6_interface *ospf6_interface_create (struct interface *); extern void ospf6_interface_delete (struct ospf6_interface *); extern void ospf6_interface_enable (struct ospf6_interface *); extern void ospf6_interface_disable (struct ospf6_interface *); extern void ospf6_interface_if_add (struct interface *); extern void ospf6_interface_state_update (struct interface *); extern void ospf6_interface_connected_route_update (struct interface *); /* interface event */ extern int interface_up (struct thread *); extern int interface_down (struct thread *); extern int wait_timer (struct thread *); extern int backup_seen (struct thread *); extern int neighbor_change (struct thread *); extern void ospf6_interface_init (void); extern void install_element_ospf6_clear_interface (void); extern int config_write_ospf6_debug_interface (struct vty *vty); extern void install_element_ospf6_debug_interface (void); #endif /* OSPF6_INTERFACE_H */ quagga-1.2.4/ospf6d/ospf6_intra.c000066400000000000000000001551131325323223500165700ustar00rootroot00000000000000/* * 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" #include "ospf6_spf.h" unsigned char conf_debug_ospf6_brouter = 0; u_int32_t conf_debug_ospf6_brouter_specific_router_id; u_int32_t conf_debug_ospf6_brouter_specific_area_id; /******************************/ /* RFC2740 3.4.3.1 Router-LSA */ /******************************/ static char * ospf6_router_lsa_get_nbr_id (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_router_lsa *router_lsa; struct ospf6_router_lsdesc *lsdesc; char *start, *end; char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN]; if (lsa) { router_lsa = (struct ospf6_router_lsa *) ((char *) lsa->header + sizeof (struct ospf6_lsa_header)); start = (char *) router_lsa + sizeof (struct ospf6_router_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); lsdesc = (struct ospf6_router_lsdesc *) (start + pos*(sizeof (struct ospf6_router_lsdesc))); if ((char *)lsdesc < end) { if (buf && (buflen > INET_ADDRSTRLEN*2)) { inet_ntop (AF_INET, &lsdesc->neighbor_interface_id, buf1, sizeof(buf1)); inet_ntop (AF_INET, &lsdesc->neighbor_router_id, buf2, sizeof(buf2)); sprintf (buf, "%s/%s", buf2, buf1); } } else return NULL; } return buf; } static 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_is_stub_router (struct ospf6_lsa *lsa) { struct ospf6_router_lsa *rtr_lsa; if (lsa != NULL && OSPF6_LSA_IS_TYPE (ROUTER, lsa)) { rtr_lsa = (struct ospf6_router_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_R)) { return (OSPF6_IS_STUB_ROUTER); } else if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_V6)) { return (OSPF6_IS_STUB_ROUTER_V6); } } return (OSPF6_NOT_STUB_ROUTER); } 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; struct listnode *node, *nnode; struct listnode *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_debug ("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 (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) { /* 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 (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) 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) && ((size_t)((char *)lsdesc - buffer) + sizeof (struct ospf6_router_lsdesc) > 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_debug ("Size limit setting for Router-LSA too short"); return 0; } link_state_id ++; } /* Point-to-Point interfaces */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) { for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) { 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 */ else if (oi->type == OSPF_IFTYPE_BROADCAST) { /* 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++; } else { assert (0); /* Unknown interface type */ } /* Virtual links */ /* xxx */ /* Point-to-Multipoint interfaces */ /* xxx */ } /* 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 ++; /* 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 */ /*******************************/ static char * ospf6_network_lsa_get_ar_id (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { char *start, *end, *current; struct ospf6_network_lsa *network_lsa; struct ospf6_network_lsdesc *lsdesc; if (lsa) { network_lsa = (struct ospf6_network_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); start = (char *) network_lsa + sizeof (struct ospf6_network_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); current = start + pos*(sizeof (struct ospf6_network_lsdesc)); if ((current + sizeof(struct ospf6_network_lsdesc)) <= end) { lsdesc = (struct ospf6_network_lsdesc *)current; if (buf) inet_ntop (AF_INET, &lsdesc->router_id, buf, buflen); } else return NULL; } return (buf); } static 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; struct 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_debug ("Originate Network-LSA for Interface %s", oi->interface->name); /* If none of neighbor is adjacent to us */ count = 0; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on)) if (on->state == OSPF6_NEIGHBOR_FULL) count++; if (count == 0) { if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK)) zlog_debug ("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 (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on)) { 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 */ /****************************/ static char * ospf6_link_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { char *start, *end, *current; struct ospf6_link_lsa *link_lsa; struct in6_addr in6; struct ospf6_prefix *prefix; int cnt = 0, prefixnum; if (lsa) { link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); if (pos == 0) { inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, buflen); return (buf); } prefixnum = ntohl (link_lsa->prefix_num); if (pos > prefixnum) return (NULL); start = (char *) link_lsa + sizeof (struct ospf6_link_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); current = start; do { prefix = (struct ospf6_prefix *) current; if (prefix->prefix_length == 0 || current + OSPF6_PREFIX_SIZE (prefix) > end) { return (NULL); } if (cnt < pos) { current = start + pos*OSPF6_PREFIX_SIZE(prefix); cnt++; } else { memset (&in6, 0, sizeof (in6)); memcpy (&in6, OSPF6_PREFIX_BODY (prefix), OSPF6_PREFIX_SPACE (prefix->prefix_length)); inet_ntop (AF_INET6, &in6, buf, buflen); return (buf); } } while (current <= end); } return (NULL); } static 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; const 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_debug ("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_debug ("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 */ /*****************************************/ static char * ospf6_intra_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { char *start, *end, *current; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct in6_addr in6; int prefixnum, cnt = 0; struct ospf6_prefix *prefix; if (lsa) { intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); prefixnum = ntohs (intra_prefix_lsa->prefix_num); if (pos > prefixnum) return (NULL); start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); current = start; do { prefix = (struct ospf6_prefix *) current; if (prefix->prefix_length == 0 || current + OSPF6_PREFIX_SIZE (prefix) > end) { return NULL; } if (cnt < pos) { current = start + pos*OSPF6_PREFIX_SIZE(prefix); cnt++; } else { memset (&in6, 0, sizeof (in6)); memcpy (&in6, OSPF6_PREFIX_BODY (prefix), OSPF6_PREFIX_SPACE (prefix->prefix_length)); inet_ntop (AF_INET6, &in6, buf, buflen); sprintf(&buf[strlen(buf)], "/%d", prefix->prefix_length); return (buf); } } while (current <= end); } return (buf); } static 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]; const 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; struct 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_debug ("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 (0, 0); for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi)) { if (oi->state == OSPF6_INTERFACE_DOWN) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" Interface %s is down, ignore", oi->interface->name); continue; } full_count = 0; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) 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_debug (" Interface %s is not stub, ignore", oi->interface->name); continue; } if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" 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_debug (" 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_debug ("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; struct 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_debug ("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_debug (" Interface is not DR"); if (old) ospf6_lsa_purge (old); return 0; } full_count = 0; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on)) if (on->state == OSPF6_NEIGHBOR_FULL) full_count++; if (full_count == 0) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" Interface is stub"); if (old) ospf6_lsa_purge (old); return 0; } /* connected prefix to advertise */ route_advertise = ospf6_route_table_create (0, 0); 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_debug (" 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_debug (" 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_debug (" include %s", buf); } ospf6_route_add (route, route_advertise); prefix_num--; } if (current != end && IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug ("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_debug ("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]; struct interface *ifp; int direct_connect = 0; if (OSPF6_LSA_IS_MAXAGE (lsa)) return; if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("%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_debug ("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_debug ("LS entry does not exist: %s", buf); } return; } if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id) { /* the intra-prefix are directly connected */ direct_connect = 1; } 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; /* Appendix A.4.1.1 */ if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU)) { if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op), buf, sizeof (buf)); zlog_debug ("%s: Skipping Prefix %s has NU option set", __func__, buf); } continue; } 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); if (direct_connect) { ifp = if_lookup_prefix(&route->prefix); if (ifp) route->nexthop[0].ifindex = ifp->ifindex; } else { for (i = 0; i < OSPF6_MULTI_PATH_LIMIT && ospf6_nexthop_is_set (&ls_entry->nexthop[i]); 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_debug (" add %s", buf); } ospf6_route_add (route, oa->route_table); prefix_num--; } if (current != end && IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("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, *nroute; int prefix_num; struct ospf6_prefix *op; char *start, *current, *end; char buf[64]; if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("%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 = nroute) { nroute = 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_debug ("remove %s", buf); } ospf6_route_remove (route, oa->route_table); } if (route) ospf6_route_unlock (route); } if (current != end && IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("Trailing garbage ignored"); } void ospf6_intra_route_calculation (struct ospf6_area *oa) { struct ospf6_route *route, *nroute; 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_debug ("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 = nroute) { nroute = 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_debug ("Re-examin intra-routes for area %s: Done", oa->name); } static void ospf6_brouter_debug_print (struct ospf6_route *brouter) { u_int32_t brouter_id; char brouter_name[16]; char area_name[16]; char destination[64]; char installed[16], changed[16]; struct timeval now, res; char id[16], adv_router[16]; char capa[16], options[16]; brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); inet_ntop (AF_INET, &brouter->path.area_id, area_name, sizeof (area_name)); ospf6_linkstate_prefix2str (&brouter->prefix, destination, sizeof (destination)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &brouter->installed, &res); timerstring (&res, installed, sizeof (installed)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &brouter->changed, &res); timerstring (&res, changed, sizeof (changed)); inet_ntop (AF_INET, &brouter->path.origin.id, id, sizeof (id)); inet_ntop (AF_INET, &brouter->path.origin.adv_router, adv_router, sizeof (adv_router)); ospf6_options_printbuf (brouter->path.options, options, sizeof (options)); ospf6_capability_printbuf (brouter->path.router_bits, capa, sizeof (capa)); zlog_info ("Brouter: %s via area %s", brouter_name, area_name); zlog_info (" memory: prev: %p this: %p next: %p parent rnode: %p", (void *)brouter->prev, (void *)brouter, (void *)brouter->next, (void *)brouter->rnode); zlog_info (" type: %d prefix: %s installed: %s changed: %s", brouter->type, destination, installed, changed); zlog_info (" lock: %d flags: %s%s%s%s", brouter->lock, (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_BEST) ? "B" : "-"), (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD) ? "A" : "-"), (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"), (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-")); zlog_info (" path type: %s ls-origin %s id: %s adv-router %s", OSPF6_PATH_TYPE_NAME (brouter->path.type), ospf6_lstype_name (brouter->path.origin.type), id, adv_router); zlog_info (" options: %s router-bits: %s metric-type: %d metric: %d/%d", options, capa, brouter->path.metric_type, brouter->path.cost, brouter->path.cost_e2); } void ospf6_intra_brouter_calculation (struct ospf6_area *oa) { struct ospf6_route *brouter, *nbrouter, *copy; void (*hook_add) (struct ospf6_route *) = NULL; void (*hook_remove) (struct ospf6_route *) = NULL; u_int32_t brouter_id; char brouter_name[16]; if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) 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 (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter; brouter = ospf6_route_next (brouter)) { brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); if (brouter->path.area_id != oa->area_id) continue; brouter->flag = OSPF6_ROUTE_REMOVE; if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_ROUTE (MEMORY)) { zlog_info ("%p: mark as removing: area %s brouter %s", (void *)brouter, oa->name, brouter_name); ospf6_brouter_debug_print (brouter); } } for (brouter = ospf6_route_head (oa->spf_table); brouter; brouter = ospf6_route_next (brouter)) { brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); if (brouter->type != OSPF6_DEST_TYPE_LINKSTATE) continue; if (ospf6_linkstate_prefix_id (&brouter->prefix) != htonl (0)) continue; if (! CHECK_FLAG (brouter->path.router_bits, OSPF6_ROUTER_BIT_E) && ! CHECK_FLAG (brouter->path.router_bits, OSPF6_ROUTER_BIT_B)) continue; if (! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_V6) || ! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_R)) continue; copy = ospf6_route_copy (brouter); 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_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_ROUTE (MEMORY)) { zlog_info ("%p: transfer: area %s brouter %s", (void *)brouter, oa->name, brouter_name); ospf6_brouter_debug_print (brouter); } } oa->ospf6->brouter_table->hook_add = hook_add; oa->ospf6->brouter_table->hook_remove = hook_remove; for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter; brouter = nbrouter) { nbrouter = ospf6_route_next (brouter); brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); if (brouter->path.area_id != oa->area_id) continue; if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_WAS_REMOVED)) continue; if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE) && CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD)) { UNSET_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE); UNSET_FLAG (brouter->flag, OSPF6_ROUTE_ADD); } if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE)) { if (IS_OSPF6_DEBUG_BROUTER || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("brouter %s disappears via area %s", brouter_name, oa->name); ospf6_route_remove (brouter, oa->ospf6->brouter_table); } else if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD) || CHECK_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE)) { if (IS_OSPF6_DEBUG_BROUTER || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("brouter %s appears via area %s", brouter_name, oa->name); /* newly added */ if (hook_add) (*hook_add) (brouter); } else { if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("brouter %s still exists via area %s", brouter_name, oa->name); } brouter->flag = 0; } if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("border-router calculation for area %s: done", oa->name); } struct ospf6_lsa_handler router_handler = { OSPF6_LSTYPE_ROUTER, "Router", "Rtr", ospf6_router_lsa_show, ospf6_router_lsa_get_nbr_id }; struct ospf6_lsa_handler network_handler = { OSPF6_LSTYPE_NETWORK, "Network", "Net", ospf6_network_lsa_show, ospf6_network_lsa_get_ar_id }; struct ospf6_lsa_handler link_handler = { OSPF6_LSTYPE_LINK, "Link", "Lnk", ospf6_link_lsa_show, ospf6_link_lsa_get_prefix_str }; struct ospf6_lsa_handler intra_prefix_handler = { OSPF6_LSTYPE_INTRA_PREFIX, "Intra-Prefix", "INP", ospf6_intra_prefix_lsa_show, ospf6_intra_prefix_lsa_get_prefix_str }; void ospf6_intra_init (void) { 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); } DEFUN (debug_ospf6_brouter, debug_ospf6_brouter_cmd, "debug ospf6 border-routers", DEBUG_STR OSPF6_STR "Debug border router\n" ) { OSPF6_DEBUG_BROUTER_ON (); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_brouter, no_debug_ospf6_brouter_cmd, "no debug ospf6 border-routers", NO_STR DEBUG_STR OSPF6_STR "Debug border router\n" ) { OSPF6_DEBUG_BROUTER_OFF (); return CMD_SUCCESS; } DEFUN (debug_ospf6_brouter_router, debug_ospf6_brouter_router_cmd, "debug ospf6 border-routers router-id A.B.C.D", DEBUG_STR OSPF6_STR "Debug border router\n" "Debug specific border router\n" "Specify border-router's router-id\n" ) { u_int32_t router_id; inet_pton (AF_INET, argv[0], &router_id); OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON (router_id); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_brouter_router, no_debug_ospf6_brouter_router_cmd, "no debug ospf6 border-routers router-id", NO_STR DEBUG_STR OSPF6_STR "Debug border router\n" "Debug specific border router\n" ) { OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF (); return CMD_SUCCESS; } DEFUN (debug_ospf6_brouter_area, debug_ospf6_brouter_area_cmd, "debug ospf6 border-routers area-id A.B.C.D", DEBUG_STR OSPF6_STR "Debug border router\n" "Debug border routers in specific Area\n" "Specify Area-ID\n" ) { u_int32_t area_id; inet_pton (AF_INET, argv[0], &area_id); OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON (area_id); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_brouter_area, no_debug_ospf6_brouter_area_cmd, "no debug ospf6 border-routers area-id", NO_STR DEBUG_STR OSPF6_STR "Debug border router\n" "Debug border routers in specific Area\n" ) { OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF (); return CMD_SUCCESS; } int config_write_ospf6_debug_brouter (struct vty *vty) { char buf[16]; if (IS_OSPF6_DEBUG_BROUTER) vty_out (vty, "debug ospf6 border-routers%s", VNL); if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER) { inet_ntop (AF_INET, &conf_debug_ospf6_brouter_specific_router_id, buf, sizeof (buf)); vty_out (vty, "debug ospf6 border-routers router-id %s%s", buf, VNL); } if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA) { inet_ntop (AF_INET, &conf_debug_ospf6_brouter_specific_area_id, buf, sizeof (buf)); vty_out (vty, "debug ospf6 border-routers area-id %s%s", buf, VNL); } return 0; } void install_element_ospf6_debug_brouter (void) { install_element (ENABLE_NODE, &debug_ospf6_brouter_cmd); install_element (ENABLE_NODE, &debug_ospf6_brouter_router_cmd); install_element (ENABLE_NODE, &debug_ospf6_brouter_area_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_router_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_area_cmd); install_element (CONFIG_NODE, &debug_ospf6_brouter_cmd); install_element (CONFIG_NODE, &debug_ospf6_brouter_router_cmd); install_element (CONFIG_NODE, &debug_ospf6_brouter_area_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_router_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_area_cmd); } quagga-1.2.4/ospf6d/ospf6_intra.h000066400000000000000000000213341325323223500165720ustar00rootroot00000000000000/* * 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 /* Debug option */ extern unsigned char conf_debug_ospf6_brouter; extern u_int32_t conf_debug_ospf6_brouter_specific_router_id; extern u_int32_t conf_debug_ospf6_brouter_specific_area_id; #define OSPF6_DEBUG_BROUTER_SUMMARY 0x01 #define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER 0x02 #define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA 0x04 #define OSPF6_DEBUG_BROUTER_ON() \ (conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SUMMARY) #define OSPF6_DEBUG_BROUTER_OFF() \ (conf_debug_ospf6_brouter &= ~OSPF6_DEBUG_BROUTER_SUMMARY) #define IS_OSPF6_DEBUG_BROUTER \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SUMMARY) #define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON(router_id) \ do { \ conf_debug_ospf6_brouter_specific_router_id = (router_id); \ conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER; \ } while (0) #define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF() \ do { \ conf_debug_ospf6_brouter_specific_router_id = 0; \ conf_debug_ospf6_brouter &= ~OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER; \ } while (0) #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER) #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(router_id) \ (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER && \ conf_debug_ospf6_brouter_specific_router_id == (router_id)) #define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON(area_id) \ do { \ conf_debug_ospf6_brouter_specific_area_id = (area_id); \ conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SPECIFIC_AREA; \ } while (0) #define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF() \ do { \ conf_debug_ospf6_brouter_specific_area_id = 0; \ conf_debug_ospf6_brouter &= ~OSPF6_DEBUG_BROUTER_SPECIFIC_AREA; \ } while (0) #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SPECIFIC_AREA) #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(area_id) \ (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA && \ conf_debug_ospf6_brouter_specific_area_id == (area_id)) /* Router-LSA */ #define OSPF6_ROUTER_LSA_MIN_SIZE 4U struct ospf6_router_lsa { u_char bits; u_char options[3]; /* followed by ospf6_router_lsdesc(s) */ }; /* Link State Description in Router-LSA */ #define OSPF6_ROUTER_LSDESC_FIX_SIZE 16U 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 enum stub_router_mode { OSPF6_NOT_STUB_ROUTER, OSPF6_IS_STUB_ROUTER, OSPF6_IS_STUB_ROUTER_V6, }; #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 */ #define OSPF6_NETWORK_LSA_MIN_SIZE 4U struct ospf6_network_lsa { u_char reserved; u_char options[3]; /* followed by ospf6_netowrk_lsd(s) */ }; /* Link State Description in Router-LSA */ #define OSPF6_NETWORK_LSDESC_FIX_SIZE 4U 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 */ #define OSPF6_LINK_LSA_MIN_SIZE 24U /* w/o 1st IPv6 prefix */ 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 */ #define OSPF6_INTRA_PREFIX_LSA_MIN_SIZE 12U /* w/o 1st IPv6 prefix */ 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 \ && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \ (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 \ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (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 \ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (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 \ && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \ (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 \ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (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 */ extern 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); extern char *ospf6_network_lsdesc_lookup (u_int32_t router_id, struct ospf6_lsa *lsa); extern int ospf6_router_is_stub_router (struct ospf6_lsa *lsa); extern int ospf6_router_lsa_originate (struct thread *); extern int ospf6_network_lsa_originate (struct thread *); extern int ospf6_link_lsa_originate (struct thread *); extern int ospf6_intra_prefix_lsa_originate_transit (struct thread *); extern int ospf6_intra_prefix_lsa_originate_stub (struct thread *); extern void ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa); extern void ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa); extern void ospf6_intra_route_calculation (struct ospf6_area *oa); extern void ospf6_intra_brouter_calculation (struct ospf6_area *oa); extern void ospf6_intra_init (void); extern int config_write_ospf6_debug_brouter (struct vty *vty); extern void install_element_ospf6_debug_brouter (void); #endif /* OSPF6_LSA_H */ quagga-1.2.4/ospf6d/ospf6_lsa.c000066400000000000000000000646621325323223500162420ustar00rootroot00000000000000/* * 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 "checksum.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; static 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", "Unk", ospf6_unknown_lsa_show, NULL, 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; unsigned int index = ntohs (type) & OSPF6_LSTYPE_FCODE_MASK; if (index >= vector_active (ospf6_lsa_handler_vector)) handler = &unknown_handler; else handler = vector_slot (ospf6_lsa_handler_vector, index); if (handler == NULL) handler = &unknown_handler; return handler; } const 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; } const char * ospf6_lstype_short_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->short_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) == OSPF_LSA_MAXAGE && ntohs (lsa2->header->age) != OSPF_LSA_MAXAGE) return 1; if (ntohs (lsa1->header->age) != OSPF_LSA_MAXAGE && ntohs (lsa2->header->age) == OSPF_LSA_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; /* Going beyond LSA headers to compare the payload only makes sense, when both LSAs aren't header-only. */ if (CHECK_FLAG (lsa1->flag, OSPF6_LSA_HEADERONLY) != CHECK_FLAG (lsa2->flag, OSPF6_LSA_HEADERONLY)) { zlog_warn ("%s: only one of two (%s, %s) LSAs compared is header-only", __func__, lsa1->name, lsa2->name); return 1; } if (CHECK_FLAG (lsa1->flag, OSPF6_LSA_HEADERONLY)) return 0; length = OSPF6_LSA_SIZE (lsa1->header) - sizeof (struct ospf6_lsa_header); /* Once upper layer verifies LSAs received, length underrun should become a warning. */ if (length <= 0) return 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 (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0) zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s", safe_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 (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0) zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s", safe_strerror (errno)); if (ntohs (lsa->header->age) >= OSPF_LSA_MAXAGE) { /* ospf6_lsa_premature_aging () sets age to MAXAGE; when using relative time, we cannot compare against lsa birth time, so we catch this special case here. */ lsa->header->age = htons (OSPF_LSA_MAXAGE); return OSPF_LSA_MAXAGE; } /* calculate age */ ulage = now.tv_sec - lsa->birth.tv_sec; /* if over MAXAGE, set to it */ age = (ulage > OSPF_LSA_MAXAGE ? OSPF_LSA_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 > OSPF_LSA_MAXAGE) age = OSPF_LSA_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_debug ("LSA: Premature aging: %s", lsa->name); THREAD_OFF (lsa->expire); THREAD_OFF (lsa->refresh); /* * We clear the LSA from the neighbor retx lists now because it * will not get deleted later. Essentially, changing the age to * MaxAge will prevent this LSA from being matched with its * existing entries in the retx list thereby causing those entries * to be silently replaced with its MaxAged version, but with ever * increasing retx count causing this LSA to remain forever and * for the MaxAge remover thread to be called forever too. * * The reason the previous entry silently disappears is that when * entry is added to a neighbor's retx list, it replaces the existing * entry. But since the ospf6_lsdb_add() routine is generic and not aware * of the special semantics of retx count, the retx count is not * decremented when its replaced. Attempting to add the incr and decr * retx count routines as the hook_add and hook_remove for the retx lists * have a problem because the hook_remove routine is called for MaxAge * entries (as will be the case in a traditional LSDB, unlike in this case * where an LSDB is used as an efficient tree structure to store all kinds * of data) that are added instead of calling the hook_add routine. */ ospf6_flood_clear (lsa); lsa->header->age = htons (OSPF_LSA_MAXAGE); 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) { int32_t 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 = (int32_t) ntohl (a->header->seqnum); seqnumb = (int32_t) ntohl (b->header->seqnum); /* compare by sequence number */ if (seqnuma > seqnumb) return -1; 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 == OSPF_LSA_MAXAGE && ageb != OSPF_LSA_MAXAGE) return -1; else if (agea != OSPF_LSA_MAXAGE && ageb == OSPF_LSA_MAXAGE) return 1; /* Age check */ if (agea > ageb && agea - ageb >= OSPF_LSA_MAXAGE_DIFF) return 1; else if (agea < ageb && ageb - agea >= OSPF_LSA_MAXAGE_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_debug (" [%s Id:%s Adv:%s]", ospf6_lstype_name (header->type), id, adv_router); zlog_debug (" 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, "%-4s %-15s%-15s%4s %8s %30s%s", "Type", "LSId", "AdvRouter", "Age", "SeqNum", "Payload", VNL); } void ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[16], id[16]; int type; struct ospf6_lsa_handler *handler; char buf[64], tmpbuf[80]; int cnt = 0; 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)); type = ntohs(lsa->header->type); handler = ospf6_get_lsa_handler (lsa->header->type); if ((type == OSPF6_LSTYPE_INTER_PREFIX) || (type == OSPF6_LSTYPE_INTER_ROUTER) || (type == OSPF6_LSTYPE_AS_EXTERNAL)) { vty_out (vty, "%-4s %-15s%-15s%4hu %8lx %30s%s", ospf6_lstype_short_name (lsa->header->type), id, adv_router, ospf6_lsa_age_current (lsa), (u_long) ntohl (lsa->header->seqnum), handler->get_prefix_str(lsa, buf, sizeof(buf), 0), VNL); } else if (type != OSPF6_LSTYPE_UNKNOWN) { sprintf (tmpbuf, "%-4s %-15s%-15s%4hu %8lx", ospf6_lstype_short_name (lsa->header->type), id, adv_router, ospf6_lsa_age_current (lsa), (u_long) ntohl (lsa->header->seqnum)); while (handler->get_prefix_str(lsa, buf, sizeof(buf), cnt) != NULL) { vty_out (vty, "%s %30s%s", tmpbuf, buf, VNL); cnt++; } } else { vty_out (vty, "%-4s %-15s%-15s%4hu %8lx%s", ospf6_lstype_short_name (lsa->header->type), id, adv_router, ospf6_lsa_age_current (lsa), (u_long) ntohl (lsa->header->seqnum), 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, "Flag: %x %s", lsa->flag, VNL); vty_out (vty, "Lock: %d %s", lsa->lock, VNL); vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL); vty_out (vty, "Threads: Expire: 0x%p, Refresh: 0x%p %s", (void *)lsa->expire, (void *)lsa->refresh, 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; struct timeval now, res; char duration[16]; 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)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &lsa->installed, &res); timerstring (&res, duration, sizeof (duration)); 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, "Duration: %s%s", duration, 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 *) XCALLOC (MTYPE_OSPF6_LSA, 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 *) XCALLOC (MTYPE_OSPF6_LSA, 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; copy->rn = NULL; 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_debug ("LSA Expire:"); ospf6_lsa_header_print (lsa); } if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) return 0; /* dbexchange will do something ... */ /* reinstall lsa */ ospf6_install_lsa (lsa); /* reflood lsa */ ospf6_flood (NULL, 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_debug ("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, OSPF_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_debug ("LSA Refresh:"); ospf6_lsa_header_print (new); } ospf6_install_lsa (new); ospf6_flood (NULL, new); return 0; } /* Fletcher Checksum -- Refer to RFC1008. */ /* All the offsets are zero-based. The offsets in the RFC1008 are one-based. */ unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header) { u_char *buffer = (u_char *) &lsa_header->type; int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ /* Skip the AGE field */ u_int16_t len = ntohs(lsa_header->length) - type_offset; /* Checksum offset starts from "type" field, not the beginning of the lsa_header struct. The offset is 14, rather than 16. */ int checksum_offset = (u_char *) &lsa_header->checksum - buffer; return (unsigned short)fletcher_checksum(buffer, len, checksum_offset); } int ospf6_lsa_checksum_valid (struct ospf6_lsa_header *lsa_header) { u_char *buffer = (u_char *) &lsa_header->type; int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ /* Skip the AGE field */ u_int16_t len = ntohs(lsa_header->length) - type_offset; return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); } void ospf6_lsa_init (void) { ospf6_lsa_handler_vector = vector_init (0); ospf6_install_lsa_handler (&unknown_handler); } void ospf6_lsa_terminate (void) { vector_free (ospf6_lsa_handler_vector); } static char * ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) { static char buf[64]; unsigned int i; unsigned int size = strlen (h->name); if (!strcmp(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 ((unsigned char)h->name[i])) buf[i] = tolower ((unsigned char)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 (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) { unsigned int i; struct ospf6_lsa_handler *handler = NULL; assert (argc); for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0) break; if (! strcasecmp (argv[0], handler->name)) break; handler = NULL; } 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], "examine")) 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; } ALIAS (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_detail_cmd, "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) DEFUN (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_cmd, "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", NO_STR DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) { u_int i; struct ospf6_lsa_handler *handler = NULL; assert (argc); for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0) 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], "examine")) 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); return CMD_SUCCESS; } ALIAS (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_detail_cmd, "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)", NO_STR DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) void install_element_ospf6_debug_lsa (void) { install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd); install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_detail_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_detail_cmd); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_detail_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_detail_cmd); } int config_write_ospf6_debug_lsa (struct vty *vty) { u_int i; struct ospf6_lsa_handler *handler; for (i = 0; i < vector_active (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 examine%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; } quagga-1.2.4/ospf6d/ospf6_lsa.h000066400000000000000000000237721325323223500162440ustar00rootroot00000000000000/* * 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 */ #define OSPF6_LSA_HEADER_SIZE 20U 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) == OSPF_LSA_MAXAGE) #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2) #define OSPF6_LSA_IS_SEQWRAP(L) ((L)->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER + 1)) struct ospf6_lsa { char name[64]; /* dump string */ struct route_node *rn; 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 #define OSPF6_LSA_SEQWRAPPED 0x20 struct ospf6_lsa_handler { u_int16_t type; /* host byte order */ const char *name; const char *short_name; int (*show) (struct vty *, struct ospf6_lsa *); char *(*get_prefix_str) (struct ospf6_lsa *, char *buf, int buflen, int pos); 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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("Filter out V4Mapped: %s", buf); \ continue; \ } /* Function Prototypes */ extern const char *ospf6_lstype_name (u_int16_t type); extern const char *ospf6_lstype_short_name (u_int16_t type); extern u_char ospf6_lstype_debug (u_int16_t type); extern int ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); extern int ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); extern u_int16_t ospf6_lsa_age_current (struct ospf6_lsa *); extern void ospf6_lsa_age_update_to_send (struct ospf6_lsa *, u_int32_t); extern void ospf6_lsa_premature_aging (struct ospf6_lsa *); extern int ospf6_lsa_compare (struct ospf6_lsa *, struct ospf6_lsa *); extern char *ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size); extern void ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header); extern void ospf6_lsa_header_print (struct ospf6_lsa *lsa); extern void ospf6_lsa_show_summary_header (struct vty *vty); extern void ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa); extern void ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa); extern void ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa); extern void ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsa_create (struct ospf6_lsa_header *header); extern struct ospf6_lsa *ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header); extern void ospf6_lsa_delete (struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsa_copy (struct ospf6_lsa *); extern void ospf6_lsa_lock (struct ospf6_lsa *); extern void ospf6_lsa_unlock (struct ospf6_lsa *); extern int ospf6_lsa_expire (struct thread *); extern int ospf6_lsa_refresh (struct thread *); extern unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *); extern int ospf6_lsa_checksum_valid (struct ospf6_lsa_header *); extern int ospf6_lsa_prohibited_duration (u_int16_t type, u_int32_t id, u_int32_t adv_router, void *scope); extern void ospf6_install_lsa_handler (struct ospf6_lsa_handler *handler); extern struct ospf6_lsa_handler *ospf6_get_lsa_handler (u_int16_t type); extern void ospf6_lsa_init (void); extern void ospf6_lsa_terminate (void); extern int config_write_ospf6_debug_lsa (struct vty *vty); extern void install_element_ospf6_debug_lsa (void); #endif /* OSPF6_LSA_H */ quagga-1.2.4/ospf6d/ospf6_lsdb.c000066400000000000000000000336231325323223500164000ustar00rootroot00000000000000/* * 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) { if (lsdb != NULL) { 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; } #ifdef DEBUG static void _lsdb_count_assert (struct ospf6_lsdb *lsdb) { struct ospf6_lsa *debug; unsigned int num = 0; for (debug = ospf6_lsdb_head (lsdb); debug; debug = ospf6_lsdb_next (debug)) num++; if (num == lsdb->count) return; zlog_debug ("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb, lsdb->count, num); for (debug = ospf6_lsdb_head (lsdb); debug; debug = ospf6_lsdb_next (debug)) zlog_debug ("%p %p %s lsdb[%p]", debug->prev, debug->next, debug->name, debug->lsdb); zlog_debug ("DUMP END"); assert (num == lsdb->count); } #define ospf6_lsdb_count_assert(t) (_lsdb_count_assert (t)) #else /*DEBUG*/ #define ospf6_lsdb_count_assert(t) ((void) 0) #endif /*DEBUG*/ void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) { struct prefix_ipv6 key; struct route_node *current; struct ospf6_lsa *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; lsa->rn = current; ospf6_lsa_lock (lsa); if (!old) { lsdb->count++; if (OSPF6_LSA_IS_MAXAGE (lsa)) { if (lsdb->hook_remove) (*lsdb->hook_remove) (lsa); } else { if (lsdb->hook_add) (*lsdb->hook_add) (lsa); } } else { 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); } } ospf6_lsa_unlock (old); } ospf6_lsdb_count_assert (lsdb); } 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); node->info = NULL; lsdb->count--; if (lsdb->hook_remove) (*lsdb->hook_remove) (lsa); route_unlock_node (node); /* to free the lookup lock */ route_unlock_node (node); /* to free the original lock */ ospf6_lsa_unlock (lsa); 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; route_unlock_node (node); return (struct ospf6_lsa *) node->info; } 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_debug ("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[prefix_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)) { node = route_next (node); while (node && node->info == NULL) node = route_next (node); } 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; 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 route_node *node = lsa->rn; struct ospf6_lsa *next = NULL; do { node = route_next (node); } while (node && node->info == NULL); if ((node != NULL) && (node->info != NULL)) { next = node->info; ospf6_lsa_lock (next); } ospf6_lsa_unlock (lsa); 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[prefix6_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; 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 = ospf6_lsdb_next(lsa); if (next) { if (next->header->type != type || next->header->adv_router != adv_router) { route_unlock_node (next->rn); ospf6_lsa_unlock (next); next = NULL; } } 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[prefix6_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; 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 = ospf6_lsdb_next (lsa); if (next) { if (next->header->type != type) { route_unlock_node (next->rn); ospf6_lsa_unlock (next); next = NULL; } } return next; } void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; if (lsdb == NULL) return; for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) ospf6_lsdb_remove (lsa, lsdb); } void ospf6_lsdb_lsa_unlock (struct ospf6_lsa *lsa) { if (lsa != NULL) { if (lsa->rn != NULL) route_unlock_node (lsa->rn); ospf6_lsa_unlock (lsa); } } int ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb) { int reschedule = 0; 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) { reschedule = 1; continue; } if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) zlog_debug ("Remove MaxAge %s", lsa->name); if (CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED)) { UNSET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED); /* * lsa->header->age = 0; */ lsa->header->seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER + 1); ospf6_lsa_checksum (lsa->header); THREAD_OFF(lsa->refresh); thread_execute (master, ospf6_lsa_refresh, lsa, 0); } else { ospf6_lsdb_remove (lsa, lsdb); } } return (reschedule); } void ospf6_lsdb_show (struct vty *vty, enum ospf_lsdb_show_level 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; switch (level) { case OSPF6_LSDB_SHOW_LEVEL_DETAIL: showfunc = ospf6_lsa_show; break; case OSPF6_LSDB_SHOW_LEVEL_INTERNAL: showfunc = ospf6_lsa_show_internal; break; case OSPF6_LSDB_SHOW_LEVEL_DUMP: showfunc = ospf6_lsa_show_dump; break; case OSPF6_LSDB_SHOW_LEVEL_NORMAL: default: showfunc = ospf6_lsa_show_summary; } 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) { ospf6_lsdb_lsa_unlock (lsa); 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 = OSPF_INITIAL_SEQUENCE_NUMBER; else seqnum = (signed long) ntohl (lsa->header->seqnum) + 1; return ((u_int32_t) htonl (seqnum)); } quagga-1.2.4/ospf6d/ospf6_lsdb.h000066400000000000000000000070331325323223500164010ustar00rootroot00000000000000/* * 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 *); }; /* Function Prototypes */ extern struct ospf6_lsdb *ospf6_lsdb_create (void *data); extern void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_lookup_next (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb); extern void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_head (struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_next (struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsdb_type_router_head (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_type_router_next (u_int16_t type, u_int32_t adv_router, struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa); extern void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb); extern void ospf6_lsdb_lsa_unlock (struct ospf6_lsa *lsa); enum ospf_lsdb_show_level { OSPF6_LSDB_SHOW_LEVEL_NORMAL = 0, OSPF6_LSDB_SHOW_LEVEL_DETAIL, OSPF6_LSDB_SHOW_LEVEL_INTERNAL, OSPF6_LSDB_SHOW_LEVEL_DUMP, }; extern void ospf6_lsdb_show (struct vty *vty, enum ospf_lsdb_show_level level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, struct ospf6_lsdb *lsdb); extern u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern int ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb); #endif /* OSPF6_LSDB_H */ quagga-1.2.4/ospf6d/ospf6_main.c000066400000000000000000000200011325323223500163620ustar00rootroot00000000000000/* * 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 #include "getopt.h" #include "thread.h" #include "log.h" #include "command.h" #include "vty.h" #include "memory.h" #include "if.h" #include "filter.h" #include "prefix.h" #include "plist.h" #include "privs.h" #include "sigevent.h" #include "zclient.h" #include "vrf.h" #include "ospf6d.h" #include "ospf6_top.h" #include "ospf6_message.h" #include "ospf6_asbr.h" #include "ospf6_lsa.h" #include "ospf6_interface.h" #include "ospf6_zebra.h" /* Default configuration file name for ospf6d. */ #define OSPF6_DEFAULT_CONFIG "ospf6d.conf" /* Default port values. */ #define OSPF6_VTY_PORT 2606 /* ospf6d privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND }; struct zebra_privs_t ospf6d_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = 2, .cap_num_i = 0 }; /* 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'}, { "socket", required_argument, NULL, 'z'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { 0 } }; /* Configuration file and directory. */ 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 */ const 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\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } static void __attribute__ ((noreturn)) ospf6_exit (int status) { struct listnode *node; struct interface *ifp; if (ospf6) ospf6_delete (ospf6); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) if (ifp->info != NULL) ospf6_interface_delete(ifp->info); ospf6_message_terminate (); ospf6_asbr_terminate (); ospf6_lsa_terminate (); vrf_terminate (); vty_terminate (); cmd_terminate (); if (zclient) zclient_free (zclient); if (master) thread_master_free (master); if (zlog_default) closezlog (zlog_default); exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog_info ("SIGHUP received"); } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal SIGINT"); ospf6_exit (0); } /* SIGTERM handler. */ static void sigterm (void) { zlog_notice ("Terminating on signal SIGTERM"); ospf6_clean(); ospf6_exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_info ("SIGUSR1 received"); zlog_rotate (NULL); } struct quagga_signal_t ospf6_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigterm, }, { .signal = SIGUSR1, .handler = &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; int dryrun = 0; /* 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:i:z:hp:A:P:u:g:vC", 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 'z': zclient_serv_path_set (optarg); break; case 'P': /* Deal with atoi() returning 0 on failure, and ospf6d not listening on ospf6d port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = OSPF6_VTY_PORT; break; case 'u': ospf6d_privs.user = optarg; break; case 'g': ospf6d_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } if (geteuid () != 0) { errno = EPERM; perror (progname); exit (1); } /* thread master */ master = thread_master_create (); /* Initializations. */ zlog_default = openzlog (progname, ZLOG_OSPF6, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ospf6d_privs); /* initialize zebra libraries */ signal_init (master, array_size(ospf6_signals), ospf6_signals); cmd_init (1); vty_init (master); memory_init (); vrf_init (); access_list_init (); prefix_list_init (); /* initialize ospf6 */ ospf6_init (); /* parse config file */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if (dryrun) return(0); if (daemon_mode && daemon (0, 0) < 0) { zlog_err("OSPF6d daemon failed: %s", strerror(errno)); exit (1); } /* pid file create */ pid_output (pid_file); /* Make ospf6 vty socket. */ if (!vty_port) vty_port = OSPF6_VTY_PORT; vty_serv_sock (vty_addr, vty_port, OSPF6_VTYSH_PATH); /* Print start message */ zlog_notice ("OSPF6d (Quagga-%s ospf6d-%s) starts: vty@%d", QUAGGA_VERSION, OSPF6_DAEMON_VERSION,vty_port); /* Start finite state machine, here we go! */ thread_main (master); /* Log in case thread failed */ zlog_warn ("Thread failed"); /* Not reached. */ ospf6_exit (0); } quagga-1.2.4/ospf6d/ospf6_message.c000066400000000000000000002327321325323223500171020ustar00rootroot00000000000000/* * 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" /* for structures and macros ospf6_lsa_examin() needs */ #include "ospf6_abr.h" #include "ospf6_asbr.h" #include "ospf6_intra.h" #include "ospf6_flood.h" #include "ospf6d.h" #include unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; static const struct message ospf6_message_type_str [] = { { OSPF6_MESSAGE_TYPE_HELLO, "Hello" }, { OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc" }, { OSPF6_MESSAGE_TYPE_LSREQ, "LSReq" }, { OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate" }, { OSPF6_MESSAGE_TYPE_LSACK, "LSAck" }, }; static const size_t ospf6_message_type_str_max = array_size(ospf6_message_type_str); /* Minimum (besides the standard OSPF packet header) lengths for OSPF packets of particular types, offset is the "type" field. */ const u_int16_t ospf6_packet_minlen[OSPF6_MESSAGE_TYPE_ALL] = { 0, OSPF6_HELLO_MIN_SIZE, OSPF6_DB_DESC_MIN_SIZE, OSPF6_LS_REQ_MIN_SIZE, OSPF6_LS_UPD_MIN_SIZE, OSPF6_LS_ACK_MIN_SIZE }; /* Minimum (besides the standard LSA header) lengths for LSAs of particular types, offset is the "LSA function code" portion of "LSA type" field. */ const u_int16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] = { 0, /* 0x2001 */ OSPF6_ROUTER_LSA_MIN_SIZE, /* 0x2002 */ OSPF6_NETWORK_LSA_MIN_SIZE, /* 0x2003 */ OSPF6_INTER_PREFIX_LSA_MIN_SIZE, /* 0x2004 */ OSPF6_INTER_ROUTER_LSA_FIX_SIZE, /* 0x4005 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, /* 0x2006 */ 0, /* 0x2007 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, /* 0x0008 */ OSPF6_LINK_LSA_MIN_SIZE, /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE }; /* 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_debug (" OSPFv%d Type:%d Len:%hu Router-ID:%s", oh->version, oh->type, ntohs (oh->length), router_id); zlog_debug (" 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_debug (" I/F-Id:%ld Priority:%d Option:%s", (u_long) ntohl (hello->interface_id), hello->priority, options); zlog_debug (" HelloInterval:%hu DeadInterval:%hu", ntohs (hello->hello_interval), ntohs (hello->dead_interval)); zlog_debug (" 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_debug (" Neighbor: %s", neighbor); } assert (p == OSPF6_MESSAGE_END (oh)); } 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_debug (" MBZ: %#x Option: %s IfMTU: %hu", dbdesc->reserved1, options, ntohs (dbdesc->ifmtu)); zlog_debug (" 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); assert (p == OSPF6_MESSAGE_END (oh)); } 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_debug (" [%s Id:%s Adv:%s]", ospf6_lstype_name (e->type), id, adv_router); } assert (p == OSPF6_MESSAGE_END (oh)); } 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_debug (" 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); } assert (p == OSPF6_MESSAGE_END (oh)); } 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); assert (p == OSPF6_MESSAGE_END (oh)); } static 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; 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_debug ("HelloInterval mismatch"); return; } /* RouterDeadInterval check */ if (ntohs (hello->dead_interval) != oi->dead_interval) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("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++; } assert (p == OSPF6_MESSAGE_END (oh)); /* 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_debug ("Neighbor state less than Init, ignore"); return; } switch (on->state) { case OSPF6_NEIGHBOR_TWOWAY: if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("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_debug ("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_debug ("Duplicated dbdesc discarded by Master, ignore"); return; } if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT)) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("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_debug ("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_debug ("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_debug ("Duplicated dbdesc discarded by Master, ignore"); return; } if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("%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_debug ("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_debug ("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_debug ("Add request (No database copy)"); ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } else if (ospf6_lsa_compare (his, mine) < 0) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Add request (Received MoreRecent)"); ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } else { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Discard (Existing MoreRecent)"); } ospf6_lsa_delete (his); } assert (p == OSPF6_MESSAGE_END (oh)); /* Increment sequence number */ on->dbdesc_seqnum ++; /* schedule send lsreq */ if (on->request_list->count && (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_debug ("Neighbor state less than Init, ignore"); return; } switch (on->state) { case OSPF6_NEIGHBOR_TWOWAY: if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug ("Add request-list: %s", his->name); ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } ospf6_lsa_delete (his); } assert (p == OSPF6_MESSAGE_END (oh)); /* Set sequence number to Master's */ on->dbdesc_seqnum = ntohl (dbdesc->seqnum); /* schedule send lsreq */ if ((on->thread_send_lsreq == NULL) && (on->request_list->count)) 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)); } static 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; on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor not found, ignore"); return; } dbdesc = (struct ospf6_dbdesc *) ((caddr_t) oh + sizeof (struct ospf6_header)); /* Interface MTU check */ if (!oi->mtu_ignore && ntohs (dbdesc->ifmtu) != oi->ifmtu) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("I/F MTU mismatch"); return; } if (dbdesc->reserved1 || dbdesc->reserved2) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("Can't decide which is master, ignore"); } } static 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; on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("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_debug ("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_debug ("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); } assert (p == OSPF6_MESSAGE_END (oh)); /* schedule send lsupdate */ THREAD_OFF (on->thread_send_lsupdate); on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); } /* Verify, that the specified memory area contains exactly N valid IPv6 prefixes as specified by RFC5340, A.4.1. */ static unsigned ospf6_prefixes_examin ( struct ospf6_prefix *current, /* start of buffer */ unsigned length, const u_int32_t req_num_pfxs /* always compared with the actual number of prefixes */ ) { u_char requested_pfx_bytes; u_int32_t real_num_pfxs = 0; while (length) { if (length < OSPF6_PREFIX_MIN_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized IPv6 prefix header", __func__); return MSG_NG; } /* safe to look deeper */ if (current->prefix_length > IPV6_MAX_BITLEN) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: invalid PrefixLength (%u bits)", __func__, current->prefix_length); return MSG_NG; } /* covers both fixed- and variable-sized fields */ requested_pfx_bytes = OSPF6_PREFIX_MIN_SIZE + OSPF6_PREFIX_SPACE (current->prefix_length); if (requested_pfx_bytes > length) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized IPv6 prefix", __func__); return MSG_NG; } /* next prefix */ length -= requested_pfx_bytes; current = (struct ospf6_prefix *) ((caddr_t) current + requested_pfx_bytes); real_num_pfxs++; } if (real_num_pfxs != req_num_pfxs) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: IPv6 prefix number mismatch (%u required, %u real)", __func__, req_num_pfxs, real_num_pfxs); return MSG_NG; } return MSG_OK; } /* Verify an LSA to have a valid length and dispatch further (where appropriate) to check if the contents, including nested IPv6 prefixes, is properly sized/aligned within the LSA. Note that this function gets LSA type in network byte order, uses in host byte order and passes to ospf6_lstype_name() in network byte order again. */ static unsigned ospf6_lsa_examin (struct ospf6_lsa_header *lsah, const u_int16_t lsalen, const u_char headeronly) { struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct ospf6_as_external_lsa *as_external_lsa; struct ospf6_link_lsa *link_lsa; unsigned exp_length; u_int8_t ltindex; u_int16_t lsatype; /* In case an additional minimum length constraint is defined for current LSA type, make sure that this constraint is met. */ lsatype = ntohs (lsah->type); ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK; if ( ltindex < OSPF6_LSTYPE_SIZE && ospf6_lsa_minlen[ltindex] && lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE ) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) LSA", __func__, lsalen); return MSG_NG; } switch (lsatype) { case OSPF6_LSTYPE_ROUTER: /* RFC5340 A.4.3, LSA header + OSPF6_ROUTER_LSA_MIN_SIZE bytes followed by N>=0 interface descriptions. */ if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE) % OSPF6_ROUTER_LSDESC_FIX_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: interface description alignment error", __func__); return MSG_NG; } break; case OSPF6_LSTYPE_NETWORK: /* RFC5340 A.4.4, LSA header + OSPF6_NETWORK_LSA_MIN_SIZE bytes followed by N>=0 attached router descriptions. */ if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_NETWORK_LSA_MIN_SIZE) % OSPF6_NETWORK_LSDESC_FIX_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: router description alignment error", __func__); return MSG_NG; } break; case OSPF6_LSTYPE_INTER_PREFIX: /* RFC5340 A.4.5, LSA header + OSPF6_INTER_PREFIX_LSA_MIN_SIZE bytes followed by 3-4 fields of a single IPv6 prefix. */ if (headeronly) break; return ospf6_prefixes_examin ( (struct ospf6_prefix *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_PREFIX_LSA_MIN_SIZE), lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTER_PREFIX_LSA_MIN_SIZE, 1 ); case OSPF6_LSTYPE_INTER_ROUTER: /* RFC5340 A.4.6, fixed-size LSA. */ if (lsalen > OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: oversized (%u B) LSA", __func__, lsalen); return MSG_NG; } break; case OSPF6_LSTYPE_AS_EXTERNAL: /* RFC5340 A.4.7, same as A.4.8. */ case OSPF6_LSTYPE_TYPE_7: /* RFC5340 A.4.8, LSA header + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE bytes followed by 3-4 fields of IPv6 prefix and 3 conditional LSA fields: 16 bytes of forwarding address, 4 bytes of external route tag, 4 bytes of referenced link state ID. */ if (headeronly) break; as_external_lsa = (struct ospf6_as_external_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); exp_length = OSPF6_LSA_HEADER_SIZE + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE; /* To find out if the last optional field (Referenced Link State ID) is assumed in this LSA, we need to access fixed fields of the IPv6 prefix before ospf6_prefix_examin() confirms its sizing. */ if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) LSA header", __func__, lsalen); return MSG_NG; } /* forwarding address */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) exp_length += 16; /* external route tag */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) exp_length += 4; /* referenced link state ID */ if (as_external_lsa->prefix.u._prefix_referenced_lstype) exp_length += 4; /* All the fixed-size fields (mandatory and optional) must fit. I.e., this check does not include any IPv6 prefix fields. */ if (exp_length > lsalen) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) LSA header", __func__, lsalen); return MSG_NG; } /* The last call completely covers the remainder (IPv6 prefix). */ return ospf6_prefixes_examin ( (struct ospf6_prefix *) ((caddr_t) as_external_lsa + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE), lsalen - exp_length, 1 ); case OSPF6_LSTYPE_LINK: /* RFC5340 A.4.9, LSA header + OSPF6_LINK_LSA_MIN_SIZE bytes followed by N>=0 IPv6 prefix blocks (with N declared beforehand). */ if (headeronly) break; link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); return ospf6_prefixes_examin ( (struct ospf6_prefix *) ((caddr_t) link_lsa + OSPF6_LINK_LSA_MIN_SIZE), lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_LINK_LSA_MIN_SIZE, ntohl (link_lsa->prefix_num) /* 32 bits */ ); case OSPF6_LSTYPE_INTRA_PREFIX: /* RFC5340 A.4.10, LSA header + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE bytes followed by N>=0 IPv6 prefixes (with N declared beforehand). */ if (headeronly) break; intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); return ospf6_prefixes_examin ( (struct ospf6_prefix *) ((caddr_t) intra_prefix_lsa + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE), lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTRA_PREFIX_LSA_MIN_SIZE, ntohs (intra_prefix_lsa->prefix_num) /* 16 bits */ ); } /* No additional validation is possible for unknown LSA types, which are themselves valid in OPSFv3, hence the default decision is to accept. */ return MSG_OK; } /* Verify if the provided input buffer is a valid sequence of LSAs. This includes verification of LSA blocks length/alignment and dispatching of deeper-level checks. */ static unsigned ospf6_lsaseq_examin ( struct ospf6_lsa_header *lsah, /* start of buffered data */ size_t length, const u_char headeronly, /* When declared_num_lsas is not 0, compare it to the real number of LSAs and treat the difference as an error. */ const u_int32_t declared_num_lsas ) { u_int32_t counted_lsas = 0; while (length) { u_int16_t lsalen; if (length < OSPF6_LSA_HEADER_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%zu B) trailing (#%u) LSA header", __func__, length, counted_lsas); return MSG_NG; } /* save on ntohs() calls here and in the LSA validator */ lsalen = OSPF6_LSA_SIZE (lsah); if (lsalen < OSPF6_LSA_HEADER_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: malformed LSA header #%u, declared length is %u B", __func__, counted_lsas, lsalen); return MSG_NG; } if (headeronly) { /* less checks here and in ospf6_lsa_examin() */ if (MSG_OK != ospf6_lsa_examin (lsah, lsalen, 1)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: anomaly in header-only %s LSA #%u", __func__, ospf6_lstype_name (lsah->type), counted_lsas); return MSG_NG; } lsah = (struct ospf6_lsa_header *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); length -= OSPF6_LSA_HEADER_SIZE; } else { /* make sure the input buffer is deep enough before further checks */ if (lsalen > length) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B", __func__, ospf6_lstype_name (lsah->type), counted_lsas, lsalen, length); return MSG_NG; } if (MSG_OK != ospf6_lsa_examin (lsah, lsalen, 0)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: anomaly in %s LSA #%u", __func__, ospf6_lstype_name (lsah->type), counted_lsas); return MSG_NG; } lsah = (struct ospf6_lsa_header *) ((caddr_t) lsah + lsalen); length -= lsalen; } counted_lsas++; } if (declared_num_lsas && counted_lsas != declared_num_lsas) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: #LSAs declared (%u) does not match actual (%u)", __func__, declared_num_lsas, counted_lsas); return MSG_NG; } return MSG_OK; } /* Verify a complete OSPF packet for proper sizing/alignment. */ static unsigned ospf6_packet_examin (struct ospf6_header *oh, const unsigned bytesonwire) { struct ospf6_lsupdate *lsupd; unsigned test; /* length, 1st approximation */ if (bytesonwire < OSPF6_HEADER_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire); return MSG_NG; } /* Now it is safe to access header fields. */ if (bytesonwire != ntohs (oh->length)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: packet length error (%u real, %u declared)", __func__, bytesonwire, ntohs (oh->length)); return MSG_NG; } /* version check */ if (oh->version != OSPFV3_VERSION) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version); return MSG_NG; } /* length, 2nd approximation */ if ( oh->type < OSPF6_MESSAGE_TYPE_ALL && ospf6_packet_minlen[oh->type] && bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type] ) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) %s packet", __func__, bytesonwire, LOOKUP (ospf6_message_type_str, oh->type)); return MSG_NG; } /* type-specific deeper validation */ switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: /* RFC5340 A.3.2, packet header + OSPF6_HELLO_MIN_SIZE bytes followed by N>=0 router-IDs. */ if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE) % 4) return MSG_OK; if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: alignment error in %s packet", __func__, LOOKUP (ospf6_message_type_str, oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_DBDESC: /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes followed by N>=0 header-only LSAs. */ test = ospf6_lsaseq_examin ( (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_DB_DESC_MIN_SIZE), bytesonwire - OSPF6_HEADER_SIZE - OSPF6_DB_DESC_MIN_SIZE, 1, 0 ); break; case OSPF6_MESSAGE_TYPE_LSREQ: /* RFC5340 A.3.4, packet header + N>=0 LS description blocks. */ if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE) % OSPF6_LSREQ_LSDESC_FIX_SIZE) return MSG_OK; if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: alignment error in %s packet", __func__, LOOKUP (ospf6_message_type_str, oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_LSUPDATE: /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes followed by N>=0 full LSAs (with N declared beforehand). */ lsupd = (struct ospf6_lsupdate *) ((caddr_t) oh + OSPF6_HEADER_SIZE); test = ospf6_lsaseq_examin ( (struct ospf6_lsa_header *) ((caddr_t) lsupd + OSPF6_LS_UPD_MIN_SIZE), bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_UPD_MIN_SIZE, 0, ntohl (lsupd->lsa_number) /* 32 bits */ ); break; case OSPF6_MESSAGE_TYPE_LSACK: /* RFC5340 A.3.6, packet header + N>=0 header-only LSAs. */ test = ospf6_lsaseq_examin ( (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_LS_ACK_MIN_SIZE), bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_ACK_MIN_SIZE, 1, 0 ); break; default: if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: invalid (%u) message type", __func__, oh->type); return MSG_NG; } if (test != MSG_OK && IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: anomaly in %s packet", __func__, LOOKUP (ospf6_message_type_str, oh->type)); return test; } /* Verify particular fields of otherwise correct received OSPF packet to meet the requirements of RFC. */ static int ospf6_rxpacket_examin (struct ospf6_interface *oi, struct ospf6_header *oh, const unsigned bytesonwire) { char buf[2][INET_ADDRSTRLEN]; if (MSG_OK != ospf6_packet_examin (oh, bytesonwire)) return MSG_NG; /* Area-ID check */ if (oh->area_id != oi->area->area_id) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) { if (oh->area_id == OSPF_AREA_BACKBONE) zlog_debug ("%s: Message may be via Virtual Link: not supported", __func__); else zlog_debug ( "%s: Area-ID mismatch (my %s, rcvd %s)", __func__, inet_ntop (AF_INET, &oi->area->area_id, buf[0], INET_ADDRSTRLEN), inet_ntop (AF_INET, &oh->area_id, buf[1], INET_ADDRSTRLEN) ); } return MSG_NG; } /* Instance-ID check */ if (oh->instance_id != oi->instance_id) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("%s: Instance-ID mismatch (my %u, rcvd %u)", __func__, oi->instance_id, oh->instance_id); return MSG_NG; } /* Router-ID check */ if (oh->router_id == oi->area->ospf6->router_id) { zlog_warn ("%s: Duplicate Router-ID (%s)", __func__, inet_ntop (AF_INET, &oh->router_id, buf[0], INET_ADDRSTRLEN)); return MSG_NG; } return MSG_OK; } static 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; char *p; on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("Neighbor state less than Exchange, ignore"); return; } lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); /* 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)) { ospf6_receive_lsa (on, (struct ospf6_lsa_header *) p); } assert (p == OSPF6_MESSAGE_END (oh)); } static 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); on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("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_debug ("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_debug ("Ignoring LSA of reserved scope"); ospf6_lsa_delete (his); continue; break; } if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("%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_debug ("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_debug ("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_debug ("Questionable acknowledgement"); ospf6_lsa_delete (his); continue; } if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Acknowledged, remove from %s's retrans-list", on->name); ospf6_decrement_retrans_count (mine); if (OSPF6_LSA_IS_MAXAGE (mine)) ospf6_maxage_remove (on->ospf6_if->area->ospf6); ospf6_lsdb_remove (mine, on->retrans_list); ospf6_lsa_delete (his); } assert (p == OSPF6_MESSAGE_END (oh)); } static u_char *recvbuf = NULL; static u_char *sendbuf = NULL; static unsigned int iobuflen = 0; int ospf6_iobuf_size (unsigned int size) { u_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_debug ("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; } void ospf6_message_terminate (void) { if (recvbuf) { XFREE (MTYPE_OSPF6_MESSAGE, recvbuf); recvbuf = NULL; } if (sendbuf) { XFREE (MTYPE_OSPF6_MESSAGE, sendbuf); sendbuf = NULL; } iobuflen = 0; } int ospf6_receive (struct thread *thread) { int sockfd; unsigned int len; char srcname[64], dstname[64]; struct in6_addr src, dst; ifindex_t 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 (&src, 0, sizeof (src)); memset (&dst, 0, sizeof (dst)); ifindex = 0; 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; } oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL || oi->area == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { zlog_debug ("Message received on disabled interface"); return 0; } if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: Ignore message on passive interface %s", __func__, oi->interface->name); return 0; } oh = (struct ospf6_header *) recvbuf; if (ospf6_rxpacket_examin (oi, oh, len) != MSG_OK) return 0; /* Being here means, that no sizing/alignment issues were detected in the input packet. This renders the additional checks performed below and also in the type-specific dispatching functions a dead code, which can be dismissed in a cleanup-focused review round later. */ /* 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_debug ("%s received on %s", LOOKUP (ospf6_message_type_str, oh->type), oi->interface->name); zlog_debug (" src: %s", srcname); zlog_debug (" 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: assert (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: assert (0); } return 0; } static void ospf6_send (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { unsigned 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_debug ("%s send on %s", LOOKUP (ospf6_message_type_str, oh->type), oi->interface->name); zlog_debug (" src: %s", srcname); zlog_debug (" 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_debug ("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"); } static uint32_t ospf6_packet_max(struct ospf6_interface *oi) { assert (oi->ifmtu > sizeof (struct ip6_hdr)); return oi->ifmtu - (sizeof (struct ip6_hdr)); } int ospf6_hello_send (struct thread *thread) { struct ospf6_interface *oi; struct ospf6_header *oh; struct ospf6_hello *hello; u_char *p; struct listnode *node, *nnode; 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_debug ("Unable to send Hello on down interface %s", oi->interface->name); return 0; } if (iobuflen == 0) { zlog_debug ("Unable to send Hello on interface %s iobuflen is 0", 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 = (u_char *)((caddr_t) hello + sizeof (struct ospf6_hello)); for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { if (on->state < OSPF6_NEIGHBOR_INIT) continue; if (p - sendbuf + sizeof (u_int32_t) > ospf6_packet_max(oi)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND)) zlog_debug ("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; u_char *p; struct ospf6_lsa *lsa; struct in6_addr *dst; 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_debug ("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) && (on->dbdesc_seqnum == 0)) { struct timeval tv; if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 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 = (u_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) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_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); if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) dst = &allspfrouters6; else dst = &on->linklocal_addr; ospf6_send (on->ospf6_if->linklocal_addr, dst, 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) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_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; u_char *p; struct ospf6_lsa *lsa, *last_req; 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_debug ("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; } memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; last_req = NULL; /* set Request entries in lsreq */ p = (u_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) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_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); last_req = lsa; } if (last_req != NULL) { if (on->last_ls_req != NULL) { ospf6_lsa_unlock (on->last_ls_req); } ospf6_lsa_lock (last_req); on->last_ls_req = last_req; } oh->type = OSPF6_MESSAGE_TYPE_LSREQ; oh->length = htons (p - sendbuf); if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); else ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); /* set next thread */ if (on->request_list->count != 0) { on->thread_send_lsreq = thread_add_timer (master, ospf6_lsreq_send, on, on->ospf6_if->rxmt_interval); } return 0; } int ospf6_lsupdate_send_neighbor (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_header *oh; struct ospf6_lsupdate *lsupdate; u_char *p; int lsa_cnt; 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_debug ("LSUpdate to neighbor %s", on->name); if (on->state < OSPF6_NEIGHBOR_EXCHANGE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) zlog_debug ("Quit to send (neighbor state %s)", ospf6_neighbor_state_str[on->state]); return 0; } memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); lsa_cnt = 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 + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_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); lsa_cnt++; assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, on->lsupdate_list); } if (lsa_cnt) { oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; oh->length = htons (p - sendbuf); lsupdate->lsa_number = htonl (lsa_cnt); if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) || (on->ospf6_if->state == OSPF6_INTERFACE_DR) || (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); else ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); } /* The addresses used for retransmissions are different from those sent the first time and so we need to separate them here. */ memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); lsa_cnt = 0; for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_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); lsa_cnt++; } if (lsa_cnt) { oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; oh->length = htons (p - sendbuf); lsupdate->lsa_number = htonl (lsa_cnt); if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); else ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); } if (on->lsupdate_list->count != 0) on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); else if (on->retrans_list->count != 0) 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; u_char *p; int lsa_cnt; 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_debug ("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 = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); lsa_cnt = 0; for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE (lsa->header))) > ospf6_packet_max(oi)) { ospf6_lsdb_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); lsa_cnt++; assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, oi->lsupdate_list); } if (lsa_cnt) { lsupdate->lsa_number = htonl (lsa_cnt); oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; oh->length = htons (p - sendbuf); if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) || (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; u_char *p; struct ospf6_lsa *lsa; int lsa_cnt = 0; 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_debug ("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 = (u_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) > ospf6_packet_max(on->ospf6_if)) { /* 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_lsdb_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); lsa_cnt++; } if (lsa_cnt) { 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); } if (on->thread_send_lsack == NULL && on->lsack_list->count > 0) { on->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); } return 0; } int ospf6_lsack_send_interface (struct thread *thread) { struct ospf6_interface *oi; struct ospf6_header *oh; u_char *p; struct ospf6_lsa *lsa; int lsa_cnt = 0; 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_debug ("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 = (u_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) > ospf6_packet_max(oi)) { /* 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_lsdb_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); lsa_cnt++; } if (lsa_cnt) { oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons (p - sendbuf); if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) || (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) { const 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 (void) { 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); } quagga-1.2.4/ospf6d/ospf6_message.h000066400000000000000000000107531325323223500171040ustar00rootroot00000000000000/* * 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 */ /* OSPFv3 packet header */ #define OSPF6_HEADER_SIZE 16U 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 */ #define OSPF6_HELLO_MIN_SIZE 20U 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 */ #define OSPF6_DB_DESC_MIN_SIZE 12U 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 */ #define OSPF6_LS_REQ_MIN_SIZE 0U /* It is just a sequence of entries below */ #define OSPF6_LSREQ_LSDESC_FIX_SIZE 12U 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 */ #define OSPF6_LS_UPD_MIN_SIZE 4U struct ospf6_lsupdate { u_int32_t lsa_number; /* Followed by LSAs */ }; /* Link State Acknowledgement */ #define OSPF6_LS_ACK_MIN_SIZE 0U /* It is just a sequence of LSA Headers */ /* Function definition */ extern void ospf6_hello_print (struct ospf6_header *); extern void ospf6_dbdesc_print (struct ospf6_header *); extern void ospf6_lsreq_print (struct ospf6_header *); extern void ospf6_lsupdate_print (struct ospf6_header *); extern void ospf6_lsack_print (struct ospf6_header *); extern int ospf6_iobuf_size (unsigned int size); extern void ospf6_message_terminate (void); extern int ospf6_receive (struct thread *thread); extern int ospf6_hello_send (struct thread *thread); extern int ospf6_dbdesc_send (struct thread *thread); extern int ospf6_dbdesc_send_newone (struct thread *thread); extern int ospf6_lsreq_send (struct thread *thread); extern int ospf6_lsupdate_send_interface (struct thread *thread); extern int ospf6_lsupdate_send_neighbor (struct thread *thread); extern int ospf6_lsack_send_interface (struct thread *thread); extern int ospf6_lsack_send_neighbor (struct thread *thread); extern int config_write_ospf6_debug_message (struct vty *); extern void install_element_ospf6_debug_message (void); #endif /* OSPF6_MESSAGE_H */ quagga-1.2.4/ospf6d/ospf6_neighbor.c000066400000000000000000000720231325323223500172460ustar00rootroot00000000000000/* * 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 "ospf6_snmp.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_neighbor = 0; const char *ospf6_neighbor_state_str[] = { "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange", "Loading", "Full", NULL }; static const char *ospf6_neighbor_event_str[] = { "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone", "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "BadLSReq", "1-WayReceived", "InactivityTimer", }; static const char * ospf6_neighbor_event_string (int event) { #define OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING "UnknownEvent" if (event < OSPF6_NEIGHBOR_EVENT_MAX_EVENT) return ospf6_neighbor_event_str[event]; return OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING; } 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) { struct listnode *n; struct ospf6_neighbor *on; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, n, on)) 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; on->state_change = 0; quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed); 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->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->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->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, int event) { u_char prev_state; prev_state = on->state; on->state = next_state; if (prev_state == next_state) return; on->state_change++; quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed); /* log */ if (IS_OSPF6_DEBUG_NEIGHBOR (STATE)) { zlog_debug ("Neighbor state change %s: [%s]->[%s] (%s)", on->name, ospf6_neighbor_state_str[prev_state], ospf6_neighbor_state_str[next_state], ospf6_neighbor_event_string(event)); } /* Optionally notify about adjacency changes */ if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES) && (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL) || (next_state == OSPF6_NEIGHBOR_FULL) || (next_state < prev_state))) zlog_notice("AdjChg: Nbr %s: %s -> %s (%s)", on->name, ospf6_neighbor_state_str[prev_state], ospf6_neighbor_state_str[next_state], ospf6_neighbor_event_string(event)); 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); } if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE || prev_state == OSPF6_NEIGHBOR_LOADING) && (next_state != OSPF6_NEIGHBOR_EXCHANGE && next_state != OSPF6_NEIGHBOR_LOADING)) ospf6_maxage_remove (on->ospf6_if->area->ospf6); #ifdef HAVE_SNMP /* Terminal state or regression */ if ((next_state == OSPF6_NEIGHBOR_FULL) || (next_state == OSPF6_NEIGHBOR_TWOWAY) || (next_state < prev_state)) ospf6TrapNbrStateChange (on); #endif } /* RFC2328 section 10.4 */ static 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_debug ("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, OSPF6_NEIGHBOR_EVENT_HELLO_RCVD); 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_debug ("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, OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); return 0; } ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); 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_debug ("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, OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE); 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_debug ("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, OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE); else { ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on, OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE); if (on->thread_send_lsreq == NULL) on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 0); } return 0; } /* Check loading state. */ void ospf6_check_nbr_loading (struct ospf6_neighbor *on) { /* 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. */ if ((on->state == OSPF6_NEIGHBOR_LOADING) || (on->state == OSPF6_NEIGHBOR_EXCHANGE)) { if (on->request_list->count == 0) thread_add_event (master, loading_done, on, 0); else if (on->last_ls_req == NULL) { if (on->thread_send_lsreq != NULL) THREAD_OFF (on->thread_send_lsreq); on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 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_debug ("Neighbor Event %s: *LoadingDone*", on->name); assert (on->request_list->count == 0); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on, OSPF6_NEIGHBOR_EVENT_LOADING_DONE); 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_debug ("Neighbor Event %s: *AdjOK?*", on->name); if (on->state == OSPF6_NEIGHBOR_TWOWAY && need_adjacency (on)) { ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, OSPF6_NEIGHBOR_EVENT_ADJ_OK); 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_NEIGHBOR_EVENT_ADJ_OK); 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_debug ("Neighbor Event %s: *SeqNumberMismatch*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, OSPF6_NEIGHBOR_EVENT_SEQNUMBER_MISMATCH); 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->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ 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_debug ("Neighbor Event %s: *BadLSReq*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, OSPF6_NEIGHBOR_EVENT_BAD_LSREQ); 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->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ 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_debug ("Neighbor Event %s: *1Way-Received*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on, OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD); 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_debug ("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, OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER); 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 */ static 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*/ quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); /* Dead time */ h = m = s = 0; if (on->inactivity_timer) { s = on->inactivity_timer->u.sands.tv_sec - recent_relative_time().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); } static 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)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); 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); } static 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)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); 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->request_list->count, duration, (on->thread_send_lsreq ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (on->request_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; struct 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 (ALL_LIST_ELEMENTS_RO (ospf6->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on)) (*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; struct 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 (ALL_LIST_ELEMENTS_RO (ospf6->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on)) (*showfunc) (vty, on); return CMD_SUCCESS; } void ospf6_neighbor_init (void) { install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd); install_element (VIEW_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 (void) { 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); } quagga-1.2.4/ospf6d/ospf6_neighbor.h000066400000000000000000000114761325323223500172600ustar00rootroot00000000000000/* * 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 */ u_int32_t state_change; struct timeval last_changed; /* Neighbor Router ID */ u_int32_t router_id; /* Neighbor Interface ID */ ifindex_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; struct ospf6_lsa *last_ls_req; /* 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 /* Neighbor Events */ #define OSPF6_NEIGHBOR_EVENT_NO_EVENT 0 #define OSPF6_NEIGHBOR_EVENT_HELLO_RCVD 1 #define OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD 2 #define OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE 3 #define OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE 4 #define OSPF6_NEIGHBOR_EVENT_LOADING_DONE 5 #define OSPF6_NEIGHBOR_EVENT_ADJ_OK 6 #define OSPF6_NEIGHBOR_EVENT_SEQNUMBER_MISMATCH 7 #define OSPF6_NEIGHBOR_EVENT_BAD_LSREQ 8 #define OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD 9 #define OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER 10 #define OSPF6_NEIGHBOR_EVENT_MAX_EVENT 11 extern const 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 */ extern int hello_received (struct thread *); extern int twoway_received (struct thread *); extern int negotiation_done (struct thread *); extern int exchange_done (struct thread *); extern int loading_done (struct thread *); extern int adj_ok (struct thread *); extern int seqnumber_mismatch (struct thread *); extern int bad_lsreq (struct thread *); extern int oneway_received (struct thread *); extern int inactivity_timer (struct thread *); extern void ospf6_check_nbr_loading (struct ospf6_neighbor *); extern void ospf6_neighbor_init (void); extern int config_write_ospf6_debug_neighbor (struct vty *vty); extern void install_element_ospf6_debug_neighbor (void); #endif /* OSPF6_NEIGHBOR_H */ quagga-1.2.4/ospf6d/ospf6_network.c000066400000000000000000000156251325323223500171470ustar00rootroot00000000000000/* * 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 "sockopt.h" #include "privs.h" #include "libospf.h" #include "ospf6_proto.h" #include "ospf6_network.h" extern struct zebra_privs_t ospf6d_privs; int ospf6_sock; struct in6_addr allspfrouters6; struct in6_addr alldrouters6; /* setsockopt MulticastLoop to off */ static void ospf6_reset_mcastloop (void) { 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", safe_strerror (errno)); } static void ospf6_set_pktinfo (void) { setsockopt_ipv6_pktinfo (ospf6_sock, 1); } static void ospf6_set_transport_class (void) { #ifdef IPTOS_PREC_INTERNETCONTROL setsockopt_ipv6_tclass (ospf6_sock, IPTOS_PREC_INTERNETCONTROL); #endif } static void ospf6_set_checksum (void) { 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", safe_strerror (errno)); #else zlog_warn ("Network: Don't set IPV6_CHECKSUM"); #endif /* DISABLE_IPV6_CHECKSUM */ } /* Make ospf6d's server socket. */ int ospf6_serv_sock (void) { if (ospf6d_privs.change (ZPRIVS_RAISE)) zlog_err ("ospf6_serv_sock: could not raise privs"); ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP); if (ospf6_sock < 0) { zlog_warn ("Network: can't create OSPF6 socket."); if (ospf6d_privs.change (ZPRIVS_LOWER)) zlog_err ("ospf_sock_init: could not lower privs"); return -1; } if (ospf6d_privs.change (ZPRIVS_LOWER)) zlog_err ("ospf_sock_init: could not lower privs"); /* set socket options */ #if 1 sockopt_reuseaddr (ospf6_sock); #else ospf6_set_reuseaddr (); #endif /*1*/ ospf6_reset_mcastloop (); ospf6_set_pktinfo (); ospf6_set_transport_class (); 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; } /* ospf6 set socket option */ int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option) { struct ipv6_mreq mreq6; int ret; assert (ifindex); mreq6.ipv6mr_interface = ifindex; memcpy (&mreq6.ipv6mr_multiaddr, group, sizeof (struct in6_addr)); ret = setsockopt (ospf6_sock, IPPROTO_IPV6, option, &mreq6, sizeof (mreq6)); if (ret < 0) { zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s", option, ifindex, safe_strerror (errno)); } return ret; } static int iov_count (struct iovec *iov) { int i; for (i = 0; iov[i].iov_base; i++) ; return i; } static 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, ifindex_t *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 */ memset (&smsghdr, 0, sizeof (smsghdr)); 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 = scmsgp->cmsg_len; retval = sendmsg (ospf6_sock, &smsghdr, 0); if (retval != iov_totallen (message)) zlog_warn ("sendmsg failed: ifindex: %d: %s (%d)", *ifindex, safe_strerror (errno), errno); return retval; } int ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst, ifindex_t *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 */ memset (&rmsghdr, 0, sizeof (rmsghdr)); 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", safe_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; } quagga-1.2.4/ospf6d/ospf6_network.h000066400000000000000000000024761325323223500171540ustar00rootroot00000000000000/* * 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; extern int ospf6_serv_sock (void); extern int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, ifindex_t *, struct iovec *); extern int ospf6_recvmsg (struct in6_addr *, struct in6_addr *, ifindex_t *, struct iovec *); #endif /* OSPF6_NETWORK_H */ quagga-1.2.4/ospf6d/ospf6_proto.c000066400000000000000000000047411325323223500166160ustar00rootroot00000000000000/* * 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; } /* nonzero mask means no check for this byte because if it contains * prefix bits it must be there for us to write */ if (mask) pnt[index++] &= mask; 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) { const 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); } quagga-1.2.4/ospf6d/ospf6_proto.h000066400000000000000000000074111325323223500166200ustar00rootroot00000000000000/* * 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 /* TOS field normaly null */ #define DEFAULT_TOS_VALUE 0x0 #define ALLSPFROUTERS6 "ff02::5" #define ALLDROUTERS6 "ff02::6" #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 */ #define OSPF6_PREFIX_MIN_SIZE 4U /* .length == 0 */ 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) extern void ospf6_prefix_apply_mask (struct ospf6_prefix *op); extern void ospf6_prefix_options_printbuf (u_int8_t prefix_options, char *buf, int size); extern void ospf6_capability_printbuf (char capability, char *buf, int size); extern void ospf6_options_printbuf (u_char *options, char *buf, int size); #endif /* OSPF6_PROTO_H */ quagga-1.2.4/ospf6d/ospf6_route.c000066400000000000000000001145301325323223500166070ustar00rootroot00000000000000/* * 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 "linklist.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 "ospf6d.h" unsigned char conf_debug_ospf6_route = 0; static char * ospf6_route_table_name (struct ospf6_route_table *table) { static char name[32]; switch (table->scope_type) { case OSPF6_SCOPE_TYPE_GLOBAL: { switch (table->table_type) { case OSPF6_TABLE_TYPE_ROUTES: snprintf (name, sizeof (name), "global route table"); break; case OSPF6_TABLE_TYPE_BORDER_ROUTERS: snprintf (name, sizeof (name), "global brouter table"); break; case OSPF6_TABLE_TYPE_EXTERNAL_ROUTES: snprintf (name, sizeof (name), "global external table"); break; default: snprintf (name, sizeof (name), "global unknown table"); break; } } break; case OSPF6_SCOPE_TYPE_AREA: { struct ospf6_area *oa = (struct ospf6_area *) table->scope; switch (table->table_type) { case OSPF6_TABLE_TYPE_SPF_RESULTS: snprintf (name, sizeof (name), "area %s spf table", oa->name); break; case OSPF6_TABLE_TYPE_ROUTES: snprintf (name, sizeof (name), "area %s route table", oa->name); break; case OSPF6_TABLE_TYPE_PREFIX_RANGES: snprintf (name, sizeof (name), "area %s range table", oa->name); break; case OSPF6_TABLE_TYPE_SUMMARY_PREFIXES: snprintf (name, sizeof (name), "area %s summary prefix table", oa->name); break; case OSPF6_TABLE_TYPE_SUMMARY_ROUTERS: snprintf (name, sizeof (name), "area %s summary router table", oa->name); break; default: snprintf (name, sizeof (name), "area %s unknown table", oa->name); break; } } break; case OSPF6_SCOPE_TYPE_INTERFACE: { struct ospf6_interface *oi = (struct ospf6_interface *) table->scope; switch (table->table_type) { case OSPF6_TABLE_TYPE_CONNECTED_ROUTES: snprintf (name, sizeof (name), "interface %s connected table", oi->interface->name); break; default: snprintf (name, sizeof (name), "interface %s unknown table", oi->interface->name); break; } } break; default: { switch (table->table_type) { case OSPF6_TABLE_TYPE_SPF_RESULTS: snprintf (name, sizeof (name), "temporary spf table"); break; default: snprintf (name, sizeof (name), "temporary unknown table"); break; } } break; } return name; } 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 */ const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] = { "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange", }; const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] = { "?", "R", "N", "D", "L", "A", }; const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] = { "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", }; const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = { "??", "IA", "IE", "E1", "E2", }; struct ospf6_route * ospf6_route_create (void) { 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->table = 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) { /* Can't detach from the table until here because ospf6_route_next () will use the 'route->table' pointer for logging */ route->table = NULL; 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; } #ifdef DEBUG static void route_table_assert (struct ospf6_route_table *table) { struct ospf6_route *prev, *r, *next; char buf[64]; unsigned int link_error = 0, num = 0; r = ospf6_route_head (table); prev = NULL; while (r) { if (r->prev != prev) link_error++; next = ospf6_route_next (r); if (r->next != next) link_error++; prev = r; r = next; } for (r = ospf6_route_head (table); r; r = ospf6_route_next (r)) num++; if (link_error == 0 && num == table->count) return; zlog_err ("PANIC !!"); zlog_err ("Something has gone wrong with ospf6_route_table[%p]", table); zlog_debug ("table count = %d, real number = %d", table->count, num); zlog_debug ("DUMP START"); for (r = ospf6_route_head (table); r; r = ospf6_route_next (r)) { prefix2str (&r->prefix, buf, sizeof (buf)); zlog_info ("%p<-[%p]->%p : %s", r->prev, r, r->next, buf); } zlog_debug ("DUMP END"); assert (link_error == 0 && num == table->count); } #define ospf6_route_table_assert(t) (route_table_assert (t)) #else #define ospf6_route_table_assert(t) ((void) 0) #endif /*DEBUG*/ 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 (MEMORY)) zlog_debug ("%s %p: route add %p: %s", ospf6_route_table_name (table), (void *)table, (void *)route, buf); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); 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 (MEMORY)) zlog_debug ("%s %p: route add %p: needless update of %p", ospf6_route_table_name (table), (void *)table, (void *)route, (void *)old); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: needless update", ospf6_route_table_name (table)); ospf6_route_delete (route); SET_FLAG (old->flag, OSPF6_ROUTE_ADD); ospf6_route_table_assert (table); return old; } if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: update of %p", ospf6_route_table_name (table), (void *)table, (void *)route, (void *)old); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: update", ospf6_route_table_name (table)); /* 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; assert (route->table == NULL); route->table = table; ospf6_route_unlock (old); /* will be deleted later */ ospf6_route_lock (route); SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE); ospf6_route_table_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 (MEMORY)) zlog_debug ("%s %p: route add %p: another path: prev %p, next %p", ospf6_route_table_name (table), (void *)table, (void *)route, (void *)prev, (void *)next); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: another path found", ospf6_route_table_name (table)); 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); if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route add %p: replacing previous best: %p", ospf6_route_table_name (table), (void *)table, (void *)route, (void *)next); } route->installed = now; route->changed = now; assert (route->table == NULL); route->table = table; ospf6_route_lock (route); table->count++; ospf6_route_table_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 (MEMORY)) zlog_debug ("%s %p: route add %p: brand new route", ospf6_route_table_name (table), (void *)table, (void *)route); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: brand new route", ospf6_route_table_name (table)); assert (node->info == NULL); node->info = route; SET_FLAG (route->flag, OSPF6_ROUTE_BEST); ospf6_route_lock (route); route->installed = now; route->changed = now; assert (route->table == NULL); route->table = table; /* 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_table_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 (MEMORY)) zlog_debug ("%s %p: route remove %p: %s", ospf6_route_table_name (table), (void *)table, (void *)route, buf); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route remove: %s", ospf6_route_table_name (table), 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 && route->next->rnode == node) { 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_table_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); assert (route->table == table); ospf6_route_lock (route); if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route head: %p<-[%p]->%p", ospf6_route_table_name (table), (void *)table, (void *)route->prev, (void *)route, (void *)route->next); return route; } struct ospf6_route * ospf6_route_next (struct ospf6_route *route) { struct ospf6_route *next = route->next; if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route next: %p<-[%p]->%p", ospf6_route_table_name (route->table), (void *)route->table, (void *)route->prev, (void *)route, (void *)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; ospf6_route_unlock (route); 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_lock (next); return next; } 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[prefix_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 (int s, int t) { struct ospf6_route_table *new; new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table)); new->table = route_table_init (); new->scope_type = s; new->table_type = t; 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]; const char *ifname; struct timeval now, res; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); 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)); ifname = ifindex2ifname (route->nexthop[0].ifindex); vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", (ospf6_route_is_best (route) ? '*' : ' '), OSPF6_DEST_TYPE_SUBSTR (route->type), OSPF6_PATH_TYPE_SUBSTR (route->path.type), destination, nexthop, IFNAMSIZ, ifname, duration, VNL); for (i = 1; i < OSPF6_MULTI_PATH_LIMIT && ospf6_nexthop_is_set (&route->nexthop[i]); i++) { /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, sizeof (nexthop)); ifname = ifindex2ifname (route->nexthop[i].ifindex); vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL); } } void ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) { const char *ifname; char destination[64], nexthop[64]; char area_id[16], id[16], adv_router[16], capa[16], options[16]; struct timeval now, res; char duration[16]; int i; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); /* 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", (void *)route->prev, (void *)route, (void *)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; i < OSPF6_MULTI_PATH_LIMIT && ospf6_nexthop_is_set (&route->nexthop[i]); i++) { /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, sizeof (nexthop)); ifname = ifindex2ifname (route->nexthop[i].ifindex); vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL); } vty_out (vty, "%s", VNL); } static 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]; unsigned 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); } } static 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); } static 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); } static 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); } } static 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); } } static 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, const 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; } static 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); } static 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); } static 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); } static 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, const 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|memory)", DEBUG_STR OSPF6_STR "Debug route table calculation\n" "Debug detail\n" "Debug intra-area route calculation\n" "Debug inter-area route calculation\n" "Debug route memory use\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; else if (! strncmp (argv[0], "memor", 5)) level = OSPF6_DEBUG_ROUTE_MEMORY; 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|memory)", NO_STR DEBUG_STR OSPF6_STR "Debug route table calculation\n" "Debug intra-area route calculation\n" "Debug route memory use\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; else if (! strncmp (argv[0], "memor", 5)) level = OSPF6_DEBUG_ROUTE_MEMORY; 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 (void) { 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); } quagga-1.2.4/ospf6d/ospf6_route.h000066400000000000000000000251201325323223500166100ustar00rootroot00000000000000/* * 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_MEMORY 0x80 #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 */ ifindex_t 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; u_int32_t tag; }; #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_table *table; struct ospf6_route *prev; struct ospf6_route *next; unsigned int lock; /* Destination Type */ u_char type; /* XXX: It would likely be better to use separate struct in_addr's * for the advertising router-ID and prefix IDs, instead of stuffing them * into one. See also XXX below. */ /* 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 { int scope_type; int table_type; void *scope; /* 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 *); }; #define OSPF6_SCOPE_TYPE_NONE 0 #define OSPF6_SCOPE_TYPE_GLOBAL 1 #define OSPF6_SCOPE_TYPE_AREA 2 #define OSPF6_SCOPE_TYPE_INTERFACE 3 #define OSPF6_TABLE_TYPE_NONE 0 #define OSPF6_TABLE_TYPE_ROUTES 1 #define OSPF6_TABLE_TYPE_BORDER_ROUTERS 2 #define OSPF6_TABLE_TYPE_CONNECTED_ROUTES 3 #define OSPF6_TABLE_TYPE_EXTERNAL_ROUTES 4 #define OSPF6_TABLE_TYPE_SPF_RESULTS 5 #define OSPF6_TABLE_TYPE_PREFIX_RANGES 6 #define OSPF6_TABLE_TYPE_SUMMARY_PREFIXES 7 #define OSPF6_TABLE_TYPE_SUMMARY_ROUTERS 8 #define OSPF6_ROUTE_TABLE_CREATE(s, t) \ ospf6_route_table_create (OSPF6_SCOPE_TYPE_ ## s, \ OSPF6_TABLE_TYPE_ ## t) extern const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX]; extern const 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 const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX]; extern const 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) \ ((x)->u.lp.id.s_addr) #define ospf6_linkstate_prefix_id(x) \ ((x)->u.lp.adv_router.s_addr) #define ADV_ROUTER_IN_PREFIX(x) \ ((x)->u.lp.id.s_addr) #define ID_IN_PREFIX(x) \ ((x)->u.lp.adv_router.s_addr) /* Function prototype */ extern void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id, struct prefix *prefix); extern void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size); extern struct ospf6_route *ospf6_route_create (void); extern void ospf6_route_delete (struct ospf6_route *); extern struct ospf6_route *ospf6_route_copy (struct ospf6_route *route); extern void ospf6_route_lock (struct ospf6_route *route); extern void ospf6_route_unlock (struct ospf6_route *route); extern struct ospf6_route *ospf6_route_lookup (struct prefix *prefix, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_lookup_identical (struct ospf6_route *route, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_lookup_bestmatch (struct prefix *prefix, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_add (struct ospf6_route *route, struct ospf6_route_table *table); extern void ospf6_route_remove (struct ospf6_route *route, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_head (struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_next (struct ospf6_route *route); extern struct ospf6_route *ospf6_route_best_next (struct ospf6_route *route); extern struct ospf6_route *ospf6_route_match_head (struct prefix *prefix, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_match_next (struct prefix *prefix, struct ospf6_route *route); extern void ospf6_route_remove_all (struct ospf6_route_table *); extern struct ospf6_route_table *ospf6_route_table_create (int s, int t); extern void ospf6_route_table_delete (struct ospf6_route_table *); extern void ospf6_route_dump (struct ospf6_route_table *table); extern void ospf6_route_show (struct vty *vty, struct ospf6_route *route); extern void ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route); extern int ospf6_route_table_show (struct vty *, int, const char *[], struct ospf6_route_table *); extern int ospf6_linkstate_table_show (struct vty *vty, int argc, const char *argv[], struct ospf6_route_table *table); extern void ospf6_brouter_show_header (struct vty *vty); extern void ospf6_brouter_show (struct vty *vty, struct ospf6_route *route); extern int config_write_ospf6_debug_route (struct vty *vty); extern void install_element_ospf6_debug_route (void); extern void ospf6_route_init (void); extern void ospf6_clean (void); #endif /* OSPF6_ROUTE_H */ quagga-1.2.4/ospf6d/ospf6_snmp.c000066400000000000000000001123661325323223500164330ustar00rootroot00000000000000/* 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 #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 "ospf6_abr.h" #include "ospf6_asbr.h" #include "ospf6d.h" #include "ospf6_snmp.h" /* OSPFv3-MIB */ #define OSPFv3MIB 1,3,6,1,2,1,191 /* 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 OSPFv3EXITOVERFLOWINTERVAL 12 #define OSPFv3DEMANDEXTENSIONS 13 #define OSPFv3REFERENCEBANDWIDTH 14 #define OSPFv3RESTARTSUPPORT 15 #define OSPFv3RESTARTINTERVAL 16 #define OSPFv3RESTARTSTRICTLSACHECKING 17 #define OSPFv3RESTARTSTATUS 18 #define OSPFv3RESTARTAGE 19 #define OSPFv3RESTARTEXITREASON 20 #define OSPFv3NOTIFICATIONENABLE 21 #define OSPFv3STUBROUTERSUPPORT 22 #define OSPFv3STUBROUTERADVERTISEMENT 23 #define OSPFv3DISCONTINUITYTIME 24 #define OSPFv3RESTARTTIME 25 /* OSPFv3 MIB Area Table values: ospfv3AreaTable */ #define OSPFv3IMPORTASEXTERN 2 #define OSPFv3AREASPFRUNS 3 #define OSPFv3AREABDRRTRCOUNT 4 #define OSPFv3AREAASBDRRTRCOUNT 5 #define OSPFv3AREASCOPELSACOUNT 6 #define OSPFv3AREASCOPELSACKSUMSUM 7 #define OSPFv3AREASUMMARY 8 #define OSPFv3AREAROWSTATUS 9 #define OSPFv3AREASTUBMETRIC 10 #define OSPFv3AREANSSATRANSLATORROLE 11 #define OSPFv3AREANSSATRANSLATORSTATE 12 #define OSPFv3AREANSSATRANSLATORSTABINTERVAL 13 #define OSPFv3AREANSSATRANSLATOREVENTS 14 #define OSPFv3AREASTUBMETRICTYPE 15 #define OSPFv3AREATEENABLED 16 /* OSPFv3 MIB * Lsdb Table values: ospfv3*LsdbTable */ #define OSPFv3WWLSDBSEQUENCE 1 #define OSPFv3WWLSDBAGE 2 #define OSPFv3WWLSDBCHECKSUM 3 #define OSPFv3WWLSDBADVERTISEMENT 4 #define OSPFv3WWLSDBTYPEKNOWN 5 /* Three first bits are to identify column */ #define OSPFv3WWCOLUMN 0x7 /* Then we use other bits to identify table */ #define OSPFv3WWASTABLE (1 << 3) #define OSPFv3WWAREATABLE (1 << 4) #define OSPFv3WWLINKTABLE (1 << 5) #define OSPFv3WWVIRTLINKTABLE (1 << 6) /* OSPFv3 MIB Host Table values: ospfv3HostTable */ #define OSPFv3HOSTMETRIC 3 #define OSPFv3HOSTROWSTATUS 4 #define OSPFv3HOSTAREAID 5 /* OSPFv3 MIB Interface Table values: ospfv3IfTable */ #define OSPFv3IFAREAID 3 #define OSPFv3IFTYPE 4 #define OSPFv3IFADMINSTATUS 5 #define OSPFv3IFRTRPRIORITY 6 #define OSPFv3IFTRANSITDELAY 7 #define OSPFv3IFRETRANSINTERVAL 8 #define OSPFv3IFHELLOINTERVAL 9 #define OSPFv3IFRTRDEADINTERVAL 10 #define OSPFv3IFPOLLINTERVAL 11 #define OSPFv3IFSTATE 12 #define OSPFv3IFDESIGNATEDROUTER 13 #define OSPFv3IFBACKUPDESIGNATEDROUTER 14 #define OSPFv3IFEVENTS 15 #define OSPFv3IFROWSTATUS 16 #define OSPFv3IFDEMAND 17 #define OSPFv3IFMETRICVALUE 18 #define OSPFv3IFLINKSCOPELSACOUNT 19 #define OSPFv3IFLINKLSACKSUMSUM 20 #define OSPFv3IFDEMANDNBRPROBE 21 #define OSPFv3IFDEMANDNBRPROBERETRANSLIMIT 22 #define OSPFv3IFDEMANDNBRPROBEINTERVAL 23 #define OSPFv3IFTEDISABLED 24 #define OSPFv3IFLINKLSASUPPRESSION 25 /* OSPFv3 MIB Virtual Interface Table values: ospfv3VirtIfTable */ #define OSPFv3VIRTIFINDEX 3 #define OSPFv3VIRTIFINSTID 4 #define OSPFv3VIRTIFTRANSITDELAY 5 #define OSPFv3VIRTIFRETRANSINTERVAL 6 #define OSPFv3VIRTIFHELLOINTERVAL 7 #define OSPFv3VIRTIFRTRDEADINTERVAL 8 #define OSPFv3VIRTIFSTATE 9 #define OSPFv3VIRTIFEVENTS 10 #define OSPFv3VIRTIFROWSTATUS 11 #define OSPFv3VIRTIFLINKSCOPELSACOUNT 12 #define OSPFv3VIRTIFLINKLSACKSUMSUM 13 /* OSPFv3 MIB Neighbors Table values: ospfv3NbrTable */ #define OSPFv3NBRADDRESSTYPE 4 #define OSPFv3NBRADDRESS 5 #define OSPFv3NBROPTIONS 6 #define OSPFv3NBRPRIORITY 7 #define OSPFv3NBRSTATE 8 #define OSPFv3NBREVENTS 9 #define OSPFv3NBRLSRETRANSQLEN 10 #define OSPFv3NBRHELLOSUPPRESSED 11 #define OSPFv3NBRIFID 12 #define OSPFv3NBRRESTARTHELPERSTATUS 13 #define OSPFv3NBRRESTARTHELPERAGE 14 #define OSPFv3NBRRESTARTHELPEREXITREASON 15 /* OSPFv3 MIB Configured Neighbors Table values: ospfv3CfgNbrTable */ #define OSPFv3CFGNBRPRIORITY 5 #define OSPFv3CFGNBRROWSTATUS 6 /* OSPFv3 MIB Virtual Neighbors Table values: ospfv3VirtNbrTable */ #define OSPFv3VIRTNBRIFINDEX 3 #define OSPFv3VIRTNBRIFINSTID 4 #define OSPFv3VIRTNBRADDRESSTYPE 5 #define OSPFv3VIRTNBRADDRESS 6 #define OSPFv3VIRTNBROPTIONS 7 #define OSPFv3VIRTNBRSTATE 8 #define OSPFv3VIRTNBREVENTS 9 #define OSPFv3VIRTNBRLSRETRANSQLEN 10 #define OSPFv3VIRTNBRHELLOSUPPRESSED 11 #define OSPFv3VIRTNBRIFID 12 #define OSPFv3VIRTNBRRESTARTHELPERSTATUS 13 #define OSPFv3VIRTNBRRESTARTHELPERAGE 14 #define OSPFv3VIRTNBRRESTARTHELPEREXITREASON 15 /* OSPFv3 MIB Area Aggregate Table values: ospfv3AreaAggregateTable */ #define OSPFv3AREAAGGREGATEROWSTATUS 6 #define OSPFv3AREAAGGREGATEEFFECT 7 #define OSPFv3AREAAGGREGATEROUTETAG 8 /* 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 UNSIGNED ASN_UNSIGNED #define TIMETICKS ASN_TIMETICKS #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR /* For return values e.g. SNMP_INTEGER macro */ SNMP_LOCAL_VARIABLES /* OSPFv3-MIB instances. */ oid ospfv3_oid [] = { OSPFv3MIB }; oid ospfv3_trap_oid [] = { OSPFv3MIB, 0 }; /* Hook functions. */ static u_char *ospfv3GeneralGroup (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3AreaEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3WwLsdbEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3NbrEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3IfEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); struct variable ospfv3_variables[] = { /* OSPF general variables */ {OSPFv3ROUTERID, UNSIGNED, 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,UNSIGNED, 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}}, {OSPFv3EXITOVERFLOWINTERVAL, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 12}}, {OSPFv3DEMANDEXTENSIONS, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 13}}, {OSPFv3REFERENCEBANDWIDTH, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 14}}, {OSPFv3RESTARTSUPPORT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 15}}, {OSPFv3RESTARTINTERVAL, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 16}}, {OSPFv3RESTARTSTRICTLSACHECKING, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 17}}, {OSPFv3RESTARTSTATUS, INTEGER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 18}}, {OSPFv3RESTARTAGE, UNSIGNED, RONLY, ospfv3GeneralGroup, 3, {1, 1, 19}}, {OSPFv3RESTARTEXITREASON, INTEGER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 20}}, {OSPFv3NOTIFICATIONENABLE, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 21}}, {OSPFv3STUBROUTERSUPPORT, INTEGER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 22}}, {OSPFv3STUBROUTERADVERTISEMENT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 23}}, {OSPFv3DISCONTINUITYTIME, TIMETICKS, RONLY, ospfv3GeneralGroup, 3, {1, 1, 24}}, {OSPFv3RESTARTTIME, TIMETICKS, RONLY, ospfv3GeneralGroup, 3, {1, 1, 25}}, /* OSPFv3 Area Data Structure */ {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, UNSIGNED, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 7}}, {OSPFv3AREASUMMARY, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 8}}, {OSPFv3AREAROWSTATUS, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 9}}, {OSPFv3AREASTUBMETRIC, 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}}, {OSPFv3AREANSSATRANSLATORSTABINTERVAL, UNSIGNED, 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}}, {OSPFv3AREATEENABLED, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 16}}, /* OSPFv3 AS LSDB */ {OSPFv3WWLSDBSEQUENCE | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 4}}, {OSPFv3WWLSDBAGE | OSPFv3WWASTABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 5}}, {OSPFv3WWLSDBCHECKSUM | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 6}}, {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWASTABLE, STRING, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 7}}, {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 8}}, /* OSPFv3 Area LSDB */ {OSPFv3WWLSDBSEQUENCE | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 5}}, {OSPFv3WWLSDBAGE | OSPFv3WWAREATABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 6}}, {OSPFv3WWLSDBCHECKSUM | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 7}}, {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWAREATABLE, STRING, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 8}}, {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 9}}, /* OSPFv3 Link LSDB */ {OSPFv3WWLSDBSEQUENCE | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 6}}, {OSPFv3WWLSDBAGE | OSPFv3WWLINKTABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 7}}, {OSPFv3WWLSDBCHECKSUM | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 8}}, {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWLINKTABLE, STRING, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 9}}, {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 10}}, /* OSPFv3 interfaces */ {OSPFv3IFAREAID, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 3}}, {OSPFv3IFTYPE, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 4}}, {OSPFv3IFADMINSTATUS, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 5}}, {OSPFv3IFRTRPRIORITY, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 6}}, {OSPFv3IFTRANSITDELAY, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 7}}, {OSPFv3IFRETRANSINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 8}}, {OSPFv3IFHELLOINTERVAL, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 9}}, {OSPFv3IFRTRDEADINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 10}}, {OSPFv3IFPOLLINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 11}}, {OSPFv3IFSTATE, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 12}}, {OSPFv3IFDESIGNATEDROUTER, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 13}}, {OSPFv3IFBACKUPDESIGNATEDROUTER, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 14}}, {OSPFv3IFEVENTS, COUNTER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 15}}, {OSPFv3IFROWSTATUS, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 16}}, {OSPFv3IFDEMAND, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 17}}, {OSPFv3IFMETRICVALUE, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 18}}, {OSPFv3IFLINKSCOPELSACOUNT, GAUGE, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 19}}, {OSPFv3IFLINKLSACKSUMSUM, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 20}}, {OSPFv3IFDEMANDNBRPROBE, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 21}}, {OSPFv3IFDEMANDNBRPROBERETRANSLIMIT, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 22}}, {OSPFv3IFDEMANDNBRPROBEINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 23}}, {OSPFv3IFTEDISABLED, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 24}}, {OSPFv3IFLINKLSASUPPRESSION, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 25}}, /* OSPFv3 neighbors */ {OSPFv3NBRADDRESSTYPE, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 4}}, {OSPFv3NBRADDRESS, STRING, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 5}}, {OSPFv3NBROPTIONS, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 6}}, {OSPFv3NBRPRIORITY, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 7}}, {OSPFv3NBRSTATE, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 8}}, {OSPFv3NBREVENTS, COUNTER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 9}}, {OSPFv3NBRLSRETRANSQLEN, GAUGE, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 10}}, {OSPFv3NBRHELLOSUPPRESSED, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 11}}, {OSPFv3NBRIFID, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 12}}, {OSPFv3NBRRESTARTHELPERSTATUS, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 13}}, {OSPFv3NBRRESTARTHELPERAGE, UNSIGNED, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 14}}, {OSPFv3NBRRESTARTHELPEREXITREASON, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 15}}, }; static u_char * ospfv3GeneralGroup (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { u_int16_t sum; u_int32_t count; struct ospf6_lsa *lsa = NULL; /* 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: /* Router-ID of this OSPF instance. */ if (ospf6) return SNMP_INTEGER (ntohl (ospf6->router_id)); return SNMP_INTEGER (0); case OSPFv3ADMINSTAT: if (ospf6) return SNMP_INTEGER (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)? OSPF_STATUS_DISABLED:OSPF_STATUS_ENABLED); return SNMP_INTEGER (OSPF_STATUS_DISABLED); case OSPFv3VERSIONNUMBER: return SNMP_INTEGER (3); case OSPFv3AREABDRRTRSTATUS: if (ospf6) return SNMP_INTEGER (ospf6_is_router_abr (ospf6)?SNMP_TRUE:SNMP_FALSE); return SNMP_INTEGER (SNMP_FALSE); case OSPFv3ASBDRRTRSTATUS: if (ospf6) return SNMP_INTEGER (ospf6_asbr_is_asbr (ospf6)?SNMP_TRUE:SNMP_FALSE); return SNMP_INTEGER (SNMP_FALSE); case OSPFv3ASSCOPELSACOUNT: if (ospf6) return SNMP_INTEGER (ospf6->lsdb->count); return SNMP_INTEGER (0); case OSPFv3ASSCOPELSACHECKSUMSUM: if (ospf6) { for (sum = 0, lsa = ospf6_lsdb_head (ospf6->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) sum += ntohs (lsa->header->checksum); return SNMP_INTEGER (sum); } return SNMP_INTEGER (0); case OSPFv3ORIGINATENEWLSAS: return SNMP_INTEGER (0); /* Don't know where to get this value... */ case OSPFv3RXNEWLSAS: return SNMP_INTEGER (0); /* Don't know where to get this value... */ case OSPFv3EXTLSACOUNT: if (ospf6) { for (count = 0, lsa = ospf6_lsdb_type_head (htons (OSPF6_LSTYPE_AS_EXTERNAL), ospf6->lsdb); lsa; lsa = ospf6_lsdb_type_next (htons (OSPF6_LSTYPE_AS_EXTERNAL), lsa)) count += 1; return SNMP_INTEGER (count); } return SNMP_INTEGER (0); case OSPFv3EXTAREALSDBLIMIT: return SNMP_INTEGER (-1); case OSPFv3EXITOVERFLOWINTERVAL: return SNMP_INTEGER (0); /* Not supported */ case OSPFv3DEMANDEXTENSIONS: return SNMP_INTEGER (0); /* Not supported */ case OSPFv3REFERENCEBANDWIDTH: if (ospf6) return SNMP_INTEGER (ospf6->ref_bandwidth); /* Otherwise, like for "not implemented". */ case OSPFv3RESTARTSUPPORT: case OSPFv3RESTARTINTERVAL: case OSPFv3RESTARTSTRICTLSACHECKING: case OSPFv3RESTARTSTATUS: case OSPFv3RESTARTAGE: case OSPFv3RESTARTEXITREASON: case OSPFv3NOTIFICATIONENABLE: case OSPFv3STUBROUTERSUPPORT: case OSPFv3STUBROUTERADVERTISEMENT: case OSPFv3DISCONTINUITYTIME: case OSPFv3RESTARTTIME: /* TODO: Not implemented */ 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; struct ospf6_lsa *lsa = NULL; u_int32_t area_id = 0; u_int32_t count; u_int16_t sum; struct listnode *node; unsigned int len; char a[16]; struct ospf6_route *ro; if (ospf6 == NULL) return NULL; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; len = *length - v->namelen; len = (len >= 1 ? 1 : 0); if (exact && len != 1) return NULL; if (len) area_id = htonl (name[v->namelen]); inet_ntop (AF_INET, &area_id, a, sizeof (a)); zlog_debug ("SNMP access by area: %s, exact=%d len=%d length=%lu", a, exact, len, (u_long)*length); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { 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 + 1; name[v->namelen] = ntohl (area->area_id); inet_ntop (AF_INET, &area->area_id, a, sizeof (a)); zlog_debug ("SNMP found area: %s, exact=%d len=%d length=%lu", a, exact, len, (u_long)*length); switch (v->magic) { case OSPFv3IMPORTASEXTERN: /* No NSSA support */ return SNMP_INTEGER (IS_AREA_STUB(area)?2:1); case OSPFv3AREASPFRUNS: return SNMP_INTEGER (area->spf_calculation); case OSPFv3AREABDRRTRCOUNT: case OSPFv3AREAASBDRRTRCOUNT: count = 0; for (ro = ospf6_route_head (ospf6->brouter_table); ro; ro = ospf6_route_next (ro)) { if (ntohl (ro->path.area_id) != ntohl (area->area_id)) continue; if (v->magic == OSPFv3AREABDRRTRCOUNT && CHECK_FLAG (ro->path.router_bits, OSPF6_ROUTER_BIT_B)) count++; if (v->magic == OSPFv3AREAASBDRRTRCOUNT && CHECK_FLAG (ro->path.router_bits, OSPF6_ROUTER_BIT_E)) count++; } return SNMP_INTEGER (count); case OSPFv3AREASCOPELSACOUNT: return SNMP_INTEGER (area->lsdb->count); case OSPFv3AREASCOPELSACKSUMSUM: for (sum = 0, lsa = ospf6_lsdb_head (area->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) sum += ntohs (lsa->header->checksum); return SNMP_INTEGER (sum); case OSPFv3AREASUMMARY: return SNMP_INTEGER (2); /* sendAreaSummary */ case OSPFv3AREAROWSTATUS: return SNMP_INTEGER (1); /* Active */ case OSPFv3AREASTUBMETRIC: case OSPFv3AREANSSATRANSLATORROLE: case OSPFv3AREANSSATRANSLATORSTATE: case OSPFv3AREANSSATRANSLATORSTABINTERVAL: case OSPFv3AREANSSATRANSLATOREVENTS: case OSPFv3AREASTUBMETRICTYPE: case OSPFv3AREATEENABLED: /* Not implemented. */ return NULL; } return NULL; } static int if_icmp_func (struct interface *ifp1, struct interface *ifp2) { return (ifp1->ifindex - ifp2->ifindex); } static u_char * ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_lsa *lsa = NULL; ifindex_t ifindex, area_id, id, instid, adv_router; u_int16_t type; int len; oid *offset; int offsetlen; struct ospf6_area *oa = NULL; struct listnode *node; struct interface *iif; struct ospf6_interface *oi = NULL; struct list *ifslist; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; instid = ifindex = area_id = type = id = adv_router = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; if (exact && (v->magic & OSPFv3WWASTABLE) && offsetlen != 3) return NULL; if (exact && (v->magic & OSPFv3WWAREATABLE) && offsetlen != 4) return NULL; if (exact && (v->magic & OSPFv3WWLINKTABLE) && offsetlen != 5) return NULL; if (v->magic & OSPFv3WWLINKTABLE) { /* Parse ifindex */ len = (offsetlen < 1 ? 0 : 1); if (len) ifindex = *offset; offset += len; offsetlen -= len; /* Parse instance ID */ len = (offsetlen < 1 ? 0 : 1); if (len) instid = *offset; offset += len; offsetlen -= len; } else if (v->magic & OSPFv3WWAREATABLE) { /* Parse area-id */ len = (offsetlen < 1 ? 0 : 1); if (len) area_id = htonl (*offset); offset += len; offsetlen -= len; } /* Parse type */ len = (offsetlen < 1 ? 0 : 1); if (len) type = htons (*offset); offset += len; offsetlen -= len; /* Parse Router-ID */ len = (offsetlen < 1 ? 0 : 1); if (len) adv_router = htonl (*offset); offset += len; offsetlen -= len; /* Parse LS-ID */ len = (offsetlen < 1 ? 0 : 1); if (len) id = htonl (*offset); offset += len; offsetlen -= len; if (exact) { if (v->magic & OSPFv3WWASTABLE) { lsa = ospf6_lsdb_lookup (type, id, adv_router, ospf6->lsdb); } else if (v->magic & OSPFv3WWAREATABLE) { oa = ospf6_area_lookup (area_id, ospf6); if (!oa) return NULL; lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb); } else if (v->magic & OSPFv3WWLINKTABLE) { oi = ospf6_interface_lookup_by_ifindex (ifindex); if (!oi || oi->instance_id != instid) return NULL; lsa = ospf6_lsdb_lookup (type, id, adv_router, oi->lsdb); } } else { if (v->magic & OSPFv3WWASTABLE) { if (ospf6->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, ospf6->lsdb); } else if (v->magic & OSPFv3WWAREATABLE) for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { if (oa->area_id < area_id) continue; if (oa->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, oa->lsdb); if (lsa) break; type = 0; id = 0; adv_router = 0; } else if (v->magic & OSPFv3WWLINKTABLE) { /* We build a sorted list of interfaces */ ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; for (ALL_LIST_ELEMENTS_RO (iflist, node, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, node, iif)) { if (!iif->ifindex) continue; oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); if (!oi) continue; if (iif->ifindex < ifindex) continue; if (oi->instance_id < instid) continue; if (oi->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, oi->lsdb); if (lsa) break; type = 0; id = 0; adv_router = 0; oi = NULL; } list_delete_all_node (ifslist); } } if (! lsa) return NULL; /* Add indexes */ if (v->magic & OSPFv3WWASTABLE) { *length = v->namelen + 3; offset = name + v->namelen; } else if (v->magic & OSPFv3WWAREATABLE) { *length = v->namelen + 4; offset = name + v->namelen; *offset = ntohl (oa->area_id); offset++; } else if (v->magic & OSPFv3WWLINKTABLE) { *length = v->namelen + 5; offset = name + v->namelen; *offset = oi->interface->ifindex; offset++; *offset = oi->instance_id; offset++; } *offset = ntohs (lsa->header->type); offset++; *offset = ntohl (lsa->header->adv_router); offset++; *offset = ntohl (lsa->header->id); offset++; /* Return the current value of the variable */ switch (v->magic & OSPFv3WWCOLUMN) { case OSPFv3WWLSDBSEQUENCE: return SNMP_INTEGER (ntohl (lsa->header->seqnum)); break; case OSPFv3WWLSDBAGE: ospf6_lsa_age_current (lsa); return SNMP_INTEGER (ntohs (lsa->header->age)); break; case OSPFv3WWLSDBCHECKSUM: return SNMP_INTEGER (ntohs (lsa->header->checksum)); break; case OSPFv3WWLSDBADVERTISEMENT: *var_len = ntohs (lsa->header->length); return (u_char *) lsa->header; break; case OSPFv3WWLSDBTYPEKNOWN: return SNMP_INTEGER (OSPF6_LSA_IS_KNOWN (lsa->header->type) ? SNMP_TRUE : SNMP_FALSE); break; } return NULL; } static u_char * ospfv3IfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { ifindex_t ifindex = 0; unsigned int instid = 0; struct ospf6_interface *oi = NULL; struct ospf6_lsa *lsa = NULL; struct interface *iif; struct listnode *i; struct list *ifslist; oid *offset; int offsetlen, len; u_int32_t sum; if (smux_header_table (v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; if (exact && offsetlen != 2) return NULL; /* Parse if index */ len = (offsetlen < 1 ? 0 : 1); if (len) ifindex = *offset; offset += len; offsetlen -= len; /* Parse instance ID */ len = (offsetlen < 1 ? 0 : 1); if (len) instid = *offset; offset += len; offsetlen -= len; if (exact) { oi = ospf6_interface_lookup_by_ifindex (ifindex); if (!oi || oi->instance_id != instid) return NULL; } else { /* We build a sorted list of interfaces */ ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; for (ALL_LIST_ELEMENTS_RO (iflist, i, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, i, iif)) { if (!iif->ifindex) continue; oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); if (!oi) continue; if (iif->ifindex > ifindex || (iif->ifindex == ifindex && (oi->instance_id > instid))) break; oi = NULL; } list_delete_all_node (ifslist); } if (!oi) return NULL; /* Add Index (IfIndex, IfInstId) */ *length = v->namelen + 2; offset = name + v->namelen; *offset = oi->interface->ifindex; offset++; *offset = oi->instance_id; offset++; /* Return the current value of the variable */ switch (v->magic) { case OSPFv3IFAREAID: if (oi->area) return SNMP_INTEGER (ntohl (oi->area->area_id)); break; case OSPFv3IFTYPE: if (if_is_broadcast (oi->interface)) return SNMP_INTEGER (1); else if (if_is_pointopoint (oi->interface)) return SNMP_INTEGER (3); else break; /* Unknown, don't put anything */ case OSPFv3IFADMINSTATUS: if (oi->area) return SNMP_INTEGER (OSPF_STATUS_ENABLED); return SNMP_INTEGER (OSPF_STATUS_DISABLED); case OSPFv3IFRTRPRIORITY: return SNMP_INTEGER (oi->priority); case OSPFv3IFTRANSITDELAY: return SNMP_INTEGER (oi->transdelay); case OSPFv3IFRETRANSINTERVAL: return SNMP_INTEGER (oi->rxmt_interval); case OSPFv3IFHELLOINTERVAL: return SNMP_INTEGER (oi->hello_interval); case OSPFv3IFRTRDEADINTERVAL: return SNMP_INTEGER (oi->dead_interval); case OSPFv3IFPOLLINTERVAL: /* No support for NBMA */ break; case OSPFv3IFSTATE: return SNMP_INTEGER (oi->state); case OSPFv3IFDESIGNATEDROUTER: return SNMP_INTEGER (ntohl (oi->drouter)); case OSPFv3IFBACKUPDESIGNATEDROUTER: return SNMP_INTEGER (ntohl (oi->bdrouter)); case OSPFv3IFEVENTS: return SNMP_INTEGER (oi->state_change); case OSPFv3IFROWSTATUS: return SNMP_INTEGER (1); case OSPFv3IFDEMAND: return SNMP_INTEGER (SNMP_FALSE); case OSPFv3IFMETRICVALUE: return SNMP_INTEGER (oi->cost); case OSPFv3IFLINKSCOPELSACOUNT: return SNMP_INTEGER (oi->lsdb->count); case OSPFv3IFLINKLSACKSUMSUM: for (sum = 0, lsa = ospf6_lsdb_head (oi->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) sum += ntohs (lsa->header->checksum); return SNMP_INTEGER (sum); case OSPFv3IFDEMANDNBRPROBE: case OSPFv3IFDEMANDNBRPROBERETRANSLIMIT: case OSPFv3IFDEMANDNBRPROBEINTERVAL: case OSPFv3IFTEDISABLED: case OSPFv3IFLINKLSASUPPRESSION: /* Not implemented. Only works if all the last ones are not implemented! */ return NULL; } /* Try an internal getnext. Some columns are missing in this table. */ if (!exact && (name[*length-1] < MAX_SUBID)) return ospfv3IfEntry(v, name, length, exact, var_len, write_method); return NULL; } static u_char * ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { ifindex_t ifindex = 0; unsigned int instid, rtrid; struct ospf6_interface *oi = NULL; struct ospf6_neighbor *on = NULL; struct interface *iif; struct listnode *i, *j; struct list *ifslist; oid *offset; int offsetlen, len; if (smux_header_table (v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; instid = rtrid = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; if (exact && offsetlen != 3) return NULL; /* Parse if index */ len = (offsetlen < 1 ? 0 : 1); if (len) ifindex = *offset; offset += len; offsetlen -= len; /* Parse instance ID */ len = (offsetlen < 1 ? 0 : 1); if (len) instid = *offset; offset += len; offsetlen -= len; /* Parse router ID */ len = (offsetlen < 1 ? 0 : 1); if (len) rtrid = htonl (*offset); offset += len; offsetlen -= len; if (exact) { oi = ospf6_interface_lookup_by_ifindex (ifindex); if (!oi || oi->instance_id != instid) return NULL; on = ospf6_neighbor_lookup (rtrid, oi); } else { /* We build a sorted list of interfaces */ ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; for (ALL_LIST_ELEMENTS_RO (iflist, i, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, i, iif)) { if (!iif->ifindex) continue; oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); if (!oi) continue; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) { if (iif->ifindex > ifindex || (iif->ifindex == ifindex && (oi->instance_id > instid || (oi->instance_id == instid && ntohl (on->router_id) > ntohl (rtrid))))) break; } if (on) break; oi = NULL; on = NULL; } list_delete_all_node (ifslist); } if (!oi || !on) return NULL; /* Add Index (IfIndex, IfInstId, RtrId) */ *length = v->namelen + 3; offset = name + v->namelen; *offset = oi->interface->ifindex; offset++; *offset = oi->instance_id; offset++; *offset = ntohl (on->router_id); offset++; /* Return the current value of the variable */ switch (v->magic) { case OSPFv3NBRADDRESSTYPE: return SNMP_INTEGER (2); /* IPv6 only */ case OSPFv3NBRADDRESS: *var_len = sizeof (struct in6_addr); return (u_char *) &on->linklocal_addr; case OSPFv3NBROPTIONS: return SNMP_INTEGER (on->options[2]); case OSPFv3NBRPRIORITY: return SNMP_INTEGER (on->priority); case OSPFv3NBRSTATE: return SNMP_INTEGER (on->state); case OSPFv3NBREVENTS: return SNMP_INTEGER (on->state_change); case OSPFv3NBRLSRETRANSQLEN: return SNMP_INTEGER (on->retrans_list->count); case OSPFv3NBRHELLOSUPPRESSED: return SNMP_INTEGER (SNMP_FALSE); case OSPFv3NBRIFID: return SNMP_INTEGER (on->ifindex); case OSPFv3NBRRESTARTHELPERSTATUS: case OSPFv3NBRRESTARTHELPERAGE: case OSPFv3NBRRESTARTHELPEREXITREASON: /* Not implemented. Only works if all the last ones are not implemented! */ return NULL; } return NULL; } /* OSPF Traps. */ #define NBRSTATECHANGE 2 #define IFSTATECHANGE 10 static struct trap_object ospf6NbrTrapList[] = { {-3, {1, 1, OSPFv3ROUTERID}}, {4, {1, 9, 1, OSPFv3NBRADDRESSTYPE}}, {4, {1, 9, 1, OSPFv3NBRADDRESS}}, {4, {1, 9, 1, OSPFv3NBRSTATE}} }; static struct trap_object ospf6IfTrapList[] = { {-3, {1, 1, OSPFv3ROUTERID}}, {4, {1, 7, 1, OSPFv3IFSTATE}}, {4, {1, 7, 1, OSPFv3IFADMINSTATUS}}, {4, {1, 7, 1, OSPFv3IFAREAID}} }; void ospf6TrapNbrStateChange (struct ospf6_neighbor *on) { oid index[3]; index[0] = on->ospf6_if->interface->ifindex; index[1] = on->ospf6_if->instance_id; index[2] = ntohl (on->router_id); smux_trap (ospfv3_variables, sizeof ospfv3_variables / sizeof (struct variable), ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof (oid), ospfv3_oid, sizeof ospfv3_oid / sizeof (oid), index, 3, ospf6NbrTrapList, sizeof ospf6NbrTrapList / sizeof (struct trap_object), NBRSTATECHANGE); } void ospf6TrapIfStateChange (struct ospf6_interface *oi) { oid index[2]; index[0] = oi->interface->ifindex; index[1] = oi->instance_id; smux_trap (ospfv3_variables, sizeof ospfv3_variables / sizeof (struct variable), ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof (oid), ospfv3_oid, sizeof ospfv3_oid / sizeof (oid), index, 2, ospf6IfTrapList, sizeof ospf6IfTrapList / sizeof (struct trap_object), IFSTATECHANGE); } /* Register OSPFv3-MIB. */ void ospf6_snmp_init (struct thread_master *master) { smux_init (master); REGISTER_MIB ("OSPFv3MIB", ospfv3_variables, variable, ospfv3_oid); } #endif /* HAVE_SNMP */ quagga-1.2.4/ospf6d/ospf6_snmp.h000066400000000000000000000020641325323223500164310ustar00rootroot00000000000000/* 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 extern void ospf6TrapNbrStateChange (struct ospf6_neighbor *); extern void ospf6TrapIfStateChange (struct ospf6_interface *); extern void ospf6_snmp_init (struct thread_master *); #endif /*OSPF6_SNMP_H*/ quagga-1.2.4/ospf6d/ospf6_spf.c000066400000000000000000000641401325323223500162420ustar00rootroot00000000000000/* * 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" #include "ospf6_abr.h" unsigned char conf_debug_ospf6_spf = 0; static 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 */ if (va->cost != vb->cost) return (va->cost - vb->cost); return (va->hops - vb->hops); } static 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; } static 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; } static void ospf6_vertex_delete (struct ospf6_vertex *v) { list_delete (v->child_list); XFREE (MTYPE_OSPF6_VERTEX, v); } static 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_debug (" Link to: %s", lsa->name); else zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA", ospf6_lstype_name (type), ibuf, abuf); } return lsa; } static 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_debug (" Backlink %s", (found ? "OK" : "FAIL")); return found; } static void ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, caddr_t lsdesc) { int i; ifindex_t 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 : /* v is the local router & the interface_id is a local ifindex */ (ifindex_t) ROUTER_LSDESC_GET_IFID (lsdesc)); assert (ifindex >= 0); oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("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_debug (" 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_debug ("No nexthop for %s found", w->name); } static 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; if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("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_debug (" 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_debug (" another path found, merge"); for (i = 0; i < OSPF6_MULTI_PATH_LIMIT && ospf6_nexthop_is_set (&v->nexthop[i]); 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; assert (prev->hops <= v->hops); 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; i < OSPF6_MULTI_PATH_LIMIT && ospf6_nexthop_is_set (&v->nexthop[i]); 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, *nroute; struct ospf6_vertex *v; for (route = ospf6_route_head (result_table); route; route = nroute) { nroute = ospf6_route_next (route); v = (struct ospf6_vertex *) route->route_option; ospf6_vertex_delete (v); ospf6_route_remove (route, result_table); } } static const char *ospf6_spf_reason_str[] = { "R+", "R-", "N+", "N-", "L+", "L-", "R*", "N*", }; void ospf6_spf_reason_string (unsigned int reason, char *buf, int size) { size_t bit; int len = 0; if (!buf) return; for (bit = 0; bit < array_size(ospf6_spf_reason_str); bit++) { if ((reason & (1 << bit)) && (len < size)) { len += snprintf((buf + len), (size - len), "%s%s", (len > 0) ? ", " : "", ospf6_spf_reason_str[bit]); } } } /* 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; 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; /* initialize */ candidate_list = pqueue_create (); candidate_list->cmp = ospf6_vertex_cmp; 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; /* Skip overloaded routers */ if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) && ospf6_router_is_stub_router (v->lsa))) 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; i < OSPF6_MULTI_PATH_LIMIT && ospf6_nexthop_is_set (&v->nexthop[i]); i++) ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]); } /* add new candidate to the candidate_list */ if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug (" New candidate: %s hops %d cost %d", w->name, w->hops, w->cost); pqueue_enqueue (w, candidate_list); } } pqueue_delete (candidate_list); oa->spf_calculation++; } static void ospf6_spf_log_database (struct ospf6_area *oa) { char *p, *end, buffer[256]; struct 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 (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi)) { snprintf (p, end - p, " I/F %s: %d", oi->interface->name, oi->lsdb->count); p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end); } zlog_debug ("%s", buffer); } static int ospf6_spf_calculation_thread (struct thread *t) { struct ospf6_area *oa; struct ospf6 *ospf6; struct timeval start, end, runtime; struct listnode *node; struct ospf6_route *route; int areas_processed = 0; char rbuf[32]; ospf6 = (struct ospf6 *)THREAD_ARG (t); ospf6->t_spf_calc = NULL; /* execute SPF calculation */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &start); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { if (oa == ospf6->backbone) continue; if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("SPF calculation for Area %s", oa->name); if (IS_OSPF6_DEBUG_SPF (DATABASE)) ospf6_spf_log_database (oa); ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa); ospf6_intra_route_calculation (oa); ospf6_intra_brouter_calculation (oa); areas_processed++; } if (ospf6->backbone) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("SPF calculation for Backbone area %s", ospf6->backbone->name); if (IS_OSPF6_DEBUG_SPF (DATABASE)) ospf6_spf_log_database(ospf6->backbone); ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table, ospf6->backbone); ospf6_intra_route_calculation(ospf6->backbone); ospf6_intra_brouter_calculation(ospf6->backbone); areas_processed++; } /* Redo summaries if required */ for (route = ospf6_route_head (ospf6->route_table); route; route = ospf6_route_next (route)) ospf6_abr_originate_summary(route); quagga_gettime (QUAGGA_CLK_MONOTONIC, &end); timersub (&end, &start, &runtime); ospf6->ts_spf_duration = runtime; ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf)); if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF runtime: %lld sec %lld usec", (long long)runtime.tv_sec, (long long)runtime.tv_usec); zlog_info("SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, " "Reason: %s\n", areas_processed, (long long)runtime.tv_sec, (long long)runtime.tv_usec, rbuf); ospf6->last_spf_reason = ospf6->spf_reason; ospf6_reset_spf_reason(ospf6); return 0; } /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer for SPF calc. */ void ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason) { unsigned long delay, elapsed, ht; struct timeval now, result; ospf6_set_spf_reason(ospf6, reason); if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) { char rbuf[32]; ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf)); zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf); } /* OSPF instance does not exist. */ if (ospf6 == NULL) return; /* SPF calculation timer is already scheduled. */ if (ospf6->t_spf_calc) { if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF: calculation timer is already scheduled: %p", (void *)ospf6->t_spf_calc); return; } /* XXX Monotic timers: we only care about relative time here. */ now = recent_relative_time (); timersub (&now, &ospf6->ts_spf, &result); elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000); ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier; if (ht > ospf6->spf_max_holdtime) ht = ospf6->spf_max_holdtime; /* Get SPF calculation delay time. */ if (elapsed < ht) { /* Got an event within the hold time of last SPF. We need to * increase the hold_multiplier, if it's not already at/past * maximum value, and wasn't already increased.. */ if (ht < ospf6->spf_max_holdtime) ospf6->spf_hold_multiplier++; /* always honour the SPF initial delay */ if ( (ht - elapsed) < ospf6->spf_delay) delay = ospf6->spf_delay; else delay = ht - elapsed; } else { /* Event is past required hold-time of last SPF */ delay = ospf6->spf_delay; ospf6->spf_hold_multiplier = 1; } if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF: calculation timer delay = %ld", delay); zlog_info ("SPF: Scheduled in %ld msec", delay); ospf6->t_spf_calc = thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay); } void ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest, struct ospf6_vertex *v) { struct listnode *node, *nnode; 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); for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c)) { 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; } static int ospf6_timers_spf_set (struct vty *vty, unsigned int delay, unsigned int hold, unsigned int max) { struct ospf6 *ospf = vty->index; ospf->spf_delay = delay; ospf->spf_holdtime = hold; ospf->spf_max_holdtime = max; return CMD_SUCCESS; } DEFUN (ospf6_timers_throttle_spf, ospf6_timers_throttle_spf_cmd, "timers throttle spf <0-600000> <0-600000> <0-600000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF6 SPF timers\n" "Delay (msec) from first change received till SPF calculation\n" "Initial hold time (msec) between consecutive SPF calculations\n" "Maximum hold time (msec)\n") { unsigned int delay, hold, max; if (argc != 3) { vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000); VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000); VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000); return ospf6_timers_spf_set (vty, delay, hold, max); } DEFUN (no_ospf6_timers_throttle_spf, no_ospf6_timers_throttle_spf_cmd, "no timers throttle spf", NO_STR "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF6 SPF timers\n") { return ospf6_timers_spf_set (vty, OSPF_SPF_DELAY_DEFAULT, OSPF_SPF_HOLDTIME_DEFAULT, OSPF_SPF_MAX_HOLDTIME_DEFAULT); } 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 ospf6_spf_config_write (struct vty *vty) { if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT || ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT || ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT) vty_out (vty, " timers throttle spf %d %d %d%s", ospf6->spf_delay, ospf6->spf_holdtime, ospf6->spf_max_holdtime, VTY_NEWLINE); } void install_element_ospf6_debug_spf (void) { 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 (void) { install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd); install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd); } quagga-1.2.4/ospf6d/ospf6_spf.h000066400000000000000000000107461325323223500162520ustar00rootroot00000000000000/* * 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 #include "ospf6_top.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; struct 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) /* What triggered the SPF? */ #define OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED (1 << 0) #define OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED (1 << 1) #define OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED (1 << 2) #define OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED (1 << 3) #define OSPF6_SPF_FLAGS_LINK_LSA_ADDED (1 << 4) #define OSPF6_SPF_FLAGS_LINK_LSA_REMOVED (1 << 5) #define OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED (1 << 6) #define OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED (1 << 7) static inline void ospf6_set_spf_reason (struct ospf6* ospf, unsigned int reason) { ospf->spf_reason |= reason; } static inline void ospf6_reset_spf_reason (struct ospf6 *ospf) { ospf->spf_reason = 0; } static inline unsigned int ospf6_lsadd_to_spf_reason (struct ospf6_lsa *lsa) { unsigned int reason = 0; switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_ROUTER: reason = OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED; break; case OSPF6_LSTYPE_NETWORK: reason = OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED; break; case OSPF6_LSTYPE_LINK: reason = OSPF6_SPF_FLAGS_LINK_LSA_ADDED; break; default: break; } return (reason); } static inline unsigned int ospf6_lsremove_to_spf_reason (struct ospf6_lsa *lsa) { unsigned int reason = 0; switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_ROUTER: reason = OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED; break; case OSPF6_LSTYPE_NETWORK: reason = OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED; break; case OSPF6_LSTYPE_LINK: reason = OSPF6_SPF_FLAGS_LINK_LSA_REMOVED; break; default: break; } return (reason); } extern void ospf6_spf_table_finish (struct ospf6_route_table *result_table); extern void ospf6_spf_calculation (u_int32_t router_id, struct ospf6_route_table *result_table, struct ospf6_area *oa); extern void ospf6_spf_schedule (struct ospf6 *ospf, unsigned int reason); extern void ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest, struct ospf6_vertex *v); extern void ospf6_spf_config_write (struct vty *vty); extern int config_write_ospf6_debug_spf (struct vty *vty); extern void install_element_ospf6_debug_spf (void); extern void ospf6_spf_init (void); extern void ospf6_spf_reason_string (unsigned int reason, char *buf, int size); #endif /* OSPF6_SPF_H */ quagga-1.2.4/ospf6d/ospf6_top.c000066400000000000000000001144261325323223500162570ustar00rootroot00000000000000/* * 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 "ospf6_spf.h" #include "ospf6d.h" /* global ospf6d variable */ struct ospf6 *ospf6; static void ospf6_disable (struct ospf6 *o); static 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; } } static 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; } } static void ospf6_top_route_hook_add (struct ospf6_route *route) { ospf6_abr_originate_summary (route); ospf6_zebra_route_update_add (route); } static void ospf6_top_route_hook_remove (struct ospf6_route *route) { ospf6_abr_originate_summary (route); ospf6_zebra_route_update_remove (route); } static 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); } static 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); } static struct ospf6 * ospf6_create (void) { struct ospf6 *o; o = XCALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6)); /* initialize */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &o->starttime); 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->spf_delay = OSPF_SPF_DELAY_DEFAULT; o->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; o->spf_max_holdtime = OSPF_SPF_MAX_HOLDTIME_DEFAULT; o->spf_hold_multiplier = 1; o->route_table = OSPF6_ROUTE_TABLE_CREATE (GLOBAL, ROUTES); o->route_table->scope = o; 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 (GLOBAL, BORDER_ROUTERS); o->brouter_table->scope = o; 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 (GLOBAL, EXTERNAL_ROUTES); o->external_table->scope = o; o->external_id_table = route_table_init (); o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; o->distance_table = route_table_init (); return o; } void ospf6_delete (struct ospf6 *o) { struct listnode *node, *nnode; struct ospf6_area *oa; ospf6_disable (ospf6); for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa)) ospf6_area_delete (oa); list_delete (o->area_list); 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); ospf6_distance_reset (o); route_table_finish (o->distance_table); XFREE (MTYPE_OSPF6_TOP, o); } static void __attribute__((unused)) ospf6_enable (struct ospf6 *o) { struct listnode *node, *nnode; struct ospf6_area *oa; if (CHECK_FLAG (o->flag, OSPF6_DISABLED)) { UNSET_FLAG (o->flag, OSPF6_DISABLED); for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa)) ospf6_area_enable (oa); } } static void ospf6_disable (struct ospf6 *o) { struct listnode *node, *nnode; struct ospf6_area *oa; if (! CHECK_FLAG (o->flag, OSPF6_DISABLED)) { SET_FLAG (o->flag, OSPF6_DISABLED); for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa)) ospf6_area_disable (oa); /* XXX: This also changes persistent settings */ ospf6_asbr_redistribute_reset(); ospf6_lsdb_remove_all (o->lsdb); ospf6_route_remove_all (o->route_table); ospf6_route_remove_all (o->brouter_table); THREAD_OFF(o->maxage_remover); THREAD_OFF(o->t_spf_calc); THREAD_OFF(o->t_ase_calc); } } static 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; struct listnode *i, *j, *k; int reschedule = 0; o->maxage_remover = (struct thread *) NULL; for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on)) { if (on->state != OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_LOADING) continue; ospf6_maxage_remove (o); return 0; } } } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { if (ospf6_lsdb_maxage_remover (oi->lsdb)) { reschedule = 1; } } if (ospf6_lsdb_maxage_remover (oa->lsdb)) { reschedule = 1; } } if (ospf6_lsdb_maxage_remover (o->lsdb)) { reschedule = 1; } if (reschedule) { ospf6_maxage_remove (o); } return 0; } void ospf6_maxage_remove (struct ospf6 *o) { if (o && ! o->maxage_remover) o->maxage_remover = thread_add_timer (master, ospf6_maxage_remover, o, OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT); } /* start ospf6 */ DEFUN (router_ospf6, router_ospf6_cmd, "router ospf6", ROUTER_STR OSPF6_STR) { if (ospf6 == NULL) ospf6 = ospf6_create (); /* 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) vty_out (vty, "OSPFv3 is not configured%s", VNL); else { ospf6_delete (ospf6); ospf6 = NULL; } /* 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_static = router_id; if (o->router_id == 0) o->router_id = router_id; return CMD_SUCCESS; } DEFUN (ospf6_log_adjacency_changes, ospf6_log_adjacency_changes_cmd, "log-adjacency-changes", "Log changes in adjacency state\n") { struct ospf6 *ospf6 = vty->index; SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); return CMD_SUCCESS; } DEFUN (ospf6_log_adjacency_changes_detail, ospf6_log_adjacency_changes_detail_cmd, "log-adjacency-changes detail", "Log changes in adjacency state\n" "Log all state changes\n") { struct ospf6 *ospf6 = vty->index; SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); return CMD_SUCCESS; } DEFUN (no_ospf6_log_adjacency_changes, no_ospf6_log_adjacency_changes_cmd, "no log-adjacency-changes", NO_STR "Log changes in adjacency state\n") { struct ospf6 *ospf6 = vty->index; UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); return CMD_SUCCESS; } DEFUN (no_ospf6_log_adjacency_changes_detail, no_ospf6_log_adjacency_changes_detail_cmd, "no log-adjacency-changes detail", NO_STR "Log changes in adjacency state\n" "Log all state changes\n") { struct ospf6 *ospf6 = vty->index; UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); return CMD_SUCCESS; } DEFUN (ospf6_distance, ospf6_distance_cmd, "distance <1-255>", NO_STR "Define an administrative distance\n" "OSPF6 Administrative distance\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_all = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (no_ospf6_distance, no_ospf6_distance_cmd, "no distance <1-255>", NO_STR "Define an administrative distance\n" "OSPF6 Administrative distance\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_all = 0; return CMD_SUCCESS; } DEFUN (no_ospf6_distance_ospf6, no_ospf6_distance_ospf6_cmd, "no distance ospf6", NO_STR "Define an administrative distance\n" "OSPF6 Administrative distance\n" "OSPF6 Distance\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_intra = 0; o->distance_inter = 0; o->distance_external = 0; return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_intra, ospf6_distance_ospf6_intra_cmd, "distance ospf6 intra-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_intra = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_intra_inter, ospf6_distance_ospf6_intra_inter_cmd, "distance ospf6 intra-area <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "Inter-area routes\n" "Distance for inter-area routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_intra = atoi (argv[0]); o->distance_inter = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_intra_external, ospf6_distance_ospf6_intra_external_cmd, "distance ospf6 intra-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "External routes\n" "Distance for external routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_intra = atoi (argv[0]); o->distance_external = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_intra_inter_external, ospf6_distance_ospf6_intra_inter_external_cmd, "distance ospf6 intra-area <1-255> inter-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF6 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 ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_intra = atoi (argv[0]); o->distance_inter = atoi (argv[1]); o->distance_external = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_intra_external_inter, ospf6_distance_ospf6_intra_external_inter_cmd, "distance ospf6 intra-area <1-255> external <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF6 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 ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_intra = atoi (argv[0]); o->distance_external = atoi (argv[1]); o->distance_inter = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_inter, ospf6_distance_ospf6_inter_cmd, "distance ospf6 inter-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_inter = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_inter_intra, ospf6_distance_ospf6_inter_intra_cmd, "distance ospf6 inter-area <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "Intra-area routes\n" "Distance for intra-area routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_inter = atoi (argv[0]); o->distance_intra = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_inter_external, ospf6_distance_ospf6_inter_external_cmd, "distance ospf6 inter-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "External routes\n" "Distance for external routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_inter = atoi (argv[0]); o->distance_external = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_inter_intra_external, ospf6_distance_ospf6_inter_intra_external_cmd, "distance ospf6 inter-area <1-255> intra-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF6 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 ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_inter = atoi (argv[0]); o->distance_intra = atoi (argv[1]); o->distance_external = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_inter_external_intra, ospf6_distance_ospf6_inter_external_intra_cmd, "distance ospf6 inter-area <1-255> external <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF6 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 ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_inter = atoi (argv[0]); o->distance_external = atoi (argv[1]); o->distance_intra = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_external, ospf6_distance_ospf6_external_cmd, "distance ospf6 external <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "External routes\n" "Distance for external routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_external = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_external_intra, ospf6_distance_ospf6_external_intra_cmd, "distance ospf6 external <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "External routes\n" "Distance for external routes\n" "Intra-area routes\n" "Distance for intra-area routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_external = atoi (argv[0]); o->distance_intra = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_external_inter, ospf6_distance_ospf6_external_inter_cmd, "distance ospf6 external <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "External routes\n" "Distance for external routes\n" "Inter-area routes\n" "Distance for inter-area routes\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_external = atoi (argv[0]); o->distance_inter = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_external_intra_inter, ospf6_distance_ospf6_external_intra_inter_cmd, "distance ospf6 external <1-255> intra-area <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF6 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 ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_external = atoi (argv[0]); o->distance_intra = atoi (argv[1]); o->distance_inter = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf6_distance_ospf6_external_inter_intra, ospf6_distance_ospf6_external_inter_intra_cmd, "distance ospf6 external <1-255> inter-area <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF6 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 ospf6 *o; o = (struct ospf6 *) vty->index; o->distance_external = atoi (argv[0]); o->distance_inter = atoi (argv[1]); o->distance_intra = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf6_distance_source, ospf6_distance_source_cmd, "distance <1-255> X:X::X:X/M", "Administrative distance\n" "Distance value\n" "IP source prefix\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; ospf6_distance_set (vty, o, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (no_ospf6_distance_source, no_ospf6_distance_source_cmd, "no distance <1-255> X:X::X:X/M", NO_STR "Administrative distance\n" "Distance value\n" "IP source prefix\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; /* XXX: distance arg seems to be irrelevant */ ospf6_distance_unset (vty, o, argv[1], NULL); return CMD_SUCCESS; } DEFUN (ospf6_distance_source_access_list, ospf6_distance_source_access_list_cmd, "distance <1-255> X:X::X:X/M WORD", "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; ospf6_distance_set (vty, o, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (no_ospf6_distance_source_access_list, no_ospf6_distance_source_access_list_cmd, "no distance <1-255> X:X::X:X/M WORD", NO_STR "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") { struct ospf6 *o; o = (struct ospf6 *) vty->index; ospf6_distance_unset (vty, o, argv[1], argv[2]); 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); /* ospf6 process is currently disabled, not much more to do */ if (CHECK_FLAG (o->flag, OSPF6_DISABLED)) return CMD_SUCCESS; /* start up */ ospf6_interface_enable (oi); /* 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_interface *oi; struct ospf6_area *oa; struct interface *ifp; u_int32_t area_id; 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; } /* Verify Area */ if (oi->area == NULL) { vty_out (vty, "No such 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; } DEFUN (ospf6_stub_router_admin, ospf6_stub_router_admin_cmd, "stub-router administrative", "Make router a stub router\n" "Advertise inability to be a transit router\n" "Administratively applied, for an indefinite period\n") { struct listnode *node; struct ospf6_area *oa; if (!CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) { for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_V6); OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_R); OSPF6_ROUTER_LSA_SCHEDULE (oa); } SET_FLAG (ospf6->flag, OSPF6_STUB_ROUTER); } return CMD_SUCCESS; } DEFUN (no_ospf6_stub_router_admin, no_ospf6_stub_router_admin_cmd, "no stub-router administrative", NO_STR "Make router a stub router\n" "Advertise ability to be a transit router\n" "Administratively applied, for an indefinite period\n") { struct listnode *node; struct ospf6_area *oa; if (CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) { for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); OSPF6_ROUTER_LSA_SCHEDULE (oa); } UNSET_FLAG (ospf6->flag, OSPF6_STUB_ROUTER); } return CMD_SUCCESS; } DEFUN (ospf6_stub_router_startup, ospf6_stub_router_startup_cmd, "stub-router on-startup <5-86400>", "Make router a stub router\n" "Advertise inability to be a transit router\n" "Automatically advertise as stub-router on startup of OSPF6\n" "Time (seconds) to advertise self as stub-router\n") { return CMD_SUCCESS; } DEFUN (no_ospf6_stub_router_startup, no_ospf6_stub_router_startup_cmd, "no stub-router on-startup", NO_STR "Make router a stub router\n" "Advertise inability to be a transit router\n" "Automatically advertise as stub-router on startup of OSPF6\n" "Time (seconds) to advertise self as stub-router\n") { return CMD_SUCCESS; } DEFUN (ospf6_stub_router_shutdown, ospf6_stub_router_shutdown_cmd, "stub-router on-shutdown <5-86400>", "Make router a stub router\n" "Advertise inability to be a transit router\n" "Automatically advertise as stub-router before shutdown\n" "Time (seconds) to advertise self as stub-router\n") { return CMD_SUCCESS; } DEFUN (no_ospf6_stub_router_shutdown, no_ospf6_stub_router_shutdown_cmd, "no stub-router on-shutdown", NO_STR "Make router a stub router\n" "Advertise inability to be a transit router\n" "Automatically advertise as stub-router before shutdown\n" "Time (seconds) to advertise self as stub-router\n") { return CMD_SUCCESS; } static void ospf6_show (struct vty *vty, struct ospf6 *o) { struct listnode *n; struct ospf6_area *oa; char router_id[16], duration[32]; struct timeval now, running, result; char buf[32], rbuf[32]; /* 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 */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &o->starttime, &running); timerstring (&running, duration, sizeof (duration)); vty_out (vty, " Running %s%s", duration, VNL); /* Redistribute configuration */ /* XXX */ /* Show SPF parameters */ vty_out(vty, " Initial SPF scheduling delay %d millisec(s)%s" " Minimum hold time between consecutive SPFs %d millsecond(s)%s" " Maximum hold time between consecutive SPFs %d millsecond(s)%s" " Hold time multiplier is currently %d%s", o->spf_delay, VNL, o->spf_holdtime, VNL, o->spf_max_holdtime, VNL, o->spf_hold_multiplier, VNL); vty_out(vty, " SPF algorithm "); if (o->ts_spf.tv_sec || o->ts_spf.tv_usec) { timersub(&now, &o->ts_spf, &result); timerstring(&result, buf, sizeof(buf)); ospf6_spf_reason_string(o->last_spf_reason, rbuf, sizeof(rbuf)); vty_out(vty, "last executed %s ago, reason %s%s", buf, rbuf, VNL); vty_out (vty, " Last SPF duration %lld sec %lld usec%s", (long long)o->ts_spf_duration.tv_sec, (long long)o->ts_spf_duration.tv_usec, VNL); } else vty_out(vty, "has not been run$%s", VNL); threadtimer_string(now, o->t_spf_calc, buf, sizeof(buf)); vty_out (vty, " SPF timer %s%s%s", (o->t_spf_calc ? "due in " : "is "), buf, VNL); if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER)) vty_out (vty, " Router Is Stub Router%s", VNL); /* 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); if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) vty_out(vty, " All adjacency changes are logged%s",VTY_NEWLINE); else vty_out(vty, " Adjacency changes are logged%s",VTY_NEWLINE); } vty_out (vty, "%s",VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (o->area_list, n, oa)) 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_CMD_CHECK_RUNNING (); 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" ) { const char *sargv[CMD_ARGC_MAX]; int i, sargc; OSPF6_CMD_CHECK_RUNNING (); /* 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" ) { const 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_CMD_CHECK_RUNNING (); ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_route_match, show_ipv6_ospf6_route_longer_cmd, "show ipv6 ospf6 route X:X::X:X/M longer", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Specify IPv6 prefix\n" "Display routes longer than the specified route\n" ) DEFUN (show_ipv6_ospf6_route_match_detail, show_ipv6_ospf6_route_longer_detail_cmd, "show ipv6 ospf6 route X:X::X:X/M longer detail", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Specify IPv6 prefix\n" "Display routes longer than the specified route\n" "Detailed information\n" ); 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 "Display Intra-Area routes\n" "Display Inter-Area routes\n" "Display Type-1 External routes\n" "Display 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 "Display Intra-Area routes\n" "Display Inter-Area routes\n" "Display Type-1 External routes\n" "Display Type-2 External routes\n" "Detailed information\n" ) { const 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_CMD_CHECK_RUNNING (); ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } static void ospf6_stub_router_config_write (struct vty *vty) { if (CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) { vty_out (vty, " stub-router administrative%s", VNL); } return; } static int ospf6_distance_config_write (struct vty *vty) { struct route_node *rn; struct ospf6_distance *odistance; if (ospf6->distance_all) vty_out (vty, " distance %d%s", ospf6->distance_all, VTY_NEWLINE); if (ospf6->distance_intra || ospf6->distance_inter || ospf6->distance_external) { vty_out (vty, " distance ospf6"); if (ospf6->distance_intra) vty_out (vty, " intra-area %d", ospf6->distance_intra); if (ospf6->distance_inter) vty_out (vty, " inter-area %d", ospf6->distance_inter); if (ospf6->distance_external) vty_out (vty, " external %d", ospf6->distance_external); vty_out (vty, "%s", VTY_NEWLINE); } for (rn = route_top (ospf6->distance_table); rn; rn = route_next (rn)) if ((odistance = rn->info) != NULL) { char pstr[128]; vty_out (vty, " distance %d %s %s%s", odistance->distance, prefix2str (&rn->p, pstr, sizeof(pstr)), odistance->access_list ? odistance->access_list : "", VTY_NEWLINE); } return 0; } /* OSPF configuration write function. */ static int config_write_ospf6 (struct vty *vty) { char router_id[16]; struct listnode *j, *k; struct ospf6_area *oa; struct ospf6_interface *oi; /* OSPFv6 configuration. */ if (ospf6 == NULL) return CMD_SUCCESS; inet_ntop (AF_INET, &ospf6->router_id_static, router_id, sizeof (router_id)); vty_out (vty, "router ospf6%s", VNL); if (ospf6->router_id_static != 0) vty_out (vty, " router-id %s%s", router_id, VNL); /* log-adjacency-changes flag print. */ if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { vty_out(vty, " log-adjacency-changes"); if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) vty_out(vty, " detail"); vty_out(vty, "%s", VTY_NEWLINE); } if (ospf6->ref_bandwidth != OSPF6_REFERENCE_BANDWIDTH) vty_out (vty, " auto-cost reference-bandwidth %d%s", ospf6->ref_bandwidth / 1000, VNL); ospf6_stub_router_config_write (vty); ospf6_redistribute_config_write (vty); ospf6_area_config_write (vty); ospf6_spf_config_write (vty); ospf6_distance_config_write (vty); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, j, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, k, oi)) vty_out (vty, " interface %s area %s%s", oi->interface->name, oa->name, VNL); } vty_out (vty, "!%s", VNL); return 0; } /* OSPF6 node structure. */ static struct cmd_node ospf6_node = { OSPF6_NODE, "%s(config-ospf6)# ", 1 /* VTYSH */ }; /* Install ospf related commands. */ void ospf6_top_init (void) { /* Install ospf6 top node. */ install_node (&ospf6_node, config_write_ospf6); install_element (VIEW_NODE, &show_ipv6_ospf6_cmd); install_element (CONFIG_NODE, &router_ospf6_cmd); install_element (CONFIG_NODE, &no_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_longer_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_longer_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_cmd); install_element (VIEW_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_log_adjacency_changes_cmd); install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd); install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd); install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_detail_cmd); install_element (OSPF6_NODE, &ospf6_interface_area_cmd); install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd); install_element (OSPF6_NODE, &ospf6_stub_router_admin_cmd); install_element (OSPF6_NODE, &no_ospf6_stub_router_admin_cmd); /* For a later time install_element (OSPF6_NODE, &ospf6_stub_router_startup_cmd); install_element (OSPF6_NODE, &no_ospf6_stub_router_startup_cmd); install_element (OSPF6_NODE, &ospf6_stub_router_shutdown_cmd); install_element (OSPF6_NODE, &no_ospf6_stub_router_shutdown_cmd); */ install_element (OSPF6_NODE, &ospf6_distance_cmd); install_element (OSPF6_NODE, &no_ospf6_distance_cmd); install_element (OSPF6_NODE, &no_ospf6_distance_ospf6_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_inter_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_external_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_inter_external_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_external_inter_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_intra_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_external_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_intra_external_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_external_intra_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_intra_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_inter_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_intra_inter_cmd); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_inter_intra_cmd); install_element (OSPF6_NODE, &ospf6_distance_source_cmd); install_element (OSPF6_NODE, &no_ospf6_distance_source_cmd); install_element (OSPF6_NODE, &ospf6_distance_source_access_list_cmd); install_element (OSPF6_NODE, &no_ospf6_distance_source_access_list_cmd); } quagga-1.2.4/ospf6d/ospf6_top.h000066400000000000000000000056001325323223500162550ustar00rootroot00000000000000/* * 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; /* static router id */ u_int32_t router_id_static; /* start time */ struct timeval starttime; /* list of areas */ struct list *area_list; struct ospf6_area *backbone; /* 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; /* Configured flags */ u_char config_flags; #define OSPF6_LOG_ADJACENCY_CHANGES (1 << 0) #define OSPF6_LOG_ADJACENCY_DETAIL (1 << 1) /* SPF parameters */ unsigned int spf_delay; /* SPF delay time. */ unsigned int spf_holdtime; /* SPF hold time. */ unsigned int spf_max_holdtime; /* SPF maximum-holdtime */ unsigned int spf_hold_multiplier; /* Adaptive multiplier for hold time */ unsigned int spf_reason; /* reason bits while scheduling SPF */ struct timeval ts_spf; /* SPF calculation time stamp. */ struct timeval ts_spf_duration; /* Execution time of last SPF */ unsigned int last_spf_reason; /* Last SPF reason */ /* Threads */ struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ struct thread *maxage_remover; u_int32_t ref_bandwidth; /* Distance parameters */ u_char distance_all; u_char distance_intra; u_char distance_inter; u_char distance_external; struct route_table *distance_table; }; #define OSPF6_DISABLED 0x01 #define OSPF6_STUB_ROUTER 0x02 /* global pointer for OSPF top data structure */ extern struct ospf6 *ospf6; /* prototypes */ extern void ospf6_top_init (void); extern void ospf6_delete (struct ospf6 *o); extern void ospf6_maxage_remove (struct ospf6 *o); #endif /* OSPF6_TOP_H */ quagga-1.2.4/ospf6d/ospf6_zebra.c000066400000000000000000000545711325323223500165640ustar00rootroot00000000000000/* * 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; struct in_addr router_id_zebra; /* Router-id update message from zebra. */ static int ospf6_router_id_update_zebra (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct prefix router_id; struct ospf6 *o = ospf6; zebra_router_id_update_read(zclient->ibuf,&router_id); router_id_zebra = router_id.u.prefix4; if (o == NULL) return 0; if (o->router_id == 0) o->router_id = (u_int32_t) router_id_zebra.s_addr; return 0; } /* redistribute function */ void ospf6_zebra_redistribute (int type) { if (vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return; vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); } void ospf6_zebra_no_redistribute (int type) { if (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return; vrf_bitmap_unset (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT); } /* Inteface addition message from zebra. */ static int ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface add: %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu6); ospf6_interface_if_add (ifp); return 0; } static int ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; if (!(ifp = zebra_interface_state_read (zclient->ibuf, vrf_id))) return 0; if (if_is_up (ifp)) zlog_warn ("Zebra: got delete of %s, but interface is still up", ifp->name); if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface delete: %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu6); ifp->ifindex = IFINDEX_INTERNAL; return 0; } static int ospf6_zebra_if_state_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface state change: " "%s index %d flags %llx metric %d mtu %d bandwidth %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6, ifp->bandwidth); ospf6_interface_state_update (ifp); return 0; } static int ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; char buf[128]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf, vrf_id); if (c == NULL) return 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("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_state_update (c->ifp); ospf6_interface_connected_route_update (c->ifp); } return 0; } static int ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; char buf[128]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf, vrf_id); if (c == NULL) return 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("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); ospf6_interface_state_update (c->ifp); } return 0; } static int ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex; struct prefix_ipv6 p; struct in6_addr *nexthop; unsigned char plength = 0; 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; plength = stream_getc (s); p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, plength); 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 (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) api.tag = stream_getl (s); else api.tag = 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_debug ("Zebra Receive route %s: %s %s nexthop %s ifindex %ld tag %u", (command == ZEBRA_IPV6_ROUTE_ADD ? "add" : "delete"), zebra_route_string(api.type), prefixstr, nexthopstr, ifindex, api.tag); } if (command == ZEBRA_IPV6_ROUTE_ADD) ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p, api.nexthop_num, nexthop, api.tag); 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", vrf_bitmap_check (zclient->default_information, VRF_DEFAULT), VNL); vty_out (vty, " redistribute:"); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (vrf_bitmap_check (zclient->redist[i], VRF_DEFAULT)) vty_out (vty, " %s", zebra_route_string(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. */ static 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 (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) { 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. */ static 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]; int nhcount; struct in6_addr **nexthops; ifindex_t *ifindexes; int i, ret = 0; struct prefix_ipv6 *dest; if (IS_OSPF6_DEBUG_ZEBRA (SEND)) { prefix2str (&request->prefix, buf, sizeof (buf)); zlog_debug ("Send %s route: %s", (type == REM ? "remove" : "add"), buf); } if (zclient->sock < 0) { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) zlog_debug (" 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_debug (" 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_debug (" 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_debug (" 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_debug (" 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)) { const char *ifname; inet_ntop (AF_INET6, &request->nexthop[i].address, buf, sizeof (buf)); ifname = ifindex2ifname (request->nexthop[i].ifindex); zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname, request->nexthop[i].ifindex); } nexthops[i] = &request->nexthop[i].address; ifindexes[i] = request->nexthop[i].ifindex; } api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; 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); if (request->path.tag) { SET_FLAG (api.message, ZAPI_MESSAGE_TAG); api.tag = request->path.tag; } dest = (struct prefix_ipv6 *) &request->prefix; if (type == REM) ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api); else ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, dest, &api); if (ret < 0) zlog_err ("zapi_ipv6_route() %s failed: %s", (type == REM ? "delete" : "add"), safe_strerror (errno)); XFREE (MTYPE_OSPF6_OTHER, nexthops); XFREE (MTYPE_OSPF6_OTHER, ifindexes); return; } void ospf6_zebra_route_update_add (struct ospf6_route *request) { if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) { 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 (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) { 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 (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) return CMD_SUCCESS; vrf_bitmap_set (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT); 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 (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT)) return CMD_SUCCESS; vrf_bitmap_unset (zclient->redist[ZEBRA_ROUTE_OSPF6], VRF_DEFAULT); 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; } static void ospf6_zebra_connected (struct zclient *zclient) { zclient_send_requests (zclient, VRF_DEFAULT); } static struct ospf6_distance * ospf6_distance_new (void) { return XCALLOC (MTYPE_OSPF6_DISTANCE, sizeof (struct ospf6_distance)); } static void ospf6_distance_free (struct ospf6_distance *odistance) { XFREE (MTYPE_OSPF6_DISTANCE, odistance); } int ospf6_distance_set (struct vty *vty, struct ospf6 *o, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix_ipv6 p; u_char distance; struct route_node *rn; struct ospf6_distance *odistance; ret = str2prefix_ipv6 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } distance = atoi (distance_str); /* Get OSPF6 distance node. */ rn = route_node_get (o->distance_table, (struct prefix *) &p); if (rn->info) { odistance = rn->info; route_unlock_node (rn); } else { odistance = ospf6_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 ospf6_distance_unset (struct vty *vty, struct ospf6 *o, const char *ip_str, const char *access_list_str) { int ret; struct prefix_ipv6 p; struct route_node *rn; struct ospf6_distance *odistance; ret = str2prefix_ipv6 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } rn = route_node_lookup (o->distance_table, (struct prefix *) &p); if (!rn) { vty_out (vty, "Cant't find specified prefix%s", VTY_NEWLINE); return CMD_WARNING; } odistance = rn->info; if (odistance->access_list) free (odistance->access_list); ospf6_distance_free (odistance); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); return CMD_SUCCESS; } void ospf6_distance_reset (struct ospf6 *o) { struct route_node *rn; struct ospf6_distance *odistance; for (rn = route_top (o->distance_table); rn; rn = route_next (rn)) if ((odistance = rn->info) != NULL) { if (odistance->access_list) free (odistance->access_list); ospf6_distance_free (odistance); rn->info = NULL; route_unlock_node (rn); } } u_char ospf6_distance_apply (struct ospf6_route *or, struct ospf6 *o) { if (o == NULL) return 0; if (o->distance_intra) if (or->path.type == OSPF6_PATH_TYPE_INTRA) return o->distance_intra; if (o->distance_inter) if (or->path.type == OSPF6_PATH_TYPE_INTER) return o->distance_inter; if (o->distance_external) if(or->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || or->path.type == OSPF6_PATH_TYPE_EXTERNAL2) return o->distance_external; if (o->distance_all) return o->distance_all; return 0; } void ospf6_zebra_init (struct thread_master *master) { /* Allocate zebra structure. */ zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_OSPF6); zclient->zebra_connected = ospf6_zebra_connected; zclient->router_id_update = ospf6_router_id_update_zebra; 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 (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 (void) { 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); } quagga-1.2.4/ospf6d/ospf6_zebra.h000066400000000000000000000046221325323223500165610ustar00rootroot00000000000000/* * 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" #include "ospf6_top.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) /* OSPF6 distance */ struct ospf6_distance { /* Distance value for the IP source prefix */ u_char distance; /* Name of the access-list to be matched */ char *access_list; }; extern struct zclient *zclient; extern void ospf6_zebra_route_update_add (struct ospf6_route *request); extern void ospf6_zebra_route_update_remove (struct ospf6_route *request); extern void ospf6_zebra_redistribute (int); extern void ospf6_zebra_no_redistribute (int); #define ospf6_zebra_is_redistribute(type) \ vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT) extern void ospf6_distance_reset (struct ospf6 *); extern u_char ospf6_distance_apply (struct ospf6_route *, struct ospf6 *); extern int ospf6_distance_set (struct vty *, struct ospf6 *, const char *, const char *, const char *); extern int ospf6_distance_unset (struct vty *, struct ospf6 *, const char *, const char *); extern void ospf6_zebra_init(struct thread_master *); extern int config_write_ospf6_debug_zebra (struct vty *vty); extern void install_element_ospf6_debug_zebra (void); #endif /*OSPF6_ZEBRA_H*/ quagga-1.2.4/ospf6d/ospf6d.c000066400000000000000000001523351325323223500155420ustar00rootroot00000000000000/* * 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; 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; } static struct cmd_node debug_node = { DEBUG_NODE, "", 1 /* VTYSH */ }; static 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_brouter (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, const 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, const 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, NULL, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, NULL, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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; struct 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { 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 (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { 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); if (!ro) { vty_out (vty, "No Route found for Router ID: %s%s", argv[0], VNL); return CMD_SUCCESS; } 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" ) { struct listnode *node; struct ospf6_area *oa; OSPF6_CMD_CHECK_RUNNING (); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { 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" ) { const char *sargv[CMD_ARGC_MAX]; int i, sargc; struct listnode *node; struct ospf6_area *oa; OSPF6_CMD_CHECK_RUNNING (); /* 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 (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { 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 (void) { ospf6_top_init (); ospf6_area_init (); ospf6_interface_init (); ospf6_neighbor_init (); ospf6_zebra_init (master); ospf6_lsa_init (); ospf6_spf_init (); ospf6_intra_init (); ospf6_asbr_init (); ospf6_abr_init (); #ifdef HAVE_SNMP ospf6_snmp_init (master); #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_brouter (); install_element_ospf6_debug_asbr (); install_element_ospf6_debug_abr (); install_element_ospf6_debug_flood (); install_element_ospf6_clear_interface (); install_element (VIEW_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 (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); #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); /* Make ospf protocol socket. */ ospf6_serv_sock (); thread_add_read (master, ospf6_receive, NULL, ospf6_sock); } void ospf6_clean (void) { if (!ospf6) return; if (ospf6->route_table) ospf6_route_remove_all (ospf6->route_table); if (ospf6->brouter_table) ospf6_route_remove_all (ospf6->brouter_table); } quagga-1.2.4/ospf6d/ospf6d.conf.sample000066400000000000000000000021261325323223500175150ustar00rootroot00000000000000! ! 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 ! quagga-1.2.4/ospf6d/ospf6d.h000066400000000000000000000116351325323223500155440ustar00rootroot00000000000000/* * 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.7r" #include "libospf.h" #include "thread.h" /* global variables */ extern struct thread_master *master; /* 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 */ #define MSG_OK 0 #define MSG_NG 1 /* cast macro: XXX - these *must* die, ick ick. */ #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, "%lldd%02lld:%02lld:%02lld", \ (tv)->tv_sec / 60LL / 60 / 24, \ (tv)->tv_sec / 60LL / 60 % 24, \ (tv)->tv_sec / 60LL % 60, \ (tv)->tv_sec % 60LL); \ else \ snprintf (buf, size, "%02lld:%02lld:%02lld", \ (tv)->tv_sec / 60LL / 60 % 24, \ (tv)->tv_sec / 60LL % 60, \ (tv)->tv_sec % 60LL); \ } 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) #define threadtimer_string(now, t, buf, size) \ do { \ struct timeval result; \ if (!t) \ snprintf(buf, size, "inactive"); \ else { \ timersub(&t->u.sands, &now, &result); \ timerstring(&result, buf, size); \ } \ } 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 */ extern struct route_node *route_prev (struct route_node *node); extern void ospf6_debug (void); extern void ospf6_init (void); #endif /* OSPF6D_H */ quagga-1.2.4/ospfclient/000077500000000000000000000000001325323223500151315ustar00rootroot00000000000000quagga-1.2.4/ospfclient/AUTHORS000066400000000000000000000000451325323223500162000ustar00rootroot00000000000000Ralph Keller quagga-1.2.4/ospfclient/COPYING000066400000000000000000000430711325323223500161710ustar00rootroot00000000000000 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. quagga-1.2.4/ospfclient/INSTALL000066400000000000000000000172271325323223500161730ustar00rootroot00000000000000Basic 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. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--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. quagga-1.2.4/ospfclient/Makefile.am000066400000000000000000000012231325323223500171630ustar00rootroot00000000000000## Automake.am for OSPF API client AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 libospfapiclient_la_LIBADD = ../ospfd/libospf.la ../lib/libzebra.la sbin_PROGRAMS = ospfclient libospfapiclient_la_SOURCES = \ ospf_apiclient.c ospfapiheaderdir = $(pkgincludedir)/ospfapi ospfapiheader_HEADERS = \ ospf_apiclient.h ospfclient_SOURCES = \ ospfclient.c ospfclient_LDADD = libospfapiclient.la \ ../ospfd/libospf.la ../lib/libzebra.la @LIBCAP@ ospfclient_CFLAGS = $(AM_CFLAGS) ospfclient_LDFLAGS = $(AM_LDFLAGS) quagga-1.2.4/ospfclient/Makefile.in000066400000000000000000000672771325323223500172210ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ospfclient$(EXEEXT) subdir = ospfclient ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(ospfapiheader_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(ospfapiheaderdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libospfapiclient_la_DEPENDENCIES = ../ospfd/libospf.la \ ../lib/libzebra.la am_libospfapiclient_la_OBJECTS = ospf_apiclient.lo libospfapiclient_la_OBJECTS = $(am_libospfapiclient_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libospfapiclient_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libospfapiclient_la_LDFLAGS) \ $(LDFLAGS) -o $@ PROGRAMS = $(sbin_PROGRAMS) am_ospfclient_OBJECTS = ospfclient-ospfclient.$(OBJEXT) ospfclient_OBJECTS = $(am_ospfclient_OBJECTS) ospfclient_DEPENDENCIES = libospfapiclient.la ../ospfd/libospf.la \ ../lib/libzebra.la ospfclient_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ospfclient_CFLAGS) \ $(CFLAGS) $(ospfclient_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libospfapiclient_la_SOURCES) $(ospfclient_SOURCES) DIST_SOURCES = $(libospfapiclient_la_SOURCES) $(ospfclient_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(ospfapiheader_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp AUTHORS \ COPYING INSTALL NEWS README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 libospfapiclient_la_LIBADD = ../ospfd/libospf.la ../lib/libzebra.la libospfapiclient_la_SOURCES = \ ospf_apiclient.c ospfapiheaderdir = $(pkgincludedir)/ospfapi ospfapiheader_HEADERS = \ ospf_apiclient.h ospfclient_SOURCES = \ ospfclient.c ospfclient_LDADD = libospfapiclient.la \ ../ospfd/libospf.la ../lib/libzebra.la @LIBCAP@ ospfclient_CFLAGS = $(AM_CFLAGS) ospfclient_LDFLAGS = $(AM_LDFLAGS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ospfclient/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ospfclient/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libospfapiclient.la: $(libospfapiclient_la_OBJECTS) $(libospfapiclient_la_DEPENDENCIES) $(EXTRA_libospfapiclient_la_DEPENDENCIES) $(AM_V_CCLD)$(libospfapiclient_la_LINK) -rpath $(libdir) $(libospfapiclient_la_OBJECTS) $(libospfapiclient_la_LIBADD) $(LIBS) install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ospfclient$(EXEEXT): $(ospfclient_OBJECTS) $(ospfclient_DEPENDENCIES) $(EXTRA_ospfclient_DEPENDENCIES) @rm -f ospfclient$(EXEEXT) $(AM_V_CCLD)$(ospfclient_LINK) $(ospfclient_OBJECTS) $(ospfclient_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_apiclient.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospfclient-ospfclient.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< ospfclient-ospfclient.o: ospfclient.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ospfclient_CFLAGS) $(CFLAGS) -MT ospfclient-ospfclient.o -MD -MP -MF $(DEPDIR)/ospfclient-ospfclient.Tpo -c -o ospfclient-ospfclient.o `test -f 'ospfclient.c' || echo '$(srcdir)/'`ospfclient.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ospfclient-ospfclient.Tpo $(DEPDIR)/ospfclient-ospfclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ospfclient.c' object='ospfclient-ospfclient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ospfclient_CFLAGS) $(CFLAGS) -c -o ospfclient-ospfclient.o `test -f 'ospfclient.c' || echo '$(srcdir)/'`ospfclient.c ospfclient-ospfclient.obj: ospfclient.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ospfclient_CFLAGS) $(CFLAGS) -MT ospfclient-ospfclient.obj -MD -MP -MF $(DEPDIR)/ospfclient-ospfclient.Tpo -c -o ospfclient-ospfclient.obj `if test -f 'ospfclient.c'; then $(CYGPATH_W) 'ospfclient.c'; else $(CYGPATH_W) '$(srcdir)/ospfclient.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ospfclient-ospfclient.Tpo $(DEPDIR)/ospfclient-ospfclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ospfclient.c' object='ospfclient-ospfclient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ospfclient_CFLAGS) $(CFLAGS) -c -o ospfclient-ospfclient.obj `if test -f 'ospfclient.c'; then $(CYGPATH_W) 'ospfclient.c'; else $(CYGPATH_W) '$(srcdir)/ospfclient.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-ospfapiheaderHEADERS: $(ospfapiheader_HEADERS) @$(NORMAL_INSTALL) @list='$(ospfapiheader_HEADERS)'; test -n "$(ospfapiheaderdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(ospfapiheaderdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(ospfapiheaderdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(ospfapiheaderdir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(ospfapiheaderdir)" || exit $$?; \ done uninstall-ospfapiheaderHEADERS: @$(NORMAL_UNINSTALL) @list='$(ospfapiheader_HEADERS)'; test -n "$(ospfapiheaderdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(ospfapiheaderdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(ospfapiheaderdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libLTLIBRARIES clean-libtool \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-ospfapiheaderHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES uninstall-ospfapiheaderHEADERS \ uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-ospfapiheaderHEADERS install-pdf \ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-libLTLIBRARIES uninstall-ospfapiheaderHEADERS \ uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/ospfclient/NEWS000066400000000000000000000000311325323223500156220ustar00rootroot00000000000000This file contains news. quagga-1.2.4/ospfclient/README000066400000000000000000000001411325323223500160050ustar00rootroot00000000000000For more information about this software check out: http://www.tik.ee.ethz.ch/~keller/ospfapi/ quagga-1.2.4/ospfclient/ospf_apiclient.c000066400000000000000000000461301325323223500203000ustar00rootroot00000000000000/* * Client side of OSPF API. * Copyright (C) 2001, 2002, 2003 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "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 "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_opaque.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_api.h" #include "ospf_apiclient.h" /* Backlog for listen */ #define BACKLOG 5 /* ----------------------------------------------------------- * Forward declarations * ----------------------------------------------------------- */ void ospf_apiclient_handle_reply (struct ospf_apiclient *oclient, struct msg *msg); void ospf_apiclient_handle_update_notify (struct ospf_apiclient *oclient, struct msg *msg); void ospf_apiclient_handle_delete_notify (struct ospf_apiclient *oclient, struct msg *msg); /* ----------------------------------------------------------- * Initialization * ----------------------------------------------------------- */ static unsigned short ospf_apiclient_getport (void) { struct servent *sp = getservbyname ("ospfapi", "tcp"); return sp ? ntohs (sp->s_port) : OSPF_API_SYNC_PORT; } /* ----------------------------------------------------------- * Followings are functions for connection management * ----------------------------------------------------------- */ struct ospf_apiclient * ospf_apiclient_connect (char *host, int syncport) { struct sockaddr_in myaddr_sync; struct sockaddr_in myaddr_async; struct sockaddr_in peeraddr; struct hostent *hp; struct ospf_apiclient *new; int size = 0; unsigned int peeraddrlen; int async_server_sock; int fd1, fd2; int ret; int on = 1; /* There are two connections between the client and the server. First the client opens a connection for synchronous requests/replies to the server. The server will accept this connection and as a reaction open a reverse connection channel for asynchronous messages. */ async_server_sock = socket (AF_INET, SOCK_STREAM, 0); if (async_server_sock < 0) { fprintf (stderr, "ospf_apiclient_connect: creating async socket failed\n"); return NULL; } /* Prepare socket for asynchronous messages */ /* Initialize async address structure */ memset (&myaddr_async, 0, sizeof (struct sockaddr_in)); myaddr_async.sin_family = AF_INET; myaddr_async.sin_addr.s_addr = htonl (INADDR_ANY); myaddr_async.sin_port = htons (syncport+1); size = sizeof (struct sockaddr_in); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN myaddr_async.sin_len = size; #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* This is a server socket, reuse addr and port */ ret = setsockopt (async_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof (on)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n"); close (async_server_sock); return NULL; } #ifdef SO_REUSEPORT ret = setsockopt (async_server_sock, SOL_SOCKET, SO_REUSEPORT, (void *) &on, sizeof (on)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n"); close (async_server_sock); return NULL; } #endif /* SO_REUSEPORT */ /* Bind socket to address structure */ ret = bind (async_server_sock, (struct sockaddr *) &myaddr_async, size); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: bind async socket failed\n"); close (async_server_sock); return NULL; } /* Wait for reverse channel connection establishment from server */ ret = listen (async_server_sock, BACKLOG); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: listen: %s\n", safe_strerror (errno)); close (async_server_sock); return NULL; } /* Make connection for synchronous requests and connect to server */ /* Resolve address of server */ hp = gethostbyname (host); if (!hp) { fprintf (stderr, "ospf_apiclient_connect: no such host %s\n", host); close (async_server_sock); return NULL; } fd1 = socket (AF_INET, SOCK_STREAM, 0); if (fd1 < 0) { fprintf (stderr, "ospf_apiclient_connect: creating sync socket failed\n"); return NULL; } /* Reuse addr and port */ ret = setsockopt (fd1, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof (on)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n"); close (fd1); return NULL; } #ifdef SO_REUSEPORT ret = setsockopt (fd1, SOL_SOCKET, SO_REUSEPORT, (void *) &on, sizeof (on)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n"); close (fd1); return NULL; } #endif /* SO_REUSEPORT */ /* Bind sync socket to address structure. This is needed since we want the sync port number on a fixed port number. The reverse async channel will be at this port+1 */ memset (&myaddr_sync, 0, sizeof (struct sockaddr_in)); myaddr_sync.sin_family = AF_INET; myaddr_sync.sin_port = htons (syncport); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN myaddr_sync.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ ret = bind (fd1, (struct sockaddr *) &myaddr_sync, size); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: bind sync socket failed\n"); close (fd1); return NULL; } /* Prepare address structure for connect */ memcpy (&myaddr_sync.sin_addr, hp->h_addr, hp->h_length); myaddr_sync.sin_family = AF_INET; myaddr_sync.sin_port = htons(ospf_apiclient_getport ()); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN myaddr_sync.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Now establish synchronous channel with OSPF daemon */ ret = connect (fd1, (struct sockaddr *) &myaddr_sync, sizeof (struct sockaddr_in)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: sync connect failed\n"); close (async_server_sock); close (fd1); return NULL; } /* Accept reverse connection */ peeraddrlen = sizeof (struct sockaddr_in); memset (&peeraddr, 0, peeraddrlen); fd2 = accept (async_server_sock, (struct sockaddr *) &peeraddr, &peeraddrlen); if (fd2 < 0) { fprintf (stderr, "ospf_apiclient_connect: accept async failed\n"); close (async_server_sock); close (fd1); return NULL; } /* Server socket is not needed anymore since we are not accepting more connections */ close (async_server_sock); /* Create new client-side instance */ new = XCALLOC (MTYPE_OSPF_APICLIENT, sizeof (struct ospf_apiclient)); /* Initialize socket descriptors for sync and async channels */ new->fd_sync = fd1; new->fd_async = fd2; return new; } int ospf_apiclient_close (struct ospf_apiclient *oclient) { if (oclient->fd_sync >= 0) { close (oclient->fd_sync); } if (oclient->fd_async >= 0) { close (oclient->fd_async); } /* Free client structure */ XFREE (MTYPE_OSPF_APICLIENT, oclient); return 0; } /* ----------------------------------------------------------- * Followings are functions to send a request to OSPFd * ----------------------------------------------------------- */ /* Send synchronous request, wait for reply */ static int ospf_apiclient_send_request (struct ospf_apiclient *oclient, struct msg *msg) { u_int32_t reqseq; struct msg_reply *msgreply; int rc; /* NB: Given "msg" is freed inside this function. */ /* Remember the sequence number of the request */ reqseq = ntohl (msg->hdr.msgseq); /* Write message to OSPFd */ rc = msg_write (oclient->fd_sync, msg); msg_free (msg); if (rc < 0) { return -1; } /* Wait for reply *//* NB: New "msg" is allocated by "msg_read()". */ msg = msg_read (oclient->fd_sync); if (!msg) return -1; assert (msg->hdr.msgtype == MSG_REPLY); assert (ntohl (msg->hdr.msgseq) == reqseq); msgreply = (struct msg_reply *) STREAM_DATA (msg->s); rc = msgreply->errcode; msg_free (msg); return rc; } /* ----------------------------------------------------------- * Helper functions * ----------------------------------------------------------- */ static u_int32_t ospf_apiclient_get_seqnr (void) { static u_int32_t seqnr = MIN_SEQ; u_int32_t tmp; tmp = seqnr; /* Increment sequence number */ if (seqnr < MAX_SEQ) { seqnr++; } else { seqnr = MIN_SEQ; } return tmp; } /* ----------------------------------------------------------- * API to access OSPF daemon by client applications. * ----------------------------------------------------------- */ /* * Synchronous request to register opaque type. */ int ospf_apiclient_register_opaque_type (struct ospf_apiclient *cl, u_char ltype, u_char otype) { struct msg *msg; int rc; /* just put 1 as a sequence number. */ msg = new_msg_register_opaque_type (ospf_apiclient_get_seqnr (), ltype, otype); if (!msg) { fprintf (stderr, "new_msg_register_opaque_type failed\n"); return -1; } rc = ospf_apiclient_send_request (cl, msg); return rc; } /* * Synchronous request to synchronize with OSPF's LSDB. * Two steps required: register_event in order to get * dynamic updates and LSDB_Sync. */ int ospf_apiclient_sync_lsdb (struct ospf_apiclient *oclient) { struct msg *msg; int rc; struct lsa_filter_type filter; filter.typemask = 0xFFFF; /* all LSAs */ filter.origin = ANY_ORIGIN; filter.num_areas = 0; /* all Areas. */ msg = new_msg_register_event (ospf_apiclient_get_seqnr (), &filter); if (!msg) { fprintf (stderr, "new_msg_register_event failed\n"); return -1; } rc = ospf_apiclient_send_request (oclient, msg); if (rc != 0) goto out; msg = new_msg_sync_lsdb (ospf_apiclient_get_seqnr (), &filter); if (!msg) { fprintf (stderr, "new_msg_sync_lsdb failed\n"); return -1; } rc = ospf_apiclient_send_request (oclient, msg); out: return rc; } /* * Synchronous request to originate or update an LSA. */ int ospf_apiclient_lsa_originate (struct ospf_apiclient *oclient, struct in_addr ifaddr, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id, void *opaquedata, int opaquelen) { struct msg *msg; int rc; u_char buf[OSPF_MAX_LSA_SIZE]; struct lsa_header *lsah; u_int32_t tmp; /* We can only originate opaque LSAs */ if (!IS_OPAQUE_LSA (lsa_type)) { fprintf (stderr, "Cannot originate non-opaque LSA type %d\n", lsa_type); return OSPF_API_ILLEGALLSATYPE; } /* Make a new LSA from parameters */ lsah = (struct lsa_header *) buf; lsah->ls_age = 0; lsah->options = 0; lsah->type = lsa_type; tmp = SET_OPAQUE_LSID (opaque_type, opaque_id); lsah->id.s_addr = htonl (tmp); lsah->adv_router.s_addr = 0; lsah->ls_seqnum = 0; lsah->checksum = 0; lsah->length = htons (sizeof (struct lsa_header) + opaquelen); memcpy (((u_char *) lsah) + sizeof (struct lsa_header), opaquedata, opaquelen); msg = new_msg_originate_request (ospf_apiclient_get_seqnr (), ifaddr, area_id, lsah); if (!msg) { fprintf (stderr, "new_msg_originate_request failed\n"); return OSPF_API_NOMEMORY; } rc = ospf_apiclient_send_request (oclient, msg); return rc; } int ospf_apiclient_lsa_delete (struct ospf_apiclient *oclient, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id) { struct msg *msg; int rc; /* Only opaque LSA can be deleted */ if (!IS_OPAQUE_LSA (lsa_type)) { fprintf (stderr, "Cannot delete non-opaque LSA type %d\n", lsa_type); return OSPF_API_ILLEGALLSATYPE; } /* opaque_id is in host byte order and will be converted * to network byte order by new_msg_delete_request */ msg = new_msg_delete_request (ospf_apiclient_get_seqnr (), area_id, lsa_type, opaque_type, opaque_id); rc = ospf_apiclient_send_request (oclient, msg); return rc; } /* ----------------------------------------------------------- * Followings are handlers for messages from OSPF daemon * ----------------------------------------------------------- */ static void ospf_apiclient_handle_ready (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_ready_notify *r; r = (struct msg_ready_notify *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->ready_notify) { (oclient->ready_notify) (r->lsa_type, r->opaque_type, r->addr); } } static void ospf_apiclient_handle_new_if (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_new_if *n; n = (struct msg_new_if *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->new_if) { (oclient->new_if) (n->ifaddr, n->area_id); } } static void ospf_apiclient_handle_del_if (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_del_if *d; d = (struct msg_del_if *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->del_if) { (oclient->del_if) (d->ifaddr); } } static void ospf_apiclient_handle_ism_change (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_ism_change *m; m = (struct msg_ism_change *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->ism_change) { (oclient->ism_change) (m->ifaddr, m->area_id, m->status); } } static void ospf_apiclient_handle_nsm_change (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_nsm_change *m; m = (struct msg_nsm_change *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->nsm_change) { (oclient->nsm_change) (m->ifaddr, m->nbraddr, m->router_id, m->status); } } static void ospf_apiclient_handle_lsa_update (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_lsa_change_notify *cn; struct lsa_header *lsa; int lsalen; cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s); /* Extract LSA from message */ lsalen = ntohs (cn->data.length); lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen); if (!lsa) { fprintf (stderr, "LSA update: Cannot allocate memory for LSA\n"); return; } memcpy (lsa, &(cn->data), lsalen); /* Invoke registered update callback function */ if (oclient->update_notify) { (oclient->update_notify) (cn->ifaddr, cn->area_id, cn->is_self_originated, lsa); } /* free memory allocated by ospf apiclient library */ XFREE (MTYPE_OSPF_APICLIENT, lsa); } static void ospf_apiclient_handle_lsa_delete (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_lsa_change_notify *cn; struct lsa_header *lsa; int lsalen; cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s); /* Extract LSA from message */ lsalen = ntohs (cn->data.length); lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen); if (!lsa) { fprintf (stderr, "LSA delete: Cannot allocate memory for LSA\n"); return; } memcpy (lsa, &(cn->data), lsalen); /* Invoke registered update callback function */ if (oclient->delete_notify) { (oclient->delete_notify) (cn->ifaddr, cn->area_id, cn->is_self_originated, lsa); } /* free memory allocated by ospf apiclient library */ XFREE (MTYPE_OSPF_APICLIENT, lsa); } static void ospf_apiclient_msghandle (struct ospf_apiclient *oclient, struct msg *msg) { /* Call message handler function. */ switch (msg->hdr.msgtype) { case MSG_READY_NOTIFY: ospf_apiclient_handle_ready (oclient, msg); break; case MSG_NEW_IF: ospf_apiclient_handle_new_if (oclient, msg); break; case MSG_DEL_IF: ospf_apiclient_handle_del_if (oclient, msg); break; case MSG_ISM_CHANGE: ospf_apiclient_handle_ism_change (oclient, msg); break; case MSG_NSM_CHANGE: ospf_apiclient_handle_nsm_change (oclient, msg); break; case MSG_LSA_UPDATE_NOTIFY: ospf_apiclient_handle_lsa_update (oclient, msg); break; case MSG_LSA_DELETE_NOTIFY: ospf_apiclient_handle_lsa_delete (oclient, msg); break; default: fprintf (stderr, "ospf_apiclient_read: Unknown message type: %d\n", msg->hdr.msgtype); break; } } /* ----------------------------------------------------------- * Callback handler registration * ----------------------------------------------------------- */ void ospf_apiclient_register_callback (struct ospf_apiclient *oclient, void (*ready_notify) (u_char lsa_type, u_char opaque_type, struct in_addr addr), void (*new_if) (struct in_addr ifaddr, struct in_addr area_id), void (*del_if) (struct in_addr ifaddr), void (*ism_change) (struct in_addr ifaddr, struct in_addr area_id, u_char status), void (*nsm_change) (struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status), void (*update_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char self_origin, struct lsa_header * lsa), void (*delete_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char self_origin, struct lsa_header * lsa)) { assert (oclient); assert (update_notify); /* Register callback function */ oclient->ready_notify = ready_notify; oclient->new_if = new_if; oclient->del_if = del_if; oclient->ism_change = ism_change; oclient->nsm_change = nsm_change; oclient->update_notify = update_notify; oclient->delete_notify = delete_notify; } /* ----------------------------------------------------------- * Asynchronous message handling * ----------------------------------------------------------- */ int ospf_apiclient_handle_async (struct ospf_apiclient *oclient) { struct msg *msg; /* Get a message */ msg = msg_read (oclient->fd_async); if (!msg) { /* Connection broke down */ return -1; } /* Handle message */ ospf_apiclient_msghandle (oclient, msg); /* Don't forget to free this message */ msg_free (msg); return 0; } quagga-1.2.4/ospfclient/ospf_apiclient.h000066400000000000000000000110251325323223500203000ustar00rootroot00000000000000/* * Client side of OSPF API. * Copyright (C) 2001, 2002, 2003 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_APICLIENT_H #define _OSPF_APICLIENT_H #define MTYPE_OSPF_APICLIENT MTYPE_TMP /* Structure for the OSPF API client */ struct ospf_apiclient { /* Sockets for sync requests and async notifications */ int fd_sync; int fd_async; /* Pointer to callback functions */ void (*ready_notify) (u_char lsa_type, u_char opaque_type, struct in_addr addr); void (*new_if) (struct in_addr ifaddr, struct in_addr area_id); void (*del_if) (struct in_addr ifaddr); void (*ism_change) (struct in_addr ifaddr, struct in_addr area_id, u_char status); void (*nsm_change) (struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status); void (*update_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char self_origin, struct lsa_header * lsa); void (*delete_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char self_origin, struct lsa_header * lsa); }; /* --------------------------------------------------------- * API function prototypes. * --------------------------------------------------------- */ /* Open connection to OSPF daemon. Two ports will be allocated on client, sync channel at syncport and reverse channel at syncport+1 */ struct ospf_apiclient *ospf_apiclient_connect (char *host, int syncport); /* Shutdown connection to OSPF daemon. */ int ospf_apiclient_close (struct ospf_apiclient *oclient); /* Synchronous request to register opaque type. */ int ospf_apiclient_register_opaque_type (struct ospf_apiclient *oclient, u_char ltype, u_char otype); /* Synchronous request to register event mask. */ int ospf_apiclient_register_events (struct ospf_apiclient *oclient, u_int32_t mask); /* Register callback functions.*/ void ospf_apiclient_register_callback (struct ospf_apiclient *oclient, void (*ready_notify) (u_char lsa_type, u_char opaque_type, struct in_addr addr), void (*new_if) (struct in_addr ifaddr, struct in_addr area_id), void (*del_if) (struct in_addr ifaddr), void (*ism_change) (struct in_addr ifaddr, struct in_addr area_id, u_char status), void (*nsm_change) (struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status), void (*update_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char selforig, struct lsa_header * lsa), void (*delete_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char selforig, struct lsa_header * lsa)); /* Synchronous request to synchronize LSDB. */ int ospf_apiclient_sync_lsdb (struct ospf_apiclient *oclient); /* Synchronous request to originate or update opaque LSA. */ int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient, struct in_addr ifaddr, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id, void *opaquedata, int opaquelen); /* Synchronous request to delete opaque LSA. Parameter opaque_id is in host byte order */ int ospf_apiclient_lsa_delete (struct ospf_apiclient *oclient, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id); /* Fetch async message and handle it */ int ospf_apiclient_handle_async (struct ospf_apiclient *oclient); #endif /* _OSPF_APICLIENT_H */ quagga-1.2.4/ospfclient/ospfclient.c000066400000000000000000000225721325323223500174530ustar00rootroot00000000000000/* This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Simple program to demonstrate how OSPF API can be used. This * application retrieves the LSDB from the OSPF daemon and then * originates, updates and finally deletes an application-specific * opaque LSA. You can use this application as a template when writing * your own application. */ /* The following includes are needed in all OSPF API client applications. */ #include #include "prefix.h" /* needed by ospf_asbr.h */ #include "privs.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_opaque.h" #include "ospfd/ospf_api.h" #include "ospf_apiclient.h" /* privileges struct. * set cap_num_* and uid/gid to nothing to use NULL privs * as ospfapiclient links in libospf.a which uses privs. */ struct zebra_privs_t ospfd_privs = { .user = NULL, .group = NULL, .cap_num_p = 0, .cap_num_i = 0 }; /* The following includes are specific to this application. For example it uses threads from libzebra, however your application is free to use any thread library (like pthreads). */ #include "ospfd/ospf_dump.h" /* for ospf_lsa_header_dump */ #include "thread.h" #include "log.h" /* Local portnumber for async channel. Note that OSPF API library will also allocate a sync channel at ASYNCPORT+1. */ #define ASYNCPORT 4000 /* Master thread */ struct thread_master *master; /* Global variables */ struct ospf_apiclient *oclient; char **args; /* Our opaque LSAs have the following format. */ struct my_opaque_lsa { struct lsa_header hdr; /* include common LSA header */ u_char data[4]; /* our own data format then follows here */ }; /* --------------------------------------------------------- * Threads for asynchronous messages and LSA update/delete * --------------------------------------------------------- */ static int lsa_delete (struct thread *t) { struct ospf_apiclient *oclient; struct in_addr area_id; int rc; oclient = THREAD_ARG (t); inet_aton (args[6], &area_id); printf ("Deleting LSA... "); rc = ospf_apiclient_lsa_delete (oclient, area_id, atoi (args[2]), /* lsa type */ atoi (args[3]), /* opaque type */ atoi (args[4])); /* opaque ID */ printf ("done, return code is = %d\n", rc); return rc; } static int lsa_inject (struct thread *t) { struct ospf_apiclient *cl; struct in_addr ifaddr; struct in_addr area_id; u_char lsa_type; u_char opaque_type; u_int32_t opaque_id; void *opaquedata; int opaquelen; static u_int32_t counter = 1; /* Incremented each time invoked */ int rc; cl = THREAD_ARG (t); inet_aton (args[5], &ifaddr); inet_aton (args[6], &area_id); lsa_type = atoi (args[2]); opaque_type = atoi (args[3]); opaque_id = atoi (args[4]); opaquedata = &counter; opaquelen = sizeof (u_int32_t); printf ("Originating/updating LSA with counter=%d... ", counter); rc = ospf_apiclient_lsa_originate(cl, ifaddr, area_id, lsa_type, opaque_type, opaque_id, opaquedata, opaquelen); printf ("done, return code is %d\n", rc); counter++; return 0; } /* This thread handles asynchronous messages coming in from the OSPF API server */ static int lsa_read (struct thread *thread) { struct ospf_apiclient *oclient; int fd; int ret; printf ("lsa_read called\n"); oclient = THREAD_ARG (thread); fd = THREAD_FD (thread); /* Handle asynchronous message */ ret = ospf_apiclient_handle_async (oclient); if (ret < 0) { printf ("Connection closed, exiting..."); exit(0); } /* Reschedule read thread */ thread_add_read (master, lsa_read, oclient, fd); return 0; } /* --------------------------------------------------------- * Callback functions for asynchronous events * --------------------------------------------------------- */ static void lsa_update_callback (struct in_addr ifaddr, struct in_addr area_id, u_char is_self_originated, struct lsa_header *lsa) { printf ("lsa_update_callback: "); printf ("ifaddr: %s ", inet_ntoa (ifaddr)); printf ("area: %s\n", inet_ntoa (area_id)); printf ("is_self_origin: %u\n", is_self_originated); /* It is important to note that lsa_header does indeed include the header and the LSA payload. To access the payload, first check the LSA type and then typecast lsa into the corresponding type, e.g.: if (lsa->type == OSPF_ROUTER_LSA) { struct router_lsa *rl = (struct router_lsa) lsa; ... u_int16_t links = rl->links; ... } */ ospf_lsa_header_dump (lsa); } static void lsa_delete_callback (struct in_addr ifaddr, struct in_addr area_id, u_char is_self_originated, struct lsa_header *lsa) { printf ("lsa_delete_callback: "); printf ("ifaddr: %s ", inet_ntoa (ifaddr)); printf ("area: %s\n", inet_ntoa (area_id)); printf ("is_self_origin: %u\n", is_self_originated); ospf_lsa_header_dump (lsa); } static void ready_callback (u_char lsa_type, u_char opaque_type, struct in_addr addr) { printf ("ready_callback: lsa_type: %d opaque_type: %d addr=%s\n", lsa_type, opaque_type, inet_ntoa (addr)); /* Schedule opaque LSA originate in 5 secs */ thread_add_timer (master, lsa_inject, oclient, 5); /* Schedule opaque LSA update with new value */ thread_add_timer (master, lsa_inject, oclient, 10); /* Schedule delete */ thread_add_timer (master, lsa_delete, oclient, 30); } static void new_if_callback (struct in_addr ifaddr, struct in_addr area_id) { printf ("new_if_callback: ifaddr: %s ", inet_ntoa (ifaddr)); printf ("area_id: %s\n", inet_ntoa (area_id)); } static void del_if_callback (struct in_addr ifaddr) { printf ("new_if_callback: ifaddr: %s\n ", inet_ntoa (ifaddr)); } static void ism_change_callback (struct in_addr ifaddr, struct in_addr area_id, u_char state) { printf ("ism_change: ifaddr: %s ", inet_ntoa (ifaddr)); printf ("area_id: %s\n", inet_ntoa (area_id)); printf ("state: %d [%s]\n", state, LOOKUP (ospf_ism_state_msg, state)); } static void nsm_change_callback (struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char state) { printf ("nsm_change: ifaddr: %s ", inet_ntoa (ifaddr)); printf ("nbraddr: %s\n", inet_ntoa (nbraddr)); printf ("router_id: %s\n", inet_ntoa (router_id)); printf ("state: %d [%s]\n", state, LOOKUP (ospf_nsm_state_msg, state)); } /* --------------------------------------------------------- * Main program * --------------------------------------------------------- */ static int usage() { printf("Usage: ospfclient \n"); printf("where ospfd : router where API-enabled OSPF daemon is running\n"); printf(" lsatype : either 9, 10, or 11 depending on flooding scope\n"); printf(" opaquetype: 0-255 (e.g., experimental applications use > 128)\n"); printf(" opaqueid : arbitrary application instance (24 bits)\n"); printf(" ifaddr : interface IP address (for type 9) otherwise ignored\n"); printf(" areaid : area in IP address format (for type 10) otherwise ignored\n"); exit(1); } int main (int argc, char *argv[]) { args = argv; /* ospfclient should be started with the following arguments: * * (1) host (2) lsa_type (3) opaque_type (4) opaque_id (5) if_addr * (6) area_id * * host: name or IP of host where ospfd is running * lsa_type: 9, 10, or 11 * opaque_type: 0-255 (e.g., experimental applications use > 128) * opaque_id: arbitrary application instance (24 bits) * if_addr: interface IP address (for type 9) otherwise ignored * area_id: area in IP address format (for type 10) otherwise ignored */ if (argc != 7) { usage(); } /* Initialization */ zprivs_init (&ospfd_privs); master = thread_master_create (); /* Open connection to OSPF daemon */ oclient = ospf_apiclient_connect (args[1], ASYNCPORT); if (!oclient) { printf ("Connecting to OSPF daemon on %s failed!\n", args[1]); exit (1); } /* Register callback functions. */ ospf_apiclient_register_callback (oclient, ready_callback, new_if_callback, del_if_callback, ism_change_callback, nsm_change_callback, lsa_update_callback, lsa_delete_callback); /* Register LSA type and opaque type. */ ospf_apiclient_register_opaque_type (oclient, atoi (args[2]), atoi (args[3])); /* Synchronize database with OSPF daemon. */ ospf_apiclient_sync_lsdb (oclient); /* Schedule thread that handles asynchronous messages */ thread_add_read (master, lsa_read, oclient, oclient->fd_async); /* Now connection is established, run loop */ thread_main (master); /* Never reached */ return 0; } quagga-1.2.4/ospfd/000077500000000000000000000000001325323223500140765ustar00rootroot00000000000000quagga-1.2.4/ospfd/ChangeLog.opaque.txt000066400000000000000000000230501325323223500177570ustar00rootroot00000000000000----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- 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. quagga-1.2.4/ospfd/Makefile.am000066400000000000000000000025321325323223500161340ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 lib_LTLIBRARIES = libospf.la libospf_la_LDFLAGS = -version-info 0:0:0 libospf_la_LIBADD = ../lib/libzebra.la sbin_PROGRAMS = ospfd libospf_la_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_ri.c ospf_vty.c ospf_api.c ospf_apiserver.c ospfdheaderdir = $(pkgincludedir)/ospfd ospfdheader_HEADERS = \ ospf_api.h ospf_asbr.h ospf_dump.h ospf_lsa.h ospf_lsdb.h \ ospf_nsm.h ospf_ism.h ospf_opaque.h ospfd.h noinst_HEADERS = \ ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \ ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ ospf_flood.h ospf_snmp.h ospf_te.h ospf_ri.h ospf_vty.h ospf_apiserver.h ospfd_SOURCES = ospf_main.c ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ @LIBM@ EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt examplesdir = $(exampledir) dist_examples_DATA = ospfd.conf.sample quagga-1.2.4/ospfd/Makefile.in000066400000000000000000000721771325323223500161610ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ospfd$(EXEEXT) subdir = ospfd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(ospfdheader_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(examplesdir)" "$(DESTDIR)$(ospfdheaderdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libospf_la_DEPENDENCIES = ../lib/libzebra.la am_libospf_la_OBJECTS = ospfd.lo ospf_zebra.lo ospf_interface.lo \ ospf_ism.lo ospf_neighbor.lo ospf_nsm.lo ospf_dump.lo \ ospf_network.lo ospf_packet.lo ospf_lsa.lo ospf_spf.lo \ ospf_route.lo ospf_ase.lo ospf_abr.lo ospf_ia.lo ospf_flood.lo \ ospf_lsdb.lo ospf_asbr.lo ospf_routemap.lo ospf_snmp.lo \ ospf_opaque.lo ospf_te.lo ospf_ri.lo ospf_vty.lo ospf_api.lo \ ospf_apiserver.lo libospf_la_OBJECTS = $(am_libospf_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libospf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libospf_la_LDFLAGS) $(LDFLAGS) -o $@ PROGRAMS = $(sbin_PROGRAMS) am_ospfd_OBJECTS = ospf_main.$(OBJEXT) ospfd_OBJECTS = $(am_ospfd_OBJECTS) ospfd_DEPENDENCIES = libospf.la ../lib/libzebra.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libospf_la_SOURCES) $(ospfd_SOURCES) DIST_SOURCES = $(libospf_la_SOURCES) $(ospfd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) $(ospfdheader_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) INSTALL_SDATA = @INSTALL@ -m 600 lib_LTLIBRARIES = libospf.la libospf_la_LDFLAGS = -version-info 0:0:0 libospf_la_LIBADD = ../lib/libzebra.la libospf_la_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_ri.c ospf_vty.c ospf_api.c ospf_apiserver.c ospfdheaderdir = $(pkgincludedir)/ospfd ospfdheader_HEADERS = \ ospf_api.h ospf_asbr.h ospf_dump.h ospf_lsa.h ospf_lsdb.h \ ospf_nsm.h ospf_ism.h ospf_opaque.h ospfd.h noinst_HEADERS = \ ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \ ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ ospf_flood.h ospf_snmp.h ospf_te.h ospf_ri.h ospf_vty.h ospf_apiserver.h ospfd_SOURCES = ospf_main.c ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ @LIBM@ EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt examplesdir = $(exampledir) dist_examples_DATA = ospfd.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ospfd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ospfd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libospf.la: $(libospf_la_OBJECTS) $(libospf_la_DEPENDENCIES) $(EXTRA_libospf_la_DEPENDENCIES) $(AM_V_CCLD)$(libospf_la_LINK) -rpath $(libdir) $(libospf_la_OBJECTS) $(libospf_la_LIBADD) $(LIBS) install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ospfd$(EXEEXT): $(ospfd_OBJECTS) $(ospfd_DEPENDENCIES) $(EXTRA_ospfd_DEPENDENCIES) @rm -f ospfd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ospfd_OBJECTS) $(ospfd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_abr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_apiserver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_asbr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ase.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_dump.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_flood.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ia.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ism.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsa.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsdb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_neighbor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_network.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_nsm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_opaque.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_packet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ri.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_route.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_routemap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_snmp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_spf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_te.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_vty.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_zebra.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospfd.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) install-ospfdheaderHEADERS: $(ospfdheader_HEADERS) @$(NORMAL_INSTALL) @list='$(ospfdheader_HEADERS)'; test -n "$(ospfdheaderdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(ospfdheaderdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(ospfdheaderdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(ospfdheaderdir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(ospfdheaderdir)" || exit $$?; \ done uninstall-ospfdheaderHEADERS: @$(NORMAL_UNINSTALL) @list='$(ospfdheader_HEADERS)'; test -n "$(ospfdheaderdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(ospfdheaderdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" "$(DESTDIR)$(ospfdheaderdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libLTLIBRARIES clean-libtool \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-ospfdheaderHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-libLTLIBRARIES \ uninstall-ospfdheaderHEADERS uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-ospfdheaderHEADERS \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-libLTLIBRARIES \ uninstall-ospfdheaderHEADERS uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/ospfd/OSPF-MIB.txt000066400000000000000000002501441325323223500160210ustar00rootroot00000000000000OSPF-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 suppression 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 quagga-1.2.4/ospfd/OSPF-TRAP-MIB.txt000066400000000000000000000373371325323223500165740ustar00rootroot00000000000000OSPF-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 quagga-1.2.4/ospfd/ospf_abr.c000066400000000000000000001453431325323223500160470ustar00rootroot00000000000000/* * 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" static 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; } static void ospf_area_range_free (struct ospf_area_range *range) { XFREE (MTYPE_OSPF_AREA_RANGE, range); } static 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; } static void ospf_area_range_delete (struct ospf_area *area, struct route_node *rn) { struct ospf_area_range *range = rn->info; if (range->specifics != 0) ospf_delete_discard_route (area->ospf->new_table, (struct prefix_ipv4 *) &rn->p); ospf_area_range_free (range); 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; } static 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; struct ospf_area *area; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) if ((range = ospf_area_range_match (area, p))) return range; return NULL; } int ospf_area_range_active (struct ospf_area_range *range) { return range->specifics; } static 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_lookup (area, 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 route_node *rn; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; rn = route_node_lookup (area->ranges, (struct prefix*)p); if (rn == NULL) return 0; if (ospf_area_range_active (rn->info)) ospf_schedule_abr_task (ospf); ospf_area_range_delete (area, rn); 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; } /* Determine whether this router is elected translator or not for area */ static int ospf_abr_nssa_am_elected (struct ospf_area *area) { struct route_node *rn; struct ospf_lsa *lsa; struct router_lsa *rlsa; struct in_addr *best = NULL; LSDB_LOOP ( ROUTER_LSDB (area), rn, lsa) { /* sanity checks */ if (!lsa || (lsa->data->type != OSPF_ROUTER_LSA) || IS_LSA_SELF (lsa)) continue; rlsa = (struct router_lsa *) lsa->data; /* ignore non-ABR routers */ if (!IS_ROUTER_LSA_BORDER (rlsa)) continue; /* Router has Nt flag - always translate */ if (IS_ROUTER_LSA_NT (rlsa)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_am_elected: " "router %s asserts Nt", inet_ntoa (lsa->data->id) ); return 0; } if (best == NULL) best = &lsa->data->id; else if (IPV4_ADDR_CMP (&best->s_addr, &lsa->data->id.s_addr) < 0) best = &lsa->data->id; } if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_am_elected: best electable ABR is: %s", (best) ? inet_ntoa (*best) : "" ); if (best == NULL) return 1; if (IPV4_ADDR_CMP (&best->s_addr, &area->ospf->router_id.s_addr) < 0) return 1; else return 0; } /* Check NSSA ABR status * assumes there are nssa areas */ static void ospf_abr_nssa_check_status (struct ospf *ospf) { struct ospf_area *area; struct listnode *lnode, *nnode; for (ALL_LIST_ELEMENTS (ospf->areas, lnode, nnode, area)) { u_char old_state = area->NSSATranslatorState; if (area->external_routing != OSPF_AREA_NSSA) continue; if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "checking area %s", inet_ntoa (area->area_id)); if (!IS_OSPF_ABR (area->ospf)) { if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "not ABR"); area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; } else { switch (area->NSSATranslatorRole) { case OSPF_NSSA_ROLE_NEVER: /* We never Translate Type-7 LSA. */ /* TODO: check previous state and flush? */ if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "never translate"); area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; break; case OSPF_NSSA_ROLE_ALWAYS: /* We always translate if we are an ABR * TODO: originate new LSAs if state change? * or let the nssa abr task take care of it? */ if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "translate always"); area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_ENABLED; break; case OSPF_NSSA_ROLE_CANDIDATE: /* We are a candidate for Translation */ if (ospf_abr_nssa_am_elected (area) > 0) { area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_ENABLED; if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "elected translator"); } else { area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "not elected"); } break; } } /* RFC3101, 3.1: * All NSSA border routers must set the E-bit in the Type-1 router-LSAs * of their directly attached non-stub areas, even when they are not * translating. */ if (old_state != area->NSSATranslatorState) { if (old_state == OSPF_NSSA_TRANSLATE_DISABLED) ospf_asbr_status_update (ospf, ++ospf->redistribute); else if (area->NSSATranslatorState == OSPF_NSSA_TRANSLATE_DISABLED) ospf_asbr_status_update (ospf, --ospf->redistribute); } } } /* Check area border router status. */ void ospf_check_abr_status (struct ospf *ospf) { struct ospf_area *area; struct listnode *node, *nnode; 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_debug ("ospf_check_abr_status(): Start"); for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { 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_debug ("ospf_check_abr_status(): looked through areas"); zlog_debug ("ospf_check_abr_status(): bb_configured: %d", bb_configured); zlog_debug ("ospf_check_abr_status(): bb_act_attached: %d", bb_act_attached); zlog_debug ("ospf_check_abr_status(): areas_configured: %d", areas_configured); zlog_debug ("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, SPF_FLAG_ABR_STATUS_CHANGE); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_check_abr_status(): new router flags: %x",new_flags); ospf->flags = new_flags; ospf_router_lsa_update (ospf); } } static void ospf_abr_update_aggregate (struct ospf_area_range *range, struct ospf_route *or, struct ospf_area *area) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): Start"); if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED) && (range->cost != OSPF_STUB_MAX_METRIC_SUMMARY_COST)) { range->cost = OSPF_STUB_MAX_METRIC_SUMMARY_COST; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): use summary max-metric 0x%08x", range->cost); } else if (range->cost_config != OSPF_AREA_RANGE_COST_UNSPEC) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): use configured cost %d", range->cost_config); range->cost = range->cost_config; } else { if (range->specifics == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): use or->cost %d", or->cost); range->cost = or->cost; /* 1st time get 1st cost */ } if (or->cost > range->cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): update to %d", or->cost); 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 = (u_char *) &metric; mp++; header = (struct summary_lsa *) lsa->data; memcpy(header->metric, mp, 3); } /* ospf_abr_translate_nssa */ static 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 *old = NULL, *new = NULL; struct as_external_lsa *ext7; struct prefix_ipv4 p; if (! CHECK_FLAG (lsa->data->options, OSPF_OPTION_NP)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): LSA Id %s, P-bit off, NO Translation", inet_ntoa (lsa->data->id)); return 1; } if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): LSA Id %s, TRANSLATING 7 to 5", inet_ntoa (lsa->data->id)); ext7 = (struct as_external_lsa *)(lsa->data); p.prefix = lsa->data->id; p.prefixlen = ip_masklen (ext7->mask); if (ext7->e[0].fwd_addr.s_addr == OSPF_DEFAULT_DESTINATION) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): LSA Id %s, " "Forward address is 0, NO Translation", inet_ntoa (lsa->data->id)); return 1; } /* try find existing AS-External LSA for this prefix */ old = ospf_external_info_find_lsa (area->ospf, &p); if (old) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): " "found old translated LSA Id %s, refreshing", inet_ntoa (old->data->id)); /* refresh */ new = ospf_translated_nssa_refresh (area->ospf, lsa, old); if (!new) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): " "could not refresh translated LSA Id %s", inet_ntoa (old->data->id)); } } else { /* no existing external route for this LSA Id * originate translated LSA */ if ((new = ospf_translated_nssa_originate (area->ospf, lsa)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): Could not translate " "Type-7 for %s to Type-5", inet_ntoa (lsa->data->id)); return 1; } } /* Area where Aggregate testing will be inserted, just like summary advertisements */ /* ospf_abr_check_nssa_range (p_arg, lsa-> cost, lsa -> area); */ return 0; } static 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... */ } 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; u_int32_t full_cost; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): Start"); if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) full_cost = OSPF_STUB_MAX_METRIC_SUMMARY_COST; else full_cost = cost; old = ospf_lsa_lookup_by_prefix (area->lsdb, OSPF_SUMMARY_LSA, (struct prefix_ipv4 *) p, area->ospf->router_id); if (old) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): old summary found"); sl = (struct summary_lsa *) old->data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "old metric: %d, new metric: %d", GET_METRIC (sl->metric), cost); if ((GET_METRIC (sl->metric) == full_cost) && ((old->flags & OSPF_LSA_IN_MAXAGE) == 0)) { /* unchanged. simply reapprove it */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "old summary approved"); SET_FLAG (old->flags, OSPF_LSA_APPROVED); } else { /* LSA is changed, refresh it */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "refreshing summary"); set_metric (old, full_cost); lsa = ospf_lsa_refresh (area->ospf, old); if (!lsa) { char buf[INET_ADDRSTRLEN + 3]; /* ipv4 and /XX */ prefix2str ((struct prefix *) p, buf, sizeof(buf)); zlog_warn ("%s: Could not refresh %s to %s", __func__, buf, inet_ntoa (area->area_id)); return; } SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); /* This will flood through area. */ } } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "creating new summary"); lsa = ospf_summary_lsa_originate ( (struct prefix_ipv4 *)p, full_cost, area); /* This will flood through area. */ if (!lsa) { char buf[INET_ADDRSTRLEN + 3]; /* ipv4 and /XX */ prefix2str ((struct prefix *)p, buf, sizeof(buf)); zlog_warn ("%s: Could not originate %s to %s", __func__, buf, inet_ntoa (area->area_id)); return; } SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "flooding new version of summary"); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): Stop"); } static int ospf_abr_nexthops_belong_to_area (struct ospf_route *or, struct ospf_area *area) { struct listnode *node, *nnode; struct ospf_path *path; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) for (ALL_LIST_ELEMENTS_RO (area->oiflist, nnode, oi)) if (oi->ifp && oi->ifp->ifindex == path->ifindex) return 1; return 0; } static int ospf_abr_should_accept (struct prefix_ipv4 *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; } static int ospf_abr_plist_in_check (struct ospf_area *area, struct ospf_route *or, struct prefix_ipv4 *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; } static int ospf_abr_plist_out_check (struct ospf_area *area, struct ospf_route *or, struct prefix_ipv4 *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; } static void ospf_abr_announce_network (struct ospf *ospf, struct prefix_ipv4 *p, struct ospf_route *or) { struct ospf_area_range *range; struct ospf_area *area, *or_area; struct listnode *node; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network(): Start"); or_area = ospf_area_lookup_by_area_id (ospf, or->u.std.area_id); assert (or_area); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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 (p, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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, p)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("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_debug ("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_debug ("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, area); else ospf_abr_announce_network_to_area (p, or->cost, area); } } } static int ospf_abr_should_announce (struct ospf *ospf, struct prefix_ipv4 *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; } static 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 ) */ struct listnode *node; struct ospf_area *area; struct route_node *rn; struct ospf_lsa *lsa; if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_process_nssa_translates(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (! area->NSSATranslatorState) continue; /* skip if not translator */ if (area->external_routing != OSPF_AREA_NSSA) continue; /* skip if not Nssa Area */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("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_debug ("ospf_abr_process_nssa_translates(): Stop"); } static 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_debug ("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_debug ("ospf_abr_process_network_rt(): area %s no longer exists", inet_ntoa (or->u.std.area_id)); continue; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_abr_process_network_rt(): " "this is an External router, skipping"); continue; } if (or->cost >= OSPF_LS_INFINITY) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("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, (struct prefix_ipv4 *) &rn->p, or)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug("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, (struct prefix_ipv4 *) &rn->p)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug("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_debug ("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_debug ("ospf_abr_process_network_rt(): ALT ABR: " "No BB connection, skip not intra-area routes"); continue; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): announcing"); ospf_abr_announce_network (ospf, (struct prefix_ipv4 *)&rn->p, or); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): Stop"); } static 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_debug ("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_debug ("ospf_abr_announce_rtr_to_area(): old summary found"); slsa = (struct summary_lsa *) old->data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "old metric: %d, new metric: %d", GET_METRIC (slsa->metric), cost); } if (old && (GET_METRIC (slsa->metric) == cost) && ((old->flags & OSPF_LSA_IN_MAXAGE) == 0)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): old summary approved"); SET_FLAG (old->flags, OSPF_LSA_APPROVED); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): 2.2"); if (old) { set_metric (old, cost); lsa = ospf_lsa_refresh (area->ospf, old); } else lsa = ospf_summary_asbr_lsa_originate (p, cost, area); if (!lsa) { char buf[INET_ADDRSTRLEN + 3]; /* ipv4 and /XX */ prefix2str ((struct prefix *)p, buf, sizeof(buf)); zlog_warn ("%s: Could not refresh/originate %s to %s", __func__, buf, inet_ntoa (area->area_id)); return; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_abr_announce_rtr_to_area(): Stop"); } static void ospf_abr_announce_rtr (struct ospf *ospf, struct prefix_ipv4 *p, struct ospf_route *or) { struct listnode *node; struct ospf_area *area; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_abr_announce_rtr(): " "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_debug ("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_debug ("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_debug ("ospf_abr_announce_rtr(): Stop"); } static 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_debug ("ospf_abr_process_router_rt(): Start"); for (rn = route_top (rt); rn; rn = route_next (rn)) { struct listnode *node, *nnode; char flag = 0; struct ospf_route *best = NULL; if (rn->info == NULL) continue; l = rn->info; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): this is a route to %s", inet_ntoa (rn->p.u.prefix4)); for (ALL_LIST_ELEMENTS (l, node, nnode, or)) { if (!ospf_area_lookup_by_area_id (ospf, or->u.std.area_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("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_debug ("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_debug ("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_debug ("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_debug("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_debug ("ospf_abr_process_router_rt(): Stop"); } static 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_debug ("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_debug ("ospf_abr_unapprove_translates(): " "approved unset on link id %s", inet_ntoa (lsa->data->id)); } if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_unapprove_translates(): Stop"); } static void ospf_abr_unapprove_summaries (struct ospf *ospf) { struct listnode *node; struct ospf_area *area; struct route_node *rn; struct ospf_lsa *lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): " "considering area %s", inet_ntoa (area->area_id)); LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) if (ospf_lsa_is_self_originated (ospf, lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): " "approved unset on summary link id %s", inet_ntoa (lsa->data->id)); UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); } LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) if (ospf_lsa_is_self_originated (ospf, lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): " "approved unset on asbr-summary link id %s", inet_ntoa (lsa->data->id)); UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): Stop"); } static void ospf_abr_prepare_aggregates (struct ospf *ospf) { struct listnode *node; struct route_node *rn; struct ospf_area_range *range; struct ospf_area *area; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_prepare_aggregates(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { 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_debug ("ospf_abr_prepare_aggregates(): Stop"); } static void ospf_abr_announce_aggregates (struct ospf *ospf) { struct ospf_area *area, *ar; struct ospf_area_range *range; struct route_node *rn; struct prefix p; struct listnode *node, *n; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_abr_announce_aggregates():" " discarding suppress-ranges"); continue; } p.family = AF_INET; p.u.prefix4 = range->addr; p.prefixlen = range->masklen; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates():" " this is range: %s/%d", inet_ntoa (p.u.prefix4), p.prefixlen); if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) { p.family = AF_INET; p.u.prefix4 = range->subst_addr; p.prefixlen = range->subst_masklen; } if (range->specifics) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates(): active range"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, n, ar)) { 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_debug ("ospf_abr_announce_aggregates(): Skipping " "announcement of BB aggregate into" " a transit area"); continue; } ospf_abr_announce_network_to_area ((struct prefix_ipv4 *)&p, range->cost, ar); } } } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates(): Stop"); } static void ospf_abr_send_nssa_aggregates (struct ospf *ospf) /* temporarily turned off */ { struct 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_debug ("ospf_abr_send_nssa_aggregates(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (! area->NSSATranslatorState) continue; if (IS_DEBUG_OSPF_NSSA) zlog_debug ("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_debug ("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_debug ("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_debug ("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); } } /* all area ranges*/ } /* all areas */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_send_nssa_aggregates(): Stop"); } static void ospf_abr_announce_stub_defaults (struct ospf *ospf) { struct listnode *node; struct ospf_area *area; struct prefix_ipv4 p; if (! IS_OSPF_ABR (ospf)) return; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): Start"); p.family = AF_INET; p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; p.prefixlen = 0; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): looking at area %s", inet_ntoa (area->area_id)); if ( (area->external_routing != OSPF_AREA_STUB) && (area->external_routing != OSPF_AREA_NSSA) ) continue; if (OSPF_IS_AREA_BACKBONE (area)) continue; /* Sanity Check */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): " "announcing 0.0.0.0/0 to area %s", inet_ntoa (area->area_id)); ospf_abr_announce_network_to_area (&p, area->default_cost, area); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): Stop"); } static 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; } static 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_debug ("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_debug ("ospf_abr_remove_unapproved_translates(): Stop"); } static void ospf_abr_remove_unapproved_summaries (struct ospf *ospf) { struct listnode *node; struct ospf_area *area; struct route_node *rn; struct ospf_lsa *lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_remove_unapproved_summaries(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_abr_remove_unapproved_summaries(): Stop"); } static void ospf_abr_manage_discard_routes (struct ospf *ospf) { struct listnode *node, *nnode; struct route_node *rn; struct ospf_area *area; struct ospf_area_range *range; for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) 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 (ospf->new_table, (struct prefix_ipv4 *) &rn->p); } } /* 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. */ static void ospf_abr_nssa_task (struct ospf *ospf) /* called only if any_nssa */ { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("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_debug ("ospf_abr_nssa_task(): Start"); /* For all Global Entries flagged "local-translate", unset APPROVED */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("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_debug ("ospf_abr_nssa_task(): NSSA initialize aggregates"); ospf_abr_prepare_aggregates (ospf); /*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_debug ("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_debug("ospf_abr_nssa_task(): send NSSA aggregates"); ospf_abr_send_nssa_aggregates (ospf); /*TURNED OFF FOR NOW */ /* Send any NSSA defaults as Type-5 *if (IS_DEBUG_OSPF_NSSA) * zlog_debug ("ospf_abr_nssa_task(): announce nssa defaults"); *ospf_abr_announce_nssa_defaults (ospf); * havnt a clue what above is supposed to do. */ /* Flush any unapproved previous translates from Global Data Base */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("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_debug ("ospf_abr_nssa_task(): Stop"); } /* 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_debug ("ospf_abr_task(): Start"); if (ospf->new_table == NULL || ospf->new_rtrs == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): Routing tables are not yet ready"); return; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): unapprove summaries"); ospf_abr_unapprove_summaries (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): prepare aggregates"); ospf_abr_prepare_aggregates (ospf); if (IS_OSPF_ABR (ospf)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): process network RT"); ospf_abr_process_network_rt (ospf, ospf->new_table); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): process router RT"); ospf_abr_process_router_rt (ospf, ospf->new_rtrs); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): announce aggregates"); ospf_abr_announce_aggregates (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): announce stub defaults"); ospf_abr_announce_stub_defaults (ospf); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): remove unapproved summaries"); ospf_abr_remove_unapproved_summaries (ospf); ospf_abr_manage_discard_routes (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): Stop"); } static 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_debug ("Running ABR task on timer"); ospf_check_abr_status (ospf); ospf_abr_nssa_check_status (ospf); ospf_abr_task (ospf); ospf_abr_nssa_task (ospf); /* if nssa-abr, then scan Type-7 LSDB */ return 0; } void ospf_schedule_abr_task (struct ospf *ospf) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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); } quagga-1.2.4/ospfd/ospf_abr.h000066400000000000000000000056321325323223500160500ustar00rootroot00000000000000/* * 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 -1U }; /* Prototypes. */ extern struct ospf_area_range *ospf_area_range_lookup (struct ospf_area *, struct prefix_ipv4 *); extern struct ospf_area_range *ospf_some_area_range_match (struct prefix_ipv4 *); extern struct ospf_area_range *ospf_area_range_lookup_next (struct ospf_area *, struct in_addr *, int); extern int ospf_area_range_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, int); extern int ospf_area_range_cost_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, u_int32_t); extern int ospf_area_range_unset (struct ospf *, struct in_addr, struct prefix_ipv4 *); extern int ospf_area_range_substitute_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, struct prefix_ipv4 *); extern int ospf_area_range_substitute_unset (struct ospf *, struct in_addr, struct prefix_ipv4 *); extern struct ospf_area_range *ospf_area_range_match_any (struct ospf *, struct prefix_ipv4 *); extern int ospf_area_range_active (struct ospf_area_range *); extern int ospf_act_bb_connection (struct ospf *); extern void ospf_check_abr_status (struct ospf *); extern void ospf_abr_task (struct ospf *); extern void ospf_schedule_abr_task (struct ospf *); extern void ospf_abr_announce_network_to_area (struct prefix_ipv4 *, u_int32_t, struct ospf_area *); #endif /* _ZEBRA_OSPF_ABR_H */ quagga-1.2.4/ospfd/ospf_api.c000066400000000000000000000370061325323223500160500ustar00rootroot00000000000000/* * API message handling module for OSPF daemon and client. * Copyright (C) 2001, 2002 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 SUPPORT_OSPF_API #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 "buffer.h" #include "network.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_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_api.h" /* For debugging only, will be removed */ void api_opaque_lsa_print (struct lsa_header *data) { struct opaque_lsa { struct lsa_header header; u_char mydata[]; }; struct opaque_lsa *olsa; int opaquelen; int i; ospf_lsa_header_dump (data); olsa = (struct opaque_lsa *) data; opaquelen = ntohs (data->length) - OSPF_LSA_HEADER_SIZE; zlog_debug ("apiserver_lsa_print: opaquelen=%d\n", opaquelen); for (i = 0; i < opaquelen; i++) { zlog_debug ("0x%x ", olsa->mydata[i]); } zlog_debug ("\n"); } /* ----------------------------------------------------------- * Generic messages * ----------------------------------------------------------- */ struct msg * msg_new (u_char msgtype, void *msgbody, u_int32_t seqnum, u_int16_t msglen) { struct msg *new; new = XCALLOC (MTYPE_OSPF_API_MSG, sizeof (struct msg)); new->hdr.version = OSPF_API_VERSION; new->hdr.msgtype = msgtype; new->hdr.msglen = htons (msglen); new->hdr.msgseq = htonl (seqnum); new->s = stream_new (msglen); assert (new->s); stream_put (new->s, msgbody, msglen); return new; } /* Duplicate a message by copying content. */ struct msg * msg_dup (struct msg *msg) { struct msg *new; assert (msg); new = msg_new (msg->hdr.msgtype, STREAM_DATA (msg->s), ntohl (msg->hdr.msgseq), ntohs (msg->hdr.msglen)); return new; } /* XXX only for testing, will be removed */ struct nametab { int value; const char *name; }; const char * ospf_api_typename (int msgtype) { struct nametab NameTab[] = { { MSG_REGISTER_OPAQUETYPE, "Register opaque-type", }, { MSG_UNREGISTER_OPAQUETYPE, "Unregister opaque-type", }, { MSG_REGISTER_EVENT, "Register event", }, { MSG_SYNC_LSDB, "Sync LSDB", }, { MSG_ORIGINATE_REQUEST, "Originate request", }, { MSG_DELETE_REQUEST, "Delete request", }, { MSG_REPLY, "Reply", }, { MSG_READY_NOTIFY, "Ready notify", }, { MSG_LSA_UPDATE_NOTIFY, "LSA update notify", }, { MSG_LSA_DELETE_NOTIFY, "LSA delete notify", }, { MSG_NEW_IF, "New interface", }, { MSG_DEL_IF, "Del interface", }, { MSG_ISM_CHANGE, "ISM change", }, { MSG_NSM_CHANGE, "NSM change", }, }; int i, n = array_size(NameTab); const char *name = NULL; for (i = 0; i < n; i++) { if (NameTab[i].value == msgtype) { name = NameTab[i].name; break; } } return name ? name : "?"; } const char * ospf_api_errname (int errcode) { struct nametab NameTab[] = { { OSPF_API_OK, "OK", }, { OSPF_API_NOSUCHINTERFACE, "No such interface", }, { OSPF_API_NOSUCHAREA, "No such area", }, { OSPF_API_NOSUCHLSA, "No such LSA", }, { OSPF_API_ILLEGALLSATYPE, "Illegal LSA type", }, { OSPF_API_OPAQUETYPEINUSE, "Opaque type in use", }, { OSPF_API_OPAQUETYPENOTREGISTERED, "Opaque type not registered", }, { OSPF_API_NOTREADY, "Not ready", }, { OSPF_API_NOMEMORY, "No memory", }, { OSPF_API_ERROR, "Other error", }, { OSPF_API_UNDEF, "Undefined", }, }; int i, n = array_size(NameTab); const char *name = NULL; for (i = 0; i < n; i++) { if (NameTab[i].value == errcode) { name = NameTab[i].name; break; } } return name ? name : "?"; } void msg_print (struct msg *msg) { if (!msg) { zlog_debug ("msg_print msg=NULL!\n"); return; } #ifdef ORIGINAL_CODING zlog_debug ("msg=%p msgtype=%d msglen=%d msgseq=%d streamdata=%p streamsize=%lu\n", msg, msg->hdr.msgtype, ntohs (msg->hdr.msglen), ntohl (msg->hdr.msgseq), STREAM_DATA (msg->s), STREAM_SIZE (msg->s)); #else /* ORIGINAL_CODING */ /* API message common header part. */ zlog_debug ("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%zd)", ospf_api_typename (msg->hdr.msgtype), msg->hdr.msgtype, ntohs (msg->hdr.msglen), (unsigned long) ntohl (msg->hdr.msgseq), STREAM_DATA (msg->s), STREAM_SIZE (msg->s)); /* API message body part. */ #ifdef ndef /* Generic Hex/Ascii dump */ DumpBuf (STREAM_DATA (msg->s), STREAM_SIZE (msg->s)); /* Sorry, deleted! */ #else /* ndef */ /* Message-type dependent dump function. */ #endif /* ndef */ return; #endif /* ORIGINAL_CODING */ } void msg_free (struct msg *msg) { if (msg->s) stream_free (msg->s); XFREE (MTYPE_OSPF_API_MSG, msg); } /* Set sequence number of message */ void msg_set_seq (struct msg *msg, u_int32_t seqnr) { assert (msg); msg->hdr.msgseq = htonl (seqnr); } /* Get sequence number of message */ u_int32_t msg_get_seq (struct msg *msg) { assert (msg); return ntohl (msg->hdr.msgseq); } /* ----------------------------------------------------------- * Message fifo queues * ----------------------------------------------------------- */ struct msg_fifo * msg_fifo_new () { return XCALLOC (MTYPE_OSPF_API_FIFO, sizeof (struct msg_fifo)); } /* Add new message to fifo. */ void msg_fifo_push (struct msg_fifo *fifo, struct msg *msg) { if (fifo->tail) fifo->tail->next = msg; else fifo->head = msg; fifo->tail = msg; fifo->count++; } /* Remove first message from fifo. */ struct msg * msg_fifo_pop (struct msg_fifo *fifo) { struct msg *msg; msg = fifo->head; if (msg) { fifo->head = msg->next; if (fifo->head == NULL) fifo->tail = NULL; fifo->count--; } return msg; } /* Return first fifo entry but do not remove it. */ struct msg * msg_fifo_head (struct msg_fifo *fifo) { return fifo->head; } /* Flush message fifo. */ void msg_fifo_flush (struct msg_fifo *fifo) { struct msg *op; struct msg *next; for (op = fifo->head; op; op = next) { next = op->next; msg_free (op); } fifo->head = fifo->tail = NULL; fifo->count = 0; } /* Free API message fifo. */ void msg_fifo_free (struct msg_fifo *fifo) { msg_fifo_flush (fifo); XFREE (MTYPE_OSPF_API_FIFO, fifo); } struct msg * msg_read (int fd) { struct msg *msg; struct apimsghdr hdr; u_char buf[OSPF_API_MAX_MSG_SIZE]; int bodylen; int rlen; /* Read message header */ rlen = readn (fd, (u_char *) &hdr, sizeof (struct apimsghdr)); if (rlen < 0) { zlog_warn ("msg_read: readn %s", safe_strerror (errno)); return NULL; } else if (rlen == 0) { zlog_warn ("msg_read: Connection closed by peer"); return NULL; } else if (rlen != sizeof (struct apimsghdr)) { zlog_warn ("msg_read: Cannot read message header!"); return NULL; } /* Check version of API protocol */ if (hdr.version != OSPF_API_VERSION) { zlog_warn ("msg_read: OSPF API protocol version mismatch"); return NULL; } /* Determine body length. */ bodylen = ntohs (hdr.msglen); if (bodylen > 0) { /* Read message body */ rlen = readn (fd, buf, bodylen); if (rlen < 0) { zlog_warn ("msg_read: readn %s", safe_strerror (errno)); return NULL; } else if (rlen == 0) { zlog_warn ("msg_read: Connection closed by peer"); return NULL; } else if (rlen != bodylen) { zlog_warn ("msg_read: Cannot read message body!"); return NULL; } } /* Allocate new message */ msg = msg_new (hdr.msgtype, buf, ntohl (hdr.msgseq), ntohs (hdr.msglen)); return msg; } int msg_write (int fd, struct msg *msg) { u_char buf[OSPF_API_MAX_MSG_SIZE]; int l; int wlen; assert (msg); assert (msg->s); /* Length of message including header */ l = sizeof (struct apimsghdr) + ntohs (msg->hdr.msglen); /* Make contiguous memory buffer for message */ memcpy (buf, &msg->hdr, sizeof (struct apimsghdr)); memcpy (buf + sizeof (struct apimsghdr), STREAM_DATA (msg->s), ntohs (msg->hdr.msglen)); wlen = writen (fd, buf, l); if (wlen < 0) { zlog_warn ("msg_write: writen %s", safe_strerror (errno)); return -1; } else if (wlen == 0) { zlog_warn ("msg_write: Connection closed by peer"); return -1; } else if (wlen != l) { zlog_warn ("msg_write: Cannot write API message"); return -1; } return 0; } /* ----------------------------------------------------------- * Specific messages * ----------------------------------------------------------- */ struct msg * new_msg_register_opaque_type (u_int32_t seqnum, u_char ltype, u_char otype) { struct msg_register_opaque_type rmsg; rmsg.lsatype = ltype; rmsg.opaquetype = otype; memset (&rmsg.pad, 0, sizeof (rmsg.pad)); return msg_new (MSG_REGISTER_OPAQUETYPE, &rmsg, seqnum, sizeof (struct msg_register_opaque_type)); } struct msg * new_msg_register_event (u_int32_t seqnum, struct lsa_filter_type *filter) { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_register_event *emsg; size_t len; emsg = (struct msg_register_event *) buf; len = sizeof (struct msg_register_event) + filter->num_areas * sizeof (struct in_addr); emsg->filter.typemask = htons (filter->typemask); emsg->filter.origin = filter->origin; emsg->filter.num_areas = filter->num_areas; if (len > sizeof (buf)) len = sizeof(buf); /* API broken - missing memcpy to fill data */ return msg_new (MSG_REGISTER_EVENT, emsg, seqnum, len); } struct msg * new_msg_sync_lsdb (u_int32_t seqnum, struct lsa_filter_type *filter) { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_sync_lsdb *smsg; size_t len; smsg = (struct msg_sync_lsdb *) buf; len = sizeof (struct msg_sync_lsdb) + filter->num_areas * sizeof (struct in_addr); smsg->filter.typemask = htons (filter->typemask); smsg->filter.origin = filter->origin; smsg->filter.num_areas = filter->num_areas; if (len > sizeof (buf)) len = sizeof(buf); /* API broken - missing memcpy to fill data */ return msg_new (MSG_SYNC_LSDB, smsg, seqnum, len); } struct msg * new_msg_originate_request (u_int32_t seqnum, struct in_addr ifaddr, struct in_addr area_id, struct lsa_header *data) { struct msg_originate_request *omsg; size_t omsglen; char buf[OSPF_API_MAX_MSG_SIZE]; omsg = (struct msg_originate_request *) buf; omsg->ifaddr = ifaddr; omsg->area_id = area_id; omsglen = ntohs (data->length); if (omsglen > sizeof (buf) - offsetof (struct msg_originate_request, data)) omsglen = sizeof (buf) - offsetof (struct msg_originate_request, data); memcpy (&omsg->data, data, omsglen); omsglen += sizeof (struct msg_originate_request) - sizeof (struct lsa_header); return msg_new (MSG_ORIGINATE_REQUEST, omsg, seqnum, omsglen); } struct msg * new_msg_delete_request (u_int32_t seqnum, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id) { struct msg_delete_request dmsg; dmsg.area_id = area_id; dmsg.lsa_type = lsa_type; dmsg.opaque_type = opaque_type; dmsg.opaque_id = htonl (opaque_id); memset (&dmsg.pad, 0, sizeof (dmsg.pad)); return msg_new (MSG_DELETE_REQUEST, &dmsg, seqnum, sizeof (struct msg_delete_request)); } struct msg * new_msg_reply (u_int32_t seqnr, u_char rc) { struct msg *msg; struct msg_reply rmsg; /* Set return code */ rmsg.errcode = rc; memset (&rmsg.pad, 0, sizeof (rmsg.pad)); msg = msg_new (MSG_REPLY, &rmsg, seqnr, sizeof (struct msg_reply)); return msg; } struct msg * new_msg_ready_notify (u_int32_t seqnr, u_char lsa_type, u_char opaque_type, struct in_addr addr) { struct msg_ready_notify rmsg; rmsg.lsa_type = lsa_type; rmsg.opaque_type = opaque_type; memset (&rmsg.pad, 0, sizeof (rmsg.pad)); rmsg.addr = addr; return msg_new (MSG_READY_NOTIFY, &rmsg, seqnr, sizeof (struct msg_ready_notify)); } struct msg * new_msg_new_if (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr area_id) { struct msg_new_if nmsg; nmsg.ifaddr = ifaddr; nmsg.area_id = area_id; return msg_new (MSG_NEW_IF, &nmsg, seqnr, sizeof (struct msg_new_if)); } struct msg * new_msg_del_if (u_int32_t seqnr, struct in_addr ifaddr) { struct msg_del_if dmsg; dmsg.ifaddr = ifaddr; return msg_new (MSG_DEL_IF, &dmsg, seqnr, sizeof (struct msg_del_if)); } struct msg * new_msg_ism_change (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr area_id, u_char status) { struct msg_ism_change imsg; imsg.ifaddr = ifaddr; imsg.area_id = area_id; imsg.status = status; memset (&imsg.pad, 0, sizeof (imsg.pad)); return msg_new (MSG_ISM_CHANGE, &imsg, seqnr, sizeof (struct msg_ism_change)); } struct msg * new_msg_nsm_change (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status) { struct msg_nsm_change nmsg; nmsg.ifaddr = ifaddr; nmsg.nbraddr = nbraddr; nmsg.router_id = router_id; nmsg.status = status; memset (&nmsg.pad, 0, sizeof (nmsg.pad)); return msg_new (MSG_NSM_CHANGE, &nmsg, seqnr, sizeof (struct msg_nsm_change)); } struct msg * new_msg_lsa_change_notify (u_char msgtype, u_int32_t seqnum, struct in_addr ifaddr, struct in_addr area_id, u_char is_self_originated, struct lsa_header *data) { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_lsa_change_notify *nmsg; size_t len; assert (data); nmsg = (struct msg_lsa_change_notify *) buf; nmsg->ifaddr = ifaddr; nmsg->area_id = area_id; nmsg->is_self_originated = is_self_originated; memset (&nmsg->pad, 0, sizeof (nmsg->pad)); len = ntohs (data->length); if (len > sizeof (buf) - offsetof (struct msg_lsa_change_notify, data)) len = sizeof (buf) - offsetof (struct msg_lsa_change_notify, data); memcpy (&nmsg->data, data, len); len += sizeof (struct msg_lsa_change_notify) - sizeof (struct lsa_header); return msg_new (msgtype, nmsg, seqnum, len); } #endif /* SUPPORT_OSPF_API */ quagga-1.2.4/ospfd/ospf_api.h000066400000000000000000000251171325323223500160550ustar00rootroot00000000000000/* * API message handling module for OSPF daemon and client. * Copyright (C) 2001, 2002 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 used both by the OSPFd and client applications to define message formats used for communication. */ #ifndef _OSPF_API_H #define _OSPF_API_H #define OSPF_API_VERSION 1 /* MTYPE definition is not reflected to "memory.h". */ #define MTYPE_OSPF_API_MSG MTYPE_TMP #define MTYPE_OSPF_API_FIFO MTYPE_TMP /* Default API server port to accept connection request from client-side. */ /* This value could be overridden by "ospfapi" entry in "/etc/services". */ #define OSPF_API_SYNC_PORT 2607 /* ----------------------------------------------------------- * Generic messages * ----------------------------------------------------------- */ /* Message header structure, fields are in network byte order and aligned to four octets. */ struct apimsghdr { u_char version; /* OSPF API protocol version */ u_char msgtype; /* Type of message */ u_int16_t msglen; /* Length of message w/o header */ u_int32_t msgseq; /* Sequence number */ }; /* Message representation with header and body */ struct msg { struct msg *next; /* to link into fifo */ /* Message header */ struct apimsghdr hdr; /* Message body */ struct stream *s; }; /* Prototypes for generic messages. */ extern struct msg *msg_new (u_char msgtype, void *msgbody, u_int32_t seqnum, u_int16_t msglen); extern struct msg *msg_dup (struct msg *msg); extern void msg_print (struct msg *msg); /* XXX debug only */ extern void msg_free (struct msg *msg); struct msg *msg_read (int fd); extern int msg_write (int fd, struct msg *msg); /* For requests, the message sequence number is between MIN_SEQ and MAX_SEQ. For notifications, the sequence number is 0. */ #define MIN_SEQ 1 #define MAX_SEQ 2147483647 extern void msg_set_seq (struct msg *msg, u_int32_t seqnr); extern u_int32_t msg_get_seq (struct msg *msg); /* ----------------------------------------------------------- * Message fifo queues * ----------------------------------------------------------- */ /* Message queue structure. */ struct msg_fifo { unsigned long count; struct msg *head; struct msg *tail; }; /* Prototype for message fifo queues. */ extern struct msg_fifo *msg_fifo_new (void); extern void msg_fifo_push (struct msg_fifo *, struct msg *msg); extern struct msg *msg_fifo_pop (struct msg_fifo *fifo); extern struct msg *msg_fifo_head (struct msg_fifo *fifo); extern void msg_fifo_flush (struct msg_fifo *fifo); extern void msg_fifo_free (struct msg_fifo *fifo); /* ----------------------------------------------------------- * Specific message type and format definitions * ----------------------------------------------------------- */ /* Messages to OSPF daemon. */ #define MSG_REGISTER_OPAQUETYPE 1 #define MSG_UNREGISTER_OPAQUETYPE 2 #define MSG_REGISTER_EVENT 3 #define MSG_SYNC_LSDB 4 #define MSG_ORIGINATE_REQUEST 5 #define MSG_DELETE_REQUEST 6 /* Messages from OSPF daemon. */ #define MSG_REPLY 10 #define MSG_READY_NOTIFY 11 #define MSG_LSA_UPDATE_NOTIFY 12 #define MSG_LSA_DELETE_NOTIFY 13 #define MSG_NEW_IF 14 #define MSG_DEL_IF 15 #define MSG_ISM_CHANGE 16 #define MSG_NSM_CHANGE 17 struct msg_register_opaque_type { u_char lsatype; u_char opaquetype; u_char pad[2]; /* padding */ }; struct msg_unregister_opaque_type { u_char lsatype; u_char opaquetype; u_char pad[2]; /* padding */ }; /* Power2 is needed to convert LSA types into bit positions, * see typemask below. Type definition starts at 1, so * Power2[0] is not used. */ #ifdef ORIGINAL_CODING static const u_int16_t Power2[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000 }; #else static const u_int16_t Power2[] = { 0, (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10), (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15) }; #endif /* ORIGINAL_CODING */ struct lsa_filter_type { u_int16_t typemask; /* bitmask for selecting LSA types (1..16) */ u_char origin; /* selects according to origin. */ #define NON_SELF_ORIGINATED 0 #define SELF_ORIGINATED (OSPF_LSA_SELF) #define ANY_ORIGIN 2 u_char num_areas; /* number of areas in the filter. */ /* areas, if any, go here. */ }; struct msg_register_event { struct lsa_filter_type filter; }; struct msg_sync_lsdb { struct lsa_filter_type filter; }; struct msg_originate_request { /* Used for LSA type 9 otherwise ignored */ struct in_addr ifaddr; /* Used for LSA type 10 otherwise ignored */ struct in_addr area_id; /* LSA header and LSA-specific part */ struct lsa_header data; }; struct msg_delete_request { struct in_addr area_id; /* "0.0.0.0" for AS-external opaque LSAs */ u_char lsa_type; u_char opaque_type; u_char pad[2]; /* padding */ u_int32_t opaque_id; }; struct msg_reply { signed char errcode; #define OSPF_API_OK 0 #define OSPF_API_NOSUCHINTERFACE (-1) #define OSPF_API_NOSUCHAREA (-2) #define OSPF_API_NOSUCHLSA (-3) #define OSPF_API_ILLEGALLSATYPE (-4) #define OSPF_API_OPAQUETYPEINUSE (-5) #define OSPF_API_OPAQUETYPENOTREGISTERED (-6) #define OSPF_API_NOTREADY (-7) #define OSPF_API_NOMEMORY (-8) #define OSPF_API_ERROR (-9) #define OSPF_API_UNDEF (-10) u_char pad[3]; /* padding to four byte alignment */ }; /* Message to tell client application that it ospf daemon is * ready to accept opaque LSAs for a given interface or area. */ struct msg_ready_notify { u_char lsa_type; u_char opaque_type; u_char pad[2]; /* padding */ struct in_addr addr; /* interface address or area address */ }; /* These messages have a dynamic length depending on the embodied LSA. They are aligned to four octets. msg_lsa_change_notify is used for both LSA update and LSAs delete. */ struct msg_lsa_change_notify { /* Used for LSA type 9 otherwise ignored */ struct in_addr ifaddr; /* Area ID. Not valid for AS-External and Opaque11 LSAs. */ struct in_addr area_id; u_char is_self_originated; /* 1 if self originated. */ u_char pad[3]; struct lsa_header data; }; struct msg_new_if { struct in_addr ifaddr; /* interface IP address */ struct in_addr area_id; /* area this interface belongs to */ }; struct msg_del_if { struct in_addr ifaddr; /* interface IP address */ }; struct msg_ism_change { struct in_addr ifaddr; /* interface IP address */ struct in_addr area_id; /* area this interface belongs to */ u_char status; /* interface status (up/down) */ u_char pad[3]; /* not used */ }; struct msg_nsm_change { struct in_addr ifaddr; /* attached interface */ struct in_addr nbraddr; /* Neighbor interface address */ struct in_addr router_id; /* Router ID of neighbor */ u_char status; /* NSM status */ u_char pad[3]; }; /* We make use of a union to define a structure that covers all possible API messages. This allows us to find out how much memory needs to be reserved for the largest API message. */ struct apimsg { struct apimsghdr hdr; union { struct msg_register_opaque_type register_opaque_type; struct msg_register_event register_event; struct msg_sync_lsdb sync_lsdb; struct msg_originate_request originate_request; struct msg_delete_request delete_request; struct msg_reply reply; struct msg_ready_notify ready_notify; struct msg_new_if new_if; struct msg_del_if del_if; struct msg_ism_change ism_change; struct msg_nsm_change nsm_change; struct msg_lsa_change_notify lsa_change_notify; } u; }; #define OSPF_API_MAX_MSG_SIZE (sizeof(struct apimsg) + OSPF_MAX_LSA_SIZE) /* ----------------------------------------------------------- * Prototypes for specific messages * ----------------------------------------------------------- */ /* For debugging only. */ extern void api_opaque_lsa_print (struct lsa_header *data); /* Messages sent by client */ extern struct msg *new_msg_register_opaque_type (u_int32_t seqnum, u_char ltype, u_char otype); extern struct msg *new_msg_register_event (u_int32_t seqnum, struct lsa_filter_type *filter); extern struct msg *new_msg_sync_lsdb (u_int32_t seqnum, struct lsa_filter_type *filter); extern struct msg *new_msg_originate_request (u_int32_t seqnum, struct in_addr ifaddr, struct in_addr area_id, struct lsa_header *data); extern struct msg *new_msg_delete_request (u_int32_t seqnum, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id); /* Messages sent by OSPF daemon */ extern struct msg *new_msg_reply (u_int32_t seqnum, u_char rc); extern struct msg *new_msg_ready_notify (u_int32_t seqnr, u_char lsa_type, u_char opaque_type, struct in_addr addr); extern struct msg *new_msg_new_if (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr area); extern struct msg *new_msg_del_if (u_int32_t seqnr, struct in_addr ifaddr); extern struct msg *new_msg_ism_change (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr area, u_char status); extern struct msg *new_msg_nsm_change (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status); /* msgtype is MSG_LSA_UPDATE_NOTIFY or MSG_LSA_DELETE_NOTIFY */ extern struct msg *new_msg_lsa_change_notify (u_char msgtype, u_int32_t seqnum, struct in_addr ifaddr, struct in_addr area_id, u_char is_self_originated, struct lsa_header *data); /* string printing functions */ extern const char *ospf_api_errname (int errcode); extern const char *ospf_api_typename (int msgtype); #endif /* _OSPF_API_H */ quagga-1.2.4/ospfd/ospf_apiserver.c000066400000000000000000002044101325323223500172720ustar00rootroot00000000000000/* * Server side of OSPF API. * Copyright (C) 2001, 2002 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 SUPPORT_OSPF_API #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 "buffer.h" #include #include "ospfd/ospfd.h" /* for "struct thread_master" */ #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_api.h" #include "ospfd/ospf_apiserver.h" /* This is an implementation of an API to the OSPF daemon that allows * external applications to access the OSPF daemon through socket * connections. The application can use this API to inject its own * opaque LSAs and flood them to other OSPF daemons. Other OSPF * daemons then receive these LSAs and inform applications through the * API by sending a corresponding message. The application can also * register to receive all LSA types (in addition to opaque types) and * use this information to reconstruct the OSPF's LSDB. The OSPF * daemon supports multiple applications concurrently. */ /* List of all active connections. */ struct list *apiserver_list; /* ----------------------------------------------------------- * Functions to lookup interfaces * ----------------------------------------------------------- */ struct ospf_interface * ospf_apiserver_if_lookup_by_addr (struct in_addr address) { struct listnode *node, *nnode; struct ospf_interface *oi; struct ospf *ospf; if (!(ospf = ospf_lookup ())) return NULL; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) if (oi->type != OSPF_IFTYPE_VIRTUALLINK) if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4)) return oi; return NULL; } struct ospf_interface * ospf_apiserver_if_lookup_by_ifp (struct interface *ifp) { struct listnode *node, *nnode; struct ospf_interface *oi; struct ospf *ospf; if (!(ospf = ospf_lookup ())) return NULL; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) if (oi->ifp == ifp) return oi; return NULL; } /* ----------------------------------------------------------- * Initialization * ----------------------------------------------------------- */ unsigned short ospf_apiserver_getport (void) { struct servent *sp = getservbyname ("ospfapi", "tcp"); return sp ? ntohs (sp->s_port) : OSPF_API_SYNC_PORT; } /* Initialize OSPF API module. Invoked from ospf_opaque_init() */ int ospf_apiserver_init (void) { int fd; int rc = -1; /* Create new socket for synchronous messages. */ fd = ospf_apiserver_serv_sock_family (ospf_apiserver_getport (), AF_INET); if (fd < 0) goto out; /* Schedule new thread that handles accepted connections. */ ospf_apiserver_event (OSPF_APISERVER_ACCEPT, fd, NULL); /* Initialize list that keeps track of all connections. */ apiserver_list = list_new (); /* Register opaque-independent call back functions. These functions are invoked on ISM, NSM changes and LSA update and LSA deletes */ rc = ospf_register_opaque_functab (0 /* all LSAs */, 0 /* all opaque types */, ospf_apiserver_new_if, ospf_apiserver_del_if, ospf_apiserver_ism_change, ospf_apiserver_nsm_change, NULL, NULL, NULL, NULL, /* ospf_apiserver_show_info */ NULL, /* originator_func */ NULL, /* ospf_apiserver_lsa_refresher */ ospf_apiserver_lsa_update, ospf_apiserver_lsa_delete); if (rc != 0) { zlog_warn ("ospf_apiserver_init: Failed to register opaque type [0/0]"); } rc = 0; out: return rc; } /* Terminate OSPF API module. */ void ospf_apiserver_term (void) { struct ospf_apiserver *apiserv; /* Unregister wildcard [0/0] type */ ospf_delete_opaque_functab (0 /* all LSAs */, 0 /* all opaque types */); /* * Free all client instances. ospf_apiserver_free removes the node * from the list, so we examine the head of the list anew each time. */ while ( apiserver_list && (apiserv = listgetdata (listhead (apiserver_list))) != NULL) ospf_apiserver_free (apiserv); /* Free client list itself */ if (apiserver_list) list_delete (apiserver_list); /* Free wildcard list */ /* XXX */ } static struct ospf_apiserver * lookup_apiserver (u_char lsa_type, u_char opaque_type) { struct listnode *n1, *n2; struct registered_opaque_type *r; struct ospf_apiserver *apiserv, *found = NULL; /* XXX: this approaches O(n**2) */ for (ALL_LIST_ELEMENTS_RO (apiserver_list, n1, apiserv)) { for (ALL_LIST_ELEMENTS_RO (apiserv->opaque_types, n2, r)) if (r->lsa_type == lsa_type && r->opaque_type == opaque_type) { found = apiserv; goto out; } } out: return found; } static struct ospf_apiserver * lookup_apiserver_by_lsa (struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct ospf_apiserver *found = NULL; if (IS_OPAQUE_LSA (lsah->type)) { found = lookup_apiserver (lsah->type, GET_OPAQUE_TYPE (ntohl (lsah->id.s_addr))); } return found; } /* ----------------------------------------------------------- * Followings are functions to manage client connections. * ----------------------------------------------------------- */ static int ospf_apiserver_new_lsa_hook (struct ospf_lsa *lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Put LSA(%p)[%s] into reserve, total=%ld", (void *)lsa, dump_lsa_key (lsa), lsa->lsdb->total); return 0; } static int ospf_apiserver_del_lsa_hook (struct ospf_lsa *lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Get LSA(%p)[%s] from reserve, total=%ld", (void *)lsa, dump_lsa_key (lsa), lsa->lsdb->total); return 0; } /* Allocate new connection structure. */ struct ospf_apiserver * ospf_apiserver_new (int fd_sync, int fd_async) { struct ospf_apiserver *new = XMALLOC (MTYPE_OSPF_APISERVER, sizeof (struct ospf_apiserver)); new->filter = XMALLOC (MTYPE_OSPF_APISERVER_MSGFILTER, sizeof (struct lsa_filter_type)); new->fd_sync = fd_sync; new->fd_async = fd_async; /* list of registered opaque types that application uses */ new->opaque_types = list_new (); /* Initialize temporary strage for LSA instances to be refreshed. */ memset (&new->reserve, 0, sizeof (struct ospf_lsdb)); ospf_lsdb_init (&new->reserve); new->reserve.new_lsa_hook = ospf_apiserver_new_lsa_hook; /* debug */ new->reserve.del_lsa_hook = ospf_apiserver_del_lsa_hook; /* debug */ new->out_sync_fifo = msg_fifo_new (); new->out_async_fifo = msg_fifo_new (); new->t_sync_read = NULL; #ifdef USE_ASYNC_READ new->t_async_read = NULL; #endif /* USE_ASYNC_READ */ new->t_sync_write = NULL; new->t_async_write = NULL; new->filter->typemask = 0; /* filter all LSAs */ new->filter->origin = ANY_ORIGIN; new->filter->num_areas = 0; return new; } void ospf_apiserver_event (enum event event, int fd, struct ospf_apiserver *apiserv) { switch (event) { case OSPF_APISERVER_ACCEPT: (void)thread_add_read (master, ospf_apiserver_accept, apiserv, fd); break; case OSPF_APISERVER_SYNC_READ: apiserv->t_sync_read = thread_add_read (master, ospf_apiserver_read, apiserv, fd); break; #ifdef USE_ASYNC_READ case OSPF_APISERVER_ASYNC_READ: apiserv->t_async_read = thread_add_read (master, ospf_apiserver_read, apiserv, fd); break; #endif /* USE_ASYNC_READ */ case OSPF_APISERVER_SYNC_WRITE: if (!apiserv->t_sync_write) { apiserv->t_sync_write = thread_add_write (master, ospf_apiserver_sync_write, apiserv, fd); } break; case OSPF_APISERVER_ASYNC_WRITE: if (!apiserv->t_async_write) { apiserv->t_async_write = thread_add_write (master, ospf_apiserver_async_write, apiserv, fd); } break; } } /* Free instance. First unregister all opaque types used by application, flush opaque LSAs injected by application from network and close connection. */ void ospf_apiserver_free (struct ospf_apiserver *apiserv) { struct listnode *node; /* Cancel read and write threads. */ if (apiserv->t_sync_read) { thread_cancel (apiserv->t_sync_read); } #ifdef USE_ASYNC_READ if (apiserv->t_async_read) { thread_cancel (apiserv->t_async_read); } #endif /* USE_ASYNC_READ */ if (apiserv->t_sync_write) { thread_cancel (apiserv->t_sync_write); } if (apiserv->t_async_write) { thread_cancel (apiserv->t_async_write); } /* Unregister all opaque types that application registered and flush opaque LSAs if still in LSDB. */ while ((node = listhead (apiserv->opaque_types)) != NULL) { struct registered_opaque_type *regtype = listgetdata(node); ospf_apiserver_unregister_opaque_type (apiserv, regtype->lsa_type, regtype->opaque_type); } /* Close connections to OSPFd. */ if (apiserv->fd_sync > 0) { close (apiserv->fd_sync); } if (apiserv->fd_async > 0) { close (apiserv->fd_async); } /* Free fifos */ msg_fifo_free (apiserv->out_sync_fifo); msg_fifo_free (apiserv->out_async_fifo); /* Clear temporary strage for LSA instances to be refreshed. */ ospf_lsdb_delete_all (&apiserv->reserve); ospf_lsdb_cleanup (&apiserv->reserve); /* Remove from the list of active clients. */ listnode_delete (apiserver_list, apiserv); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Delete apiserv(%p), total#(%d)", (void *)apiserv, apiserver_list->count); /* And free instance. */ XFREE (MTYPE_OSPF_APISERVER, apiserv); } int ospf_apiserver_read (struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; int fd; int rc = -1; enum event event; apiserv = THREAD_ARG (thread); fd = THREAD_FD (thread); if (fd == apiserv->fd_sync) { event = OSPF_APISERVER_SYNC_READ; apiserv->t_sync_read = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_read: Peer: %s/%u", inet_ntoa (apiserv->peer_sync.sin_addr), ntohs (apiserv->peer_sync.sin_port)); } #ifdef USE_ASYNC_READ else if (fd == apiserv->fd_async) { event = OSPF_APISERVER_ASYNC_READ; apiserv->t_async_read = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_read: Peer: %s/%u", inet_ntoa (apiserv->peer_async.sin_addr), ntohs (apiserv->peer_async.sin_port)); } #endif /* USE_ASYNC_READ */ else { zlog_warn ("ospf_apiserver_read: Unknown fd(%d)", fd); ospf_apiserver_free (apiserv); goto out; } /* Read message from fd. */ msg = msg_read (fd); if (msg == NULL) { zlog_warn ("ospf_apiserver_read: read failed on fd=%d, closing connection", fd); /* Perform cleanup. */ ospf_apiserver_free (apiserv); goto out; } if (IS_DEBUG_OSPF_EVENT) msg_print (msg); /* Dispatch to corresponding message handler. */ rc = ospf_apiserver_handle_msg (apiserv, msg); /* Prepare for next message, add read thread. */ ospf_apiserver_event (event, fd, apiserv); msg_free (msg); out: return rc; } int ospf_apiserver_sync_write (struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; int fd; int rc = -1; apiserv = THREAD_ARG (thread); assert (apiserv); fd = THREAD_FD (thread); apiserv->t_sync_write = NULL; /* Sanity check */ if (fd != apiserv->fd_sync) { zlog_warn ("ospf_apiserver_sync_write: Unknown fd=%d", fd); goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_sync_write: Peer: %s/%u", inet_ntoa (apiserv->peer_sync.sin_addr), ntohs (apiserv->peer_sync.sin_port)); /* Check whether there is really a message in the fifo. */ msg = msg_fifo_pop (apiserv->out_sync_fifo); if (!msg) { zlog_warn ("API: ospf_apiserver_sync_write: No message in Sync-FIFO?"); return 0; } if (IS_DEBUG_OSPF_EVENT) msg_print (msg); rc = msg_write (fd, msg); /* Once a message is dequeued, it should be freed anyway. */ msg_free (msg); if (rc < 0) { zlog_warn ("ospf_apiserver_sync_write: write failed on fd=%d", fd); goto out; } /* If more messages are in sync message fifo, schedule write thread. */ if (msg_fifo_head (apiserv->out_sync_fifo)) { ospf_apiserver_event (OSPF_APISERVER_SYNC_WRITE, apiserv->fd_sync, apiserv); } out: if (rc < 0) { /* Perform cleanup and disconnect with peer */ ospf_apiserver_free (apiserv); } return rc; } int ospf_apiserver_async_write (struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; int fd; int rc = -1; apiserv = THREAD_ARG (thread); assert (apiserv); fd = THREAD_FD (thread); apiserv->t_async_write = NULL; /* Sanity check */ if (fd != apiserv->fd_async) { zlog_warn ("ospf_apiserver_async_write: Unknown fd=%d", fd); goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_async_write: Peer: %s/%u", inet_ntoa (apiserv->peer_async.sin_addr), ntohs (apiserv->peer_async.sin_port)); /* Check whether there is really a message in the fifo. */ msg = msg_fifo_pop (apiserv->out_async_fifo); if (!msg) { zlog_warn ("API: ospf_apiserver_async_write: No message in Async-FIFO?"); return 0; } if (IS_DEBUG_OSPF_EVENT) msg_print (msg); rc = msg_write (fd, msg); /* Once a message is dequeued, it should be freed anyway. */ msg_free (msg); if (rc < 0) { zlog_warn ("ospf_apiserver_async_write: write failed on fd=%d", fd); goto out; } /* If more messages are in async message fifo, schedule write thread. */ if (msg_fifo_head (apiserv->out_async_fifo)) { ospf_apiserver_event (OSPF_APISERVER_ASYNC_WRITE, apiserv->fd_async, apiserv); } out: if (rc < 0) { /* Perform cleanup and disconnect with peer */ ospf_apiserver_free (apiserv); } return rc; } int ospf_apiserver_serv_sock_family (unsigned short port, int family) { union sockunion su; int accept_sock; int rc; 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 accept_sock; /* This is a server, so reuse address and port */ sockopt_reuseaddr (accept_sock); sockopt_reuseport (accept_sock); /* Bind socket to address and given port. */ rc = sockunion_bind (accept_sock, &su, port, NULL); if (rc < 0) { close (accept_sock); /* Close socket */ return rc; } /* Listen socket under queue length 3. */ rc = listen (accept_sock, 3); if (rc < 0) { zlog_warn ("ospf_apiserver_serv_sock_family: listen: %s", safe_strerror (errno)); close (accept_sock); /* Close socket */ return rc; } return accept_sock; } /* Accept connection request from external applications. For each accepted connection allocate own connection instance. */ int ospf_apiserver_accept (struct thread *thread) { int accept_sock; int new_sync_sock; int new_async_sock; union sockunion su; struct ospf_apiserver *apiserv; struct sockaddr_in peer_async; struct sockaddr_in peer_sync; unsigned int peerlen; int ret; /* THREAD_ARG (thread) is NULL */ accept_sock = THREAD_FD (thread); /* Keep hearing on socket for further connections. */ ospf_apiserver_event (OSPF_APISERVER_ACCEPT, accept_sock, NULL); memset (&su, 0, sizeof (union sockunion)); /* Accept connection for synchronous messages */ new_sync_sock = sockunion_accept (accept_sock, &su); if (new_sync_sock < 0) { zlog_warn ("ospf_apiserver_accept: accept: %s", safe_strerror (errno)); return -1; } /* Get port address and port number of peer to make reverse connection. The reverse channel uses the port number of the peer port+1. */ memset(&peer_sync, 0, sizeof(struct sockaddr_in)); peerlen = sizeof (struct sockaddr_in); ret = getpeername (new_sync_sock, (struct sockaddr *)&peer_sync, &peerlen); if (ret < 0) { zlog_warn ("ospf_apiserver_accept: getpeername: %s", safe_strerror (errno)); close (new_sync_sock); return -1; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_accept: New peer: %s/%u", inet_ntoa (peer_sync.sin_addr), ntohs (peer_sync.sin_port)); /* Create new socket for asynchronous messages. */ peer_async = peer_sync; peer_async.sin_port = htons(ntohs(peer_sync.sin_port) + 1); /* Check if remote port number to make reverse connection is valid one. */ if (ntohs (peer_async.sin_port) == ospf_apiserver_getport ()) { zlog_warn ("API: ospf_apiserver_accept: Peer(%s/%u): Invalid async port number?", inet_ntoa (peer_async.sin_addr), ntohs (peer_async.sin_port)); close (new_sync_sock); return -1; } new_async_sock = socket (AF_INET, SOCK_STREAM, 0); if (new_async_sock < 0) { zlog_warn ("ospf_apiserver_accept: socket: %s", safe_strerror (errno)); close (new_sync_sock); return -1; } ret = connect (new_async_sock, (struct sockaddr *) &peer_async, sizeof (struct sockaddr_in)); if (ret < 0) { zlog_warn ("ospf_apiserver_accept: connect: %s", safe_strerror (errno)); close (new_sync_sock); close (new_async_sock); return -1; } #ifdef USE_ASYNC_READ #else /* USE_ASYNC_READ */ /* Make the asynchronous channel write-only. */ ret = shutdown (new_async_sock, SHUT_RD); if (ret < 0) { zlog_warn ("ospf_apiserver_accept: shutdown: %s", safe_strerror (errno)); close (new_sync_sock); close (new_async_sock); return -1; } #endif /* USE_ASYNC_READ */ /* Allocate new server-side connection structure */ apiserv = ospf_apiserver_new (new_sync_sock, new_async_sock); /* Add to active connection list */ listnode_add (apiserver_list, apiserv); apiserv->peer_sync = peer_sync; apiserv->peer_async = peer_async; /* And add read threads for new connection */ ospf_apiserver_event (OSPF_APISERVER_SYNC_READ, new_sync_sock, apiserv); #ifdef USE_ASYNC_READ ospf_apiserver_event (OSPF_APISERVER_ASYNC_READ, new_async_sock, apiserv); #endif /* USE_ASYNC_READ */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: New apiserv(%p), total#(%d)", (void *)apiserv, apiserver_list->count); return 0; } /* ----------------------------------------------------------- * Send reply with return code to client application * ----------------------------------------------------------- */ static int ospf_apiserver_send_msg (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_fifo *fifo; struct msg *msg2; enum event event; int fd; switch (msg->hdr.msgtype) { case MSG_REPLY: fifo = apiserv->out_sync_fifo; fd = apiserv->fd_sync; event = OSPF_APISERVER_SYNC_WRITE; break; case MSG_READY_NOTIFY: case MSG_LSA_UPDATE_NOTIFY: case MSG_LSA_DELETE_NOTIFY: case MSG_NEW_IF: case MSG_DEL_IF: case MSG_ISM_CHANGE: case MSG_NSM_CHANGE: fifo = apiserv->out_async_fifo; fd = apiserv->fd_async; event = OSPF_APISERVER_ASYNC_WRITE; break; default: zlog_warn ("ospf_apiserver_send_msg: Unknown message type %d", msg->hdr.msgtype); return -1; } /* Make a copy of the message and put in the fifo. Once the fifo gets drained by the write thread, the message will be freed. */ /* NB: Given "msg" is untouched in this function. */ msg2 = msg_dup (msg); /* Enqueue message into corresponding fifo queue */ msg_fifo_push (fifo, msg2); /* Schedule write thread */ ospf_apiserver_event (event, fd, apiserv); return 0; } int ospf_apiserver_send_reply (struct ospf_apiserver *apiserv, u_int32_t seqnr, u_char rc) { struct msg *msg = new_msg_reply (seqnr, rc); int ret; if (!msg) { zlog_warn ("ospf_apiserver_send_reply: msg_new failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif return -1; } ret = ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); return ret; } /* ----------------------------------------------------------- * Generic message dispatching handler function * ----------------------------------------------------------- */ int ospf_apiserver_handle_msg (struct ospf_apiserver *apiserv, struct msg *msg) { int rc; /* Call corresponding message handler function. */ switch (msg->hdr.msgtype) { case MSG_REGISTER_OPAQUETYPE: rc = ospf_apiserver_handle_register_opaque_type (apiserv, msg); break; case MSG_UNREGISTER_OPAQUETYPE: rc = ospf_apiserver_handle_unregister_opaque_type (apiserv, msg); break; case MSG_REGISTER_EVENT: rc = ospf_apiserver_handle_register_event (apiserv, msg); break; case MSG_SYNC_LSDB: rc = ospf_apiserver_handle_sync_lsdb (apiserv, msg); break; case MSG_ORIGINATE_REQUEST: rc = ospf_apiserver_handle_originate_request (apiserv, msg); break; case MSG_DELETE_REQUEST: rc = ospf_apiserver_handle_delete_request (apiserv, msg); break; default: zlog_warn ("ospf_apiserver_handle_msg: Unknown message type: %d", msg->hdr.msgtype); rc = -1; } return rc; } /* ----------------------------------------------------------- * Following are functions for opaque type registration * ----------------------------------------------------------- */ int ospf_apiserver_register_opaque_type (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type) { struct registered_opaque_type *regtype; int (*originator_func) (void *arg); int rc; switch (lsa_type) { case OSPF_OPAQUE_LINK_LSA: originator_func = ospf_apiserver_lsa9_originator; break; case OSPF_OPAQUE_AREA_LSA: originator_func = ospf_apiserver_lsa10_originator; break; case OSPF_OPAQUE_AS_LSA: originator_func = ospf_apiserver_lsa11_originator; break; default: zlog_warn ("ospf_apiserver_register_opaque_type: lsa_type(%d)", lsa_type); return OSPF_API_ILLEGALLSATYPE; } /* Register opaque function table */ /* NB: Duplicated registration will be detected inside the function. */ rc = ospf_register_opaque_functab (lsa_type, opaque_type, NULL, /* ospf_apiserver_new_if */ NULL, /* ospf_apiserver_del_if */ NULL, /* ospf_apiserver_ism_change */ NULL, /* ospf_apiserver_nsm_change */ NULL, NULL, NULL, ospf_apiserver_show_info, originator_func, ospf_apiserver_lsa_refresher, NULL, /* ospf_apiserver_lsa_update */ NULL /* ospf_apiserver_lsa_delete */); if (rc != 0) { zlog_warn ("Failed to register opaque type [%d/%d]", lsa_type, opaque_type); return OSPF_API_OPAQUETYPEINUSE; } /* Remember the opaque type that application registers so when connection shuts down, we can flush all LSAs of this opaque type. */ regtype = XCALLOC (MTYPE_OSPF_APISERVER, sizeof (struct registered_opaque_type)); regtype->lsa_type = lsa_type; regtype->opaque_type = opaque_type; /* Add to list of registered opaque types */ listnode_add (apiserv->opaque_types, regtype); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Add LSA-type(%d)/Opaque-type(%d) into" " apiserv(%p), total#(%d)", lsa_type, opaque_type, (void *)apiserv, listcount (apiserv->opaque_types)); return 0; } int ospf_apiserver_unregister_opaque_type (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type) { struct listnode *node, *nnode; struct registered_opaque_type *regtype; for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, regtype)) { /* Check if we really registered this opaque type */ if (regtype->lsa_type == lsa_type && regtype->opaque_type == opaque_type) { /* Yes, we registered this opaque type. Flush all existing opaque LSAs of this type */ ospf_apiserver_flush_opaque_lsa (apiserv, lsa_type, opaque_type); ospf_delete_opaque_functab (lsa_type, opaque_type); /* Remove from list of registered opaque types */ listnode_delete (apiserv->opaque_types, regtype); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Del LSA-type(%d)/Opaque-type(%d)" " from apiserv(%p), total#(%d)", lsa_type, opaque_type, (void *)apiserv, listcount (apiserv->opaque_types)); return 0; } } /* Opaque type is not registered */ zlog_warn ("Failed to unregister opaque type [%d/%d]", lsa_type, opaque_type); return OSPF_API_OPAQUETYPENOTREGISTERED; } static int apiserver_is_opaque_type_registered (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type) { struct listnode *node, *nnode; struct registered_opaque_type *regtype; /* XXX: how many types are there? if few, why not just a bitmap? */ for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, regtype)) { /* Check if we really registered this opaque type */ if (regtype->lsa_type == lsa_type && regtype->opaque_type == opaque_type) { /* Yes registered */ return 1; } } /* Not registered */ return 0; } int ospf_apiserver_handle_register_opaque_type (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_register_opaque_type *rmsg; u_char lsa_type; u_char opaque_type; int rc = 0; /* Extract parameters from register opaque type message */ rmsg = (struct msg_register_opaque_type *) STREAM_DATA (msg->s); lsa_type = rmsg->lsatype; opaque_type = rmsg->opaquetype; rc = ospf_apiserver_register_opaque_type (apiserv, lsa_type, opaque_type); /* Send a reply back to client including return code */ rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc); if (rc < 0) goto out; /* Now inform application about opaque types that are ready */ switch (lsa_type) { case OSPF_OPAQUE_LINK_LSA: ospf_apiserver_notify_ready_type9 (apiserv); break; case OSPF_OPAQUE_AREA_LSA: ospf_apiserver_notify_ready_type10 (apiserv); break; case OSPF_OPAQUE_AS_LSA: ospf_apiserver_notify_ready_type11 (apiserv); break; } out: return rc; } /* Notify specific client about all opaque types 9 that are ready. */ void ospf_apiserver_notify_ready_type9 (struct ospf_apiserver *apiserv) { struct listnode *node, *nnode; struct listnode *node2, *nnode2; struct ospf *ospf; struct ospf_interface *oi; struct registered_opaque_type *r; ospf = ospf_lookup (); for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { /* Check if this interface is indeed ready for type 9 */ if (!ospf_apiserver_is_ready_type9 (oi)) continue; /* Check for registered opaque type 9 types */ /* XXX: loop-de-loop - optimise me */ for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { struct msg *msg; if (r->lsa_type == OSPF_OPAQUE_LINK_LSA) { /* Yes, this opaque type is ready */ msg = new_msg_ready_notify (0, OSPF_OPAQUE_LINK_LSA, r->opaque_type, oi->address->u.prefix4); if (!msg) { zlog_warn ("apiserver_notify_ready_type9: msg_new failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } /* Notify specific client about all opaque types 10 that are ready. */ void ospf_apiserver_notify_ready_type10 (struct ospf_apiserver *apiserv) { struct listnode *node, *nnode; struct listnode *node2, *nnode2; struct ospf *ospf; struct ospf_area *area; ospf = ospf_lookup (); for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { struct registered_opaque_type *r; if (!ospf_apiserver_is_ready_type10 (area)) { continue; } /* Check for registered opaque type 10 types */ /* XXX: loop in loop - optimise me */ for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { struct msg *msg; if (r->lsa_type == OSPF_OPAQUE_AREA_LSA) { /* Yes, this opaque type is ready */ msg = new_msg_ready_notify (0, OSPF_OPAQUE_AREA_LSA, r->opaque_type, area->area_id); if (!msg) { zlog_warn ("apiserver_notify_ready_type10: msg_new failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } /* Notify specific client about all opaque types 11 that are ready */ void ospf_apiserver_notify_ready_type11 (struct ospf_apiserver *apiserv) { struct listnode *node, *nnode; struct ospf *ospf; struct registered_opaque_type *r; ospf = ospf_lookup (); /* Can type 11 be originated? */ if (!ospf_apiserver_is_ready_type11 (ospf)) goto out; /* Check for registered opaque type 11 types */ for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, r)) { struct msg *msg; struct in_addr noarea_id = { .s_addr = 0L }; if (r->lsa_type == OSPF_OPAQUE_AS_LSA) { /* Yes, this opaque type is ready */ msg = new_msg_ready_notify (0, OSPF_OPAQUE_AS_LSA, r->opaque_type, noarea_id); if (!msg) { zlog_warn ("apiserver_notify_ready_type11: msg_new failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } out: return; } int ospf_apiserver_handle_unregister_opaque_type (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_unregister_opaque_type *umsg; u_char ltype; u_char otype; int rc = 0; /* Extract parameters from unregister opaque type message */ umsg = (struct msg_unregister_opaque_type *) STREAM_DATA (msg->s); ltype = umsg->lsatype; otype = umsg->opaquetype; rc = ospf_apiserver_unregister_opaque_type (apiserv, ltype, otype); /* Send a reply back to client including return code */ rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc); return rc; } /* ----------------------------------------------------------- * Following are functions for event (filter) registration. * ----------------------------------------------------------- */ int ospf_apiserver_handle_register_event (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_register_event *rmsg; int rc; u_int32_t seqnum; rmsg = (struct msg_register_event *) STREAM_DATA (msg->s); /* Get request sequence number */ seqnum = msg_get_seq (msg); /* Free existing filter in apiserv. */ XFREE (MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter); /* Alloc new space for filter. */ apiserv->filter = XMALLOC (MTYPE_OSPF_APISERVER_MSGFILTER, ntohs (msg->hdr.msglen)); if (apiserv->filter) { /* copy it over. */ memcpy (apiserv->filter, &rmsg->filter, ntohs (msg->hdr.msglen)); rc = OSPF_API_OK; } else { rc = OSPF_API_NOMEMORY; } /* Send a reply back to client with return code */ rc = ospf_apiserver_send_reply (apiserv, seqnum, rc); return rc; } /* ----------------------------------------------------------- * Followings are functions for LSDB synchronization. * ----------------------------------------------------------- */ static int apiserver_sync_callback (struct ospf_lsa *lsa, void *p_arg, int int_arg) { struct ospf_apiserver *apiserv; int seqnum; struct msg *msg; struct param_t { struct ospf_apiserver *apiserv; struct lsa_filter_type *filter; } *param; int rc = -1; /* Sanity check */ assert (lsa->data); assert (p_arg); param = (struct param_t *) p_arg; apiserv = param->apiserv; seqnum = (u_int32_t) int_arg; /* Check origin in filter. */ if ((param->filter->origin == ANY_ORIGIN) || (param->filter->origin == (lsa->flags & OSPF_LSA_SELF))) { /* Default area for AS-External and Opaque11 LSAs */ struct in_addr area_id = { .s_addr = 0L }; /* Default interface for non Opaque9 LSAs */ struct in_addr ifaddr = { .s_addr = 0L }; if (lsa->area) { area_id = lsa->area->area_id; } if (lsa->data->type == OSPF_OPAQUE_LINK_LSA) { ifaddr = lsa->oi->address->u.prefix4; } msg = new_msg_lsa_change_notify (MSG_LSA_UPDATE_NOTIFY, seqnum, ifaddr, area_id, lsa->flags & OSPF_LSA_SELF, lsa->data); if (!msg) { zlog_warn ("apiserver_sync_callback: new_msg_update failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ /* ospf_apiserver_free (apiserv);*//* Do nothing here XXX */ #endif goto out; } /* Send LSA */ ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } rc = 0; out: return rc; } int ospf_apiserver_handle_sync_lsdb (struct ospf_apiserver *apiserv, struct msg *msg) { struct listnode *node, *nnode; u_int32_t seqnum; int rc = 0; struct msg_sync_lsdb *smsg; struct ospf_apiserver_param_t { struct ospf_apiserver *apiserv; struct lsa_filter_type *filter; } param; u_int16_t mask; struct route_node *rn; struct ospf_lsa *lsa; struct ospf *ospf; struct ospf_area *area; ospf = ospf_lookup (); /* Get request sequence number */ seqnum = msg_get_seq (msg); /* Set sync msg. */ smsg = (struct msg_sync_lsdb *) STREAM_DATA (msg->s); /* Set parameter struct. */ param.apiserv = apiserv; param.filter = &smsg->filter; /* Remember mask. */ mask = ntohs (smsg->filter.typemask); /* Iterate over all areas. */ for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { int i; u_int32_t *area_id = NULL; /* Compare area_id with area_ids in sync request. */ if ((i = smsg->filter.num_areas) > 0) { /* Let area_id point to the list of area IDs, * which is at the end of smsg->filter. */ area_id = (u_int32_t *) (&smsg->filter + 1); while (i) { if (*area_id == area->area_id.s_addr) { break; } i--; area_id++; } } else { i = 1; } /* If area was found, then i>0 here. */ if (i) { /* Check msg type. */ if (mask & Power2[OSPF_ROUTER_LSA]) LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_NETWORK_LSA]) LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_SUMMARY_LSA]) LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_ASBR_SUMMARY_LSA]) LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_OPAQUE_LINK_LSA]) LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_OPAQUE_AREA_LSA]) LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); } } /* For AS-external LSAs */ if (ospf->lsdb) { if (mask & Power2[OSPF_AS_EXTERNAL_LSA]) LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); } /* For AS-external opaque LSAs */ if (ospf->lsdb) { if (mask & Power2[OSPF_OPAQUE_AS_LSA]) LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); } /* Send a reply back to client with return code */ rc = ospf_apiserver_send_reply (apiserv, seqnum, rc); return rc; } /* ----------------------------------------------------------- * Followings are functions to originate or update LSA * from an application. * ----------------------------------------------------------- */ /* Create a new internal opaque LSA by taking prototype and filling in missing fields such as age, sequence number, advertising router, checksum and so on. The interface parameter is used for type 9 LSAs, area parameter for type 10. Type 11 LSAs do neither need area nor interface. */ struct ospf_lsa * ospf_apiserver_opaque_lsa_new (struct ospf_area *area, struct ospf_interface *oi, struct lsa_header *protolsa) { struct stream *s; struct lsa_header *newlsa; struct ospf_lsa *new = NULL; u_char options = 0x0; u_int16_t length; struct ospf *ospf; ospf = ospf_lookup(); assert(ospf); /* Create a stream for internal opaque LSA */ if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) { zlog_warn ("ospf_apiserver_opaque_lsa_new: stream_new failed"); return NULL; } newlsa = (struct lsa_header *) STREAM_DATA (s); /* XXX If this is a link-local LSA or an AS-external LSA, how do we have to set options? */ if (area) { options = LSA_OPTIONS_GET (area); options |= LSA_OPTIONS_NSSA_GET (area); } options |= OSPF_OPTION_O; /* Don't forget to set option bit */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Creating an Opaque-LSA instance", protolsa->type, inet_ntoa (protolsa->id)); } /* Set opaque-LSA header fields. */ lsa_header_set (s, options, protolsa->type, protolsa->id, ospf->router_id); /* Set opaque-LSA body fields. */ stream_put (s, ((u_char *) protolsa) + sizeof (struct lsa_header), ntohs (protolsa->length) - sizeof (struct lsa_header)); /* Determine length of LSA. */ length = stream_get_endp (s); newlsa->length = htons (length); /* Create OSPF LSA. */ if ((new = ospf_lsa_new ()) == NULL) { zlog_warn ("ospf_apiserver_opaque_lsa_new: ospf_lsa_new() ?"); stream_free (s); return NULL; } if ((new->data = ospf_lsa_data_new (length)) == NULL) { zlog_warn ("ospf_apiserver_opaque_lsa_new: ospf_lsa_data_new() ?"); ospf_lsa_unlock (&new); stream_free (s); return NULL; } new->area = area; new->oi = oi; SET_FLAG (new->flags, OSPF_LSA_SELF); memcpy (new->data, newlsa, length); stream_free (s); return new; } int ospf_apiserver_is_ready_type9 (struct ospf_interface *oi) { /* Type 9 opaque LSA can be originated if there is at least one active opaque-capable neighbor attached to the outgoing interface. */ return (ospf_nbr_count_opaque_capable (oi) > 0); } int ospf_apiserver_is_ready_type10 (struct ospf_area *area) { /* Type 10 opaque LSA can be originated if there is at least one interface belonging to the area that has an active opaque-capable neighbor. */ struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) /* Is there an active neighbor attached to this interface? */ if (ospf_apiserver_is_ready_type9 (oi)) return 1; /* No active neighbor in area */ return 0; } int ospf_apiserver_is_ready_type11 (struct ospf *ospf) { /* Type 11 opaque LSA can be originated if there is at least one interface that has an active opaque-capable neighbor. */ struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) /* Is there an active neighbor attached to this interface? */ if (ospf_apiserver_is_ready_type9 (oi)) return 1; /* No active neighbor at all */ return 0; } int ospf_apiserver_handle_originate_request (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_originate_request *omsg; struct lsa_header *data; struct ospf_lsa *new; struct ospf_lsa *old; struct ospf_area *area = NULL; struct ospf_interface *oi = NULL; struct ospf_lsdb *lsdb = NULL; struct ospf *ospf; int lsa_type, opaque_type; int ready = 0; int rc = 0; ospf = ospf_lookup(); /* Extract opaque LSA data from message */ omsg = (struct msg_originate_request *) STREAM_DATA (msg->s); data = &omsg->data; /* Determine interface for type9 or area for type10 LSAs. */ switch (data->type) { case OSPF_OPAQUE_LINK_LSA: oi = ospf_apiserver_if_lookup_by_addr (omsg->ifaddr); if (!oi) { zlog_warn ("apiserver_originate: unknown interface %s", inet_ntoa (omsg->ifaddr)); rc = OSPF_API_NOSUCHINTERFACE; goto out; } area = oi->area; lsdb = area->lsdb; break; case OSPF_OPAQUE_AREA_LSA: area = ospf_area_lookup_by_area_id (ospf, omsg->area_id); if (!area) { zlog_warn ("apiserver_originate: unknown area %s", inet_ntoa (omsg->area_id)); rc = OSPF_API_NOSUCHAREA; goto out; } lsdb = area->lsdb; break; case OSPF_OPAQUE_AS_LSA: lsdb = ospf->lsdb; break; default: /* We can only handle opaque types here */ zlog_warn ("apiserver_originate: Cannot originate non-opaque LSA type %d", data->type); rc = OSPF_API_ILLEGALLSATYPE; goto out; } /* Check if we registered this opaque type */ lsa_type = data->type; opaque_type = GET_OPAQUE_TYPE (ntohl (data->id.s_addr)); if (!apiserver_is_opaque_type_registered (apiserv, lsa_type, opaque_type)) { zlog_warn ("apiserver_originate: LSA-type(%d)/Opaque-type(%d): Not registered", lsa_type, opaque_type); rc = OSPF_API_OPAQUETYPENOTREGISTERED; goto out; } /* Make sure that the neighbors are ready before we can originate */ switch (data->type) { case OSPF_OPAQUE_LINK_LSA: ready = ospf_apiserver_is_ready_type9 (oi); break; case OSPF_OPAQUE_AREA_LSA: ready = ospf_apiserver_is_ready_type10 (area); break; case OSPF_OPAQUE_AS_LSA: ready = ospf_apiserver_is_ready_type11 (ospf); break; default: break; } if (!ready) { zlog_warn ("Neighbors not ready to originate type %d", data->type); rc = OSPF_API_NOTREADY; goto out; } /* Create OSPF's internal opaque LSA representation */ new = ospf_apiserver_opaque_lsa_new (area, oi, data); if (!new) { rc = OSPF_API_NOMEMORY; /* XXX */ goto out; } /* Determine if LSA is new or an update for an existing one. */ old = ospf_lsdb_lookup (lsdb, new); if (!old) { /* New LSA install in LSDB. */ rc = ospf_apiserver_originate1 (new); } else { /* * Keep the new LSA instance in the "waiting place" until the next * refresh timing. If several LSA update requests for the same LSID * have issued by peer, the last one takes effect. */ new->lsdb = &apiserv->reserve; ospf_lsdb_add (&apiserv->reserve, new); /* Kick the scheduler function. */ ospf_opaque_lsa_refresh_schedule (old); } out: /* Send a reply back to client with return code */ rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc); return rc; } /* ----------------------------------------------------------- * Flood an LSA within its flooding scope. * ----------------------------------------------------------- */ /* XXX We can probably use ospf_flood_through instead of this function but then we need the neighbor parameter. If we set nbr to NULL then ospf_flood_through crashes due to dereferencing NULL. */ void ospf_apiserver_flood_opaque_lsa (struct ospf_lsa *lsa) { assert (lsa); switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: /* Increment counters? XXX */ /* Flood LSA through local network. */ ospf_flood_through_area (lsa->area, NULL /*nbr */ , lsa); break; case OSPF_OPAQUE_AREA_LSA: /* Update LSA origination count. */ assert (lsa->area); lsa->area->ospf->lsa_originate_count++; /* Flood LSA through area. */ ospf_flood_through_area (lsa->area, NULL /*nbr */ , lsa); break; case OSPF_OPAQUE_AS_LSA: { struct ospf *ospf; ospf = ospf_lookup(); assert(ospf); /* Increment counters? XXX */ /* Flood LSA through AS. */ ospf_flood_through_as (ospf, NULL /*nbr */ , lsa); break; } } } int ospf_apiserver_originate1 (struct ospf_lsa *lsa) { struct ospf *ospf; ospf = ospf_lookup(); assert(ospf); /* Install this LSA into LSDB. */ if (ospf_lsa_install (ospf, lsa->oi, lsa) == NULL) { zlog_warn ("ospf_apiserver_originate1: ospf_lsa_install failed"); return -1; } /* Flood LSA within scope */ #ifdef NOTYET /* * NB: Modified version of "ospf_flood_though ()" accepts NULL "inbr" * parameter, and thus it does not cause SIGSEGV error. */ ospf_flood_through (NULL /*nbr */ , lsa); #else /* NOTYET */ ospf_apiserver_flood_opaque_lsa (lsa); #endif /* NOTYET */ return 0; } /* Opaque LSAs of type 9 on a specific interface can now be originated. Tell clients that registered type 9. */ int ospf_apiserver_lsa9_originator (void *arg) { struct ospf_interface *oi; oi = (struct ospf_interface *) arg; if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_ready_type9 (oi); } return 0; } int ospf_apiserver_lsa10_originator (void *arg) { struct ospf_area *area; area = (struct ospf_area *) arg; if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_ready_type10 (area); } return 0; } int ospf_apiserver_lsa11_originator (void *arg) { struct ospf *ospf; ospf = (struct ospf *) arg; if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_ready_type11 (ospf); } return 0; } /* Periodically refresh opaque LSAs so that they do not expire in other routers. */ struct ospf_lsa * ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa) { struct ospf_apiserver *apiserv; struct ospf_lsa *new = NULL; struct ospf * ospf; ospf = ospf_lookup(); assert(ospf); apiserv = lookup_apiserver_by_lsa (lsa); if (!apiserv) { zlog_warn ("ospf_apiserver_lsa_refresher: LSA[%s]: No apiserver?", dump_lsa_key (lsa)); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } if (IS_LSA_MAXAGE (lsa)) { ospf_opaque_lsa_flush_schedule (lsa); goto out; } /* Check if updated version of LSA instance has already prepared. */ new = ospf_lsdb_lookup (&apiserv->reserve, lsa); if (!new) { /* This is a periodic refresh, driven by core OSPF mechanism. */ new = ospf_apiserver_opaque_lsa_new (lsa->area, lsa->oi, lsa->data); if (!new) { zlog_warn ("ospf_apiserver_lsa_refresher: Cannot create a new LSA?"); goto out; } } else { /* This is a forcible refresh, requested by OSPF-API client. */ ospf_lsdb_delete (&apiserv->reserve, new); new->lsdb = NULL; } /* Increment sequence number */ new->data->ls_seqnum = lsa_seqnum_increment (lsa); /* New LSA is in same area. */ new->area = lsa->area; SET_FLAG (new->flags, OSPF_LSA_SELF); /* Install LSA into LSDB. */ if (ospf_lsa_install (ospf, new->oi, new) == NULL) { zlog_warn ("ospf_apiserver_lsa_refresher: ospf_lsa_install failed"); ospf_lsa_unlock (&new); goto out; } /* Flood updated LSA through interface, area or AS */ #ifdef NOTYET ospf_flood_through (NULL /*nbr */ , new); #endif /* NOTYET */ ospf_apiserver_flood_opaque_lsa (new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Refresh Opaque LSA", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } out: return new; } /* ----------------------------------------------------------- * Followings are functions to delete LSAs * ----------------------------------------------------------- */ int ospf_apiserver_handle_delete_request (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_delete_request *dmsg; struct ospf_lsa *old; struct ospf_area *area = NULL; struct in_addr id; int lsa_type, opaque_type; int rc = 0; struct ospf * ospf; ospf = ospf_lookup(); assert(ospf); /* Extract opaque LSA from message */ dmsg = (struct msg_delete_request *) STREAM_DATA (msg->s); /* Lookup area for link-local and area-local opaque LSAs */ switch (dmsg->lsa_type) { case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: area = ospf_area_lookup_by_area_id (ospf, dmsg->area_id); if (!area) { zlog_warn ("ospf_apiserver_lsa_delete: unknown area %s", inet_ntoa (dmsg->area_id)); rc = OSPF_API_NOSUCHAREA; goto out; } break; case OSPF_OPAQUE_AS_LSA: /* AS-external opaque LSAs have no designated area */ area = NULL; break; default: zlog_warn ("ospf_apiserver_lsa_delete: Cannot delete non-opaque LSA type %d", dmsg->lsa_type); rc = OSPF_API_ILLEGALLSATYPE; goto out; } /* Check if we registered this opaque type */ lsa_type = dmsg->lsa_type; opaque_type = dmsg->opaque_type; if (!apiserver_is_opaque_type_registered (apiserv, lsa_type, opaque_type)) { zlog_warn ("ospf_apiserver_lsa_delete: LSA-type(%d)/Opaque-type(%d): Not registered", lsa_type, opaque_type); rc = OSPF_API_OPAQUETYPENOTREGISTERED; goto out; } /* opaque_id is in network byte order */ id.s_addr = htonl (SET_OPAQUE_LSID (dmsg->opaque_type, ntohl (dmsg->opaque_id))); /* * Even if the target LSA has once scheduled to flush, it remains in * the LSDB until it is finally handled by the maxage remover thread. * Therefore, the lookup function below may return non-NULL result. */ old = ospf_lsa_lookup (area, dmsg->lsa_type, id, ospf->router_id); if (!old) { zlog_warn ("ospf_apiserver_lsa_delete: LSA[Type%d:%s] not in LSDB", dmsg->lsa_type, inet_ntoa (id)); rc = OSPF_API_NOSUCHLSA; goto out; } /* Schedule flushing of LSA from LSDB */ /* NB: Multiple scheduling will produce a warning message, but harmless. */ ospf_opaque_lsa_flush_schedule (old); out: /* Send reply back to client including return code */ rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc); return rc; } /* Flush self-originated opaque LSA */ static int apiserver_flush_opaque_type_callback (struct ospf_lsa *lsa, void *p_arg, int int_arg) { struct param_t { struct ospf_apiserver *apiserv; u_char lsa_type; u_char opaque_type; } *param; /* Sanity check */ assert (lsa->data); assert (p_arg); param = (struct param_t *) p_arg; /* If LSA matches type and opaque type then delete it */ if (IS_LSA_SELF (lsa) && lsa->data->type == param->lsa_type && GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)) == param->opaque_type) { ospf_opaque_lsa_flush_schedule (lsa); } return 0; } /* Delete self-originated opaque LSAs of a given opaque type. This function is called when an application unregisters a given opaque type or a connection to an application closes and all those opaque LSAs need to be flushed the LSDB. */ void ospf_apiserver_flush_opaque_lsa (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type) { struct param_t { struct ospf_apiserver *apiserv; u_char lsa_type; u_char opaque_type; } param; struct listnode *node, *nnode; struct ospf * ospf; struct ospf_area *area; ospf = ospf_lookup(); assert(ospf); /* Set parameter struct. */ param.apiserv = apiserv; param.lsa_type = lsa_type; param.opaque_type = opaque_type; switch (lsa_type) { struct route_node *rn; struct ospf_lsa *lsa; case OSPF_OPAQUE_LINK_LSA: for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0); break; case OSPF_OPAQUE_AREA_LSA: for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0); break; case OSPF_OPAQUE_AS_LSA: LSDB_LOOP (OPAQUE_LINK_LSDB (ospf), rn, lsa) apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0); break; default: break; } return; } /* ----------------------------------------------------------- * Followings are callback functions to handle opaque types * ----------------------------------------------------------- */ int ospf_apiserver_new_if (struct interface *ifp) { struct ospf_interface *oi; /* For some strange reason it seems possible that we are invoked with an interface that has no name. This seems to happen during initialization. Return if this happens */ if (ifp->name[0] == '\0') { /* interface has empty name */ zlog_warn ("ospf_apiserver_new_if: interface has no name?"); return 0; } /* zlog_warn for debugging */ zlog_warn ("ospf_apiserver_new_if"); zlog_warn ("ifp name=%s status=%d index=%d", ifp->name, ifp->status, ifp->ifindex); if (ifp->name[0] == '\0') { /* interface has empty name */ zlog_warn ("ospf_apiserver_new_if: interface has no name?"); return 0; } oi = ospf_apiserver_if_lookup_by_ifp (ifp); if (!oi) { /* This interface is known to Zebra but not to OSPF daemon yet. */ zlog_warn ("ospf_apiserver_new_if: interface %s not known to OSPFd?", ifp->name); return 0; } assert (oi); /* New interface added to OSPF, tell clients about it */ if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_new_if (oi); } return 0; } int ospf_apiserver_del_if (struct interface *ifp) { struct ospf_interface *oi; /* zlog_warn for debugging */ zlog_warn ("ospf_apiserver_del_if"); zlog_warn ("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status, ifp->ifindex); oi = ospf_apiserver_if_lookup_by_ifp (ifp); if (!oi) { /* This interface is known to Zebra but not to OSPF daemon anymore. No need to tell clients about it */ return 0; } /* Interface deleted, tell clients about it */ if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_del_if (oi); } return 0; } void ospf_apiserver_ism_change (struct ospf_interface *oi, int old_state) { /* Tell clients about interface change */ /* zlog_warn for debugging */ zlog_warn ("ospf_apiserver_ism_change"); if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_ism_change (oi); } zlog_warn ("oi->ifp->name=%s", oi->ifp->name); zlog_warn ("old_state=%d", old_state); zlog_warn ("oi->state=%d", oi->state); } void ospf_apiserver_nsm_change (struct ospf_neighbor *nbr, int old_status) { /* Neighbor status changed, tell clients about it */ zlog_warn ("ospf_apiserver_nsm_change"); if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_nsm_change (nbr); } } void ospf_apiserver_show_info (struct vty *vty, struct ospf_lsa *lsa) { struct opaque_lsa { struct lsa_header header; u_char data[1]; /* opaque data have variable length. This is start address */ }; struct opaque_lsa *olsa; int opaquelen; olsa = (struct opaque_lsa *) lsa->data; if (VALID_OPAQUE_INFO_LEN (lsa->data)) opaquelen = ntohs (lsa->data->length) - OSPF_LSA_HEADER_SIZE; else opaquelen = 0; /* Output information about opaque LSAs */ if (vty != NULL) { int i; vty_out (vty, " Added using OSPF API: %u octets of opaque data %s%s", opaquelen, VALID_OPAQUE_INFO_LEN (lsa->data) ? "" : "(Invalid length?)", VTY_NEWLINE); vty_out (vty, " Opaque data: "); for (i = 0; i < opaquelen; i++) { vty_out (vty, "0x%x ", olsa->data[i]); } vty_out (vty, "%s", VTY_NEWLINE); } else { int i; zlog_debug (" Added using OSPF API: %u octets of opaque data %s", opaquelen, VALID_OPAQUE_INFO_LEN (lsa-> data) ? "" : "(Invalid length?)"); zlog_debug (" Opaque data: "); for (i = 0; i < opaquelen; i++) { zlog_debug ("0x%x ", olsa->data[i]); } zlog_debug ("\n"); } return; } /* ----------------------------------------------------------- * Followings are functions to notify clients about events * ----------------------------------------------------------- */ /* Send a message to all clients. This is useful for messages that need to be notified to all clients (such as interface changes) */ void ospf_apiserver_clients_notify_all (struct msg *msg) { struct listnode *node, *nnode; struct ospf_apiserver *apiserv; /* Send message to all clients */ for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) ospf_apiserver_send_msg (apiserv, msg); } /* An interface is now ready to accept opaque LSAs. Notify all clients that registered to use this opaque type */ void ospf_apiserver_clients_notify_ready_type9 (struct ospf_interface *oi) { struct listnode *node, *nnode; struct msg *msg; struct ospf_apiserver *apiserv; assert (oi); if (!oi->address) { zlog_warn ("Interface has no address?"); return; } if (!ospf_apiserver_is_ready_type9 (oi)) { zlog_warn ("Interface not ready for type 9?"); return; } for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) { struct listnode *node2, *nnode2; struct registered_opaque_type *r; for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { if (r->lsa_type == OSPF_OPAQUE_LINK_LSA) { msg = new_msg_ready_notify (0, OSPF_OPAQUE_LINK_LSA, r->opaque_type, oi->address->u.prefix4); if (!msg) { zlog_warn ("ospf_apiserver_clients_notify_ready_type9: new_msg_ready_notify failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } void ospf_apiserver_clients_notify_ready_type10 (struct ospf_area *area) { struct listnode *node, *nnode; struct msg *msg; struct ospf_apiserver *apiserv; assert (area); if (!ospf_apiserver_is_ready_type10 (area)) { zlog_warn ("Area not ready for type 10?"); return; } for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) { struct listnode *node2, *nnode2; struct registered_opaque_type *r; for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { if (r->lsa_type == OSPF_OPAQUE_AREA_LSA) { msg = new_msg_ready_notify (0, OSPF_OPAQUE_AREA_LSA, r->opaque_type, area->area_id); if (!msg) { zlog_warn ("ospf_apiserver_clients_notify_ready_type10: new_msg_ready_nofity failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } void ospf_apiserver_clients_notify_ready_type11 (struct ospf *top) { struct listnode *node, *nnode; struct msg *msg; struct in_addr id_null = { .s_addr = 0L }; struct ospf_apiserver *apiserv; assert (top); if (!ospf_apiserver_is_ready_type11 (top)) { zlog_warn ("AS not ready for type 11?"); return; } for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) { struct listnode *node2, *nnode2; struct registered_opaque_type *r; for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { if (r->lsa_type == OSPF_OPAQUE_AS_LSA) { msg = new_msg_ready_notify (0, OSPF_OPAQUE_AS_LSA, r->opaque_type, id_null); if (!msg) { zlog_warn ("ospf_apiserver_clients_notify_ready_type11: new_msg_ready_notify failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } void ospf_apiserver_clients_notify_new_if (struct ospf_interface *oi) { struct msg *msg; msg = new_msg_new_if (0, oi->address->u.prefix4, oi->area->area_id); if (msg != NULL) { ospf_apiserver_clients_notify_all (msg); msg_free (msg); } } void ospf_apiserver_clients_notify_del_if (struct ospf_interface *oi) { struct msg *msg; msg = new_msg_del_if (0, oi->address->u.prefix4); if (msg != NULL) { ospf_apiserver_clients_notify_all (msg); msg_free (msg); } } void ospf_apiserver_clients_notify_ism_change (struct ospf_interface *oi) { struct msg *msg; struct in_addr ifaddr = { .s_addr = 0L }; struct in_addr area_id = { .s_addr = 0L }; assert (oi); assert (oi->ifp); if (oi->address) { ifaddr = oi->address->u.prefix4; } if (oi->area) { area_id = oi->area->area_id; } msg = new_msg_ism_change (0, ifaddr, area_id, oi->state); if (!msg) { zlog_warn ("apiserver_clients_notify_ism_change: msg_new failed"); return; } ospf_apiserver_clients_notify_all (msg); msg_free (msg); } void ospf_apiserver_clients_notify_nsm_change (struct ospf_neighbor *nbr) { struct msg *msg; struct in_addr ifaddr = { .s_addr = 0L }; struct in_addr nbraddr = { .s_addr = 0L }; assert (nbr); if (nbr->oi) { ifaddr = nbr->oi->address->u.prefix4; } nbraddr = nbr->address.u.prefix4; msg = new_msg_nsm_change (0, ifaddr, nbraddr, nbr->router_id, nbr->state); if (!msg) { zlog_warn ("apiserver_clients_notify_nsm_change: msg_new failed"); return; } ospf_apiserver_clients_notify_all (msg); msg_free (msg); } static void apiserver_clients_lsa_change_notify (u_char msgtype, struct ospf_lsa *lsa) { struct msg *msg; struct listnode *node, *nnode; struct ospf_apiserver *apiserv; /* Default area for AS-External and Opaque11 LSAs */ struct in_addr area_id = { .s_addr = 0L }; /* Default interface for non Opaque9 LSAs */ struct in_addr ifaddr = { .s_addr = 0L }; if (lsa->area) { area_id = lsa->area->area_id; } if (lsa->data->type == OSPF_OPAQUE_LINK_LSA) { assert (lsa->oi); ifaddr = lsa->oi->address->u.prefix4; } /* Prepare message that can be sent to clients that have a matching filter */ msg = new_msg_lsa_change_notify (msgtype, 0L, /* no sequence number */ ifaddr, area_id, lsa->flags & OSPF_LSA_SELF, lsa->data); if (!msg) { zlog_warn ("apiserver_clients_lsa_change_notify: msg_new failed"); return; } /* Now send message to all clients with a matching filter */ for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) { struct lsa_filter_type *filter; u_int16_t mask; u_int32_t *area; int i; /* Check filter for this client. */ filter = apiserv->filter; /* Check area IDs in case of non AS-E LSAs. * If filter has areas (num_areas > 0), * then one of the areas must match the area ID of this LSA. */ i = filter->num_areas; if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA) || (lsa->data->type == OSPF_OPAQUE_AS_LSA)) { i = 0; } if (i > 0) { area = (u_int32_t *) (filter + 1); while (i) { if (*area == area_id.s_addr) { break; } i--; area++; } } else { i = 1; } if (i > 0) { /* Area match. Check LSA type. */ mask = ntohs (filter->typemask); if (mask & Power2[lsa->data->type]) { /* Type also matches. Check origin. */ if ((filter->origin == ANY_ORIGIN) || (filter->origin == IS_LSA_SELF (lsa))) { ospf_apiserver_send_msg (apiserv, msg); } } } } /* Free message since it is not used anymore */ msg_free (msg); } /* ------------------------------------------------------------- * Followings are hooks invoked when LSAs are updated or deleted * ------------------------------------------------------------- */ static int apiserver_notify_clients_lsa (u_char msgtype, struct ospf_lsa *lsa) { struct msg *msg; /* default area for AS-External and Opaque11 LSAs */ struct in_addr area_id = { .s_addr = 0L }; /* default interface for non Opaque9 LSAs */ struct in_addr ifaddr = { .s_addr = 0L }; /* Only notify this update if the LSA's age is smaller than MAXAGE. Otherwise clients would see LSA updates with max age just before they are deleted from the LSDB. LSA delete messages have MAXAGE too but should not be filtered. */ if (IS_LSA_MAXAGE(lsa) && (msgtype == MSG_LSA_UPDATE_NOTIFY)) { return 0; } if (lsa->area) { area_id = lsa->area->area_id; } if (lsa->data->type == OSPF_OPAQUE_LINK_LSA) { ifaddr = lsa->oi->address->u.prefix4; } msg = new_msg_lsa_change_notify (msgtype, 0L, /* no sequence number */ ifaddr, area_id, lsa->flags & OSPF_LSA_SELF, lsa->data); if (!msg) { zlog_warn ("notify_clients_lsa: msg_new failed"); return -1; } /* Notify all clients that new LSA is added/updated */ apiserver_clients_lsa_change_notify (msgtype, lsa); /* Clients made their own copies of msg so we can free msg here */ msg_free (msg); return 0; } int ospf_apiserver_lsa_update (struct ospf_lsa *lsa) { return apiserver_notify_clients_lsa (MSG_LSA_UPDATE_NOTIFY, lsa); } int ospf_apiserver_lsa_delete (struct ospf_lsa *lsa) { return apiserver_notify_clients_lsa (MSG_LSA_DELETE_NOTIFY, lsa); } #endif /* SUPPORT_OSPF_API */ quagga-1.2.4/ospfd/ospf_apiserver.h000066400000000000000000000176111325323223500173040ustar00rootroot00000000000000/* * Server side of OSPF API. * Copyright (C) 2001, 2002 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_APISERVER_H #define _OSPF_APISERVER_H /* MTYPE definition is not reflected to "memory.h". */ #define MTYPE_OSPF_APISERVER MTYPE_TMP #define MTYPE_OSPF_APISERVER_MSGFILTER MTYPE_TMP /* List of opaque types that application registered */ struct registered_opaque_type { u_char lsa_type; u_char opaque_type; }; /* Server instance for each accepted client connection. */ struct ospf_apiserver { /* Socket connections for synchronous commands and asynchronous notifications */ int fd_sync; /* synchronous requests */ struct sockaddr_in peer_sync; int fd_async; /* asynchronous notifications */ struct sockaddr_in peer_async; /* List of all opaque types that application registers to use. Using a single connection with the OSPF daemon, multiple pairs can be registered. However, each combination can only be registered once by all applications. */ struct list *opaque_types; /* of type registered_opaque_type */ /* Temporary storage for LSA instances to be refreshed. */ struct ospf_lsdb reserve; /* filter for LSA update/delete notifies */ struct lsa_filter_type *filter; /* Fifo buffers for outgoing messages */ struct msg_fifo *out_sync_fifo; struct msg_fifo *out_async_fifo; /* Read and write threads */ struct thread *t_sync_read; #ifdef USE_ASYNC_READ struct thread *t_async_read; #endif /* USE_ASYNC_READ */ struct thread *t_sync_write; struct thread *t_async_write; }; enum event { OSPF_APISERVER_ACCEPT, OSPF_APISERVER_SYNC_READ, #ifdef USE_ASYNC_READ OSPF_APISERVER_ASYNC_READ, #endif /* USE_ASYNC_READ */ OSPF_APISERVER_SYNC_WRITE, OSPF_APISERVER_ASYNC_WRITE }; /* ----------------------------------------------------------- * Followings are functions to manage client connections. * ----------------------------------------------------------- */ extern unsigned short ospf_apiserver_getport (void); extern int ospf_apiserver_init (void); extern void ospf_apiserver_term (void); extern struct ospf_apiserver *ospf_apiserver_new (int fd_sync, int fd_async); extern void ospf_apiserver_free (struct ospf_apiserver *apiserv); extern void ospf_apiserver_event (enum event event, int fd, struct ospf_apiserver *apiserv); extern int ospf_apiserver_serv_sock_family (unsigned short port, int family); extern int ospf_apiserver_accept (struct thread *thread); extern int ospf_apiserver_read (struct thread *thread); extern int ospf_apiserver_sync_write (struct thread *thread); extern int ospf_apiserver_async_write (struct thread *thread); extern int ospf_apiserver_send_reply (struct ospf_apiserver *apiserv, u_int32_t seqnr, u_char rc); /* ----------------------------------------------------------- * Followings are message handler functions * ----------------------------------------------------------- */ extern int ospf_apiserver_lsa9_originator (void *arg); extern int ospf_apiserver_lsa10_originator (void *arg); extern int ospf_apiserver_lsa11_originator (void *arg); extern void ospf_apiserver_clients_notify_all (struct msg *msg); extern void ospf_apiserver_clients_notify_ready_type9 (struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_ready_type10 (struct ospf_area *area); extern void ospf_apiserver_clients_notify_ready_type11 (struct ospf *top); extern void ospf_apiserver_clients_notify_new_if (struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_del_if (struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_ism_change (struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_nsm_change (struct ospf_neighbor *nbr); extern int ospf_apiserver_is_ready_type9 (struct ospf_interface *oi); extern int ospf_apiserver_is_ready_type10 (struct ospf_area *area); extern int ospf_apiserver_is_ready_type11 (struct ospf *ospf); extern void ospf_apiserver_notify_ready_type9 (struct ospf_apiserver *apiserv); extern void ospf_apiserver_notify_ready_type10 (struct ospf_apiserver *apiserv); extern void ospf_apiserver_notify_ready_type11 (struct ospf_apiserver *apiserv); extern int ospf_apiserver_handle_msg (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_register_opaque_type (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_unregister_opaque_type (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_register_event (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_originate_request (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_delete_request (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_sync_lsdb (struct ospf_apiserver *apiserv, struct msg *msg); /* ----------------------------------------------------------- * Followings are functions for LSA origination/deletion * ----------------------------------------------------------- */ extern int ospf_apiserver_register_opaque_type (struct ospf_apiserver *apiserver, u_char lsa_type, u_char opaque_type); extern int ospf_apiserver_unregister_opaque_type (struct ospf_apiserver *apiserver, u_char lsa_type, u_char opaque_type); extern struct ospf_lsa *ospf_apiserver_opaque_lsa_new (struct ospf_area *area, struct ospf_interface *oi, struct lsa_header *protolsa); extern struct ospf_interface *ospf_apiserver_if_lookup_by_addr (struct in_addr address); extern struct ospf_interface *ospf_apiserver_if_lookup_by_ifp (struct interface *ifp); extern int ospf_apiserver_originate1 (struct ospf_lsa *lsa); extern void ospf_apiserver_flood_opaque_lsa (struct ospf_lsa *lsa); /* ----------------------------------------------------------- * Followings are callback functions to handle opaque types * ----------------------------------------------------------- */ extern int ospf_apiserver_new_if (struct interface *ifp); extern int ospf_apiserver_del_if (struct interface *ifp); extern void ospf_apiserver_ism_change (struct ospf_interface *oi, int old_status); extern void ospf_apiserver_nsm_change (struct ospf_neighbor *nbr, int old_status); extern void ospf_apiserver_config_write_router (struct vty *vty); extern void ospf_apiserver_config_write_if (struct vty *vty, struct interface *ifp); extern void ospf_apiserver_show_info (struct vty *vty, struct ospf_lsa *lsa); extern int ospf_ospf_apiserver_lsa_originator (void *arg); extern struct ospf_lsa *ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa); extern void ospf_apiserver_flush_opaque_lsa (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type); /* ----------------------------------------------------------- * Followings are hooks when LSAs are updated or deleted * ----------------------------------------------------------- */ /* Hooks that are invoked from ospf opaque module */ extern int ospf_apiserver_lsa_update (struct ospf_lsa *lsa); extern int ospf_apiserver_lsa_delete (struct ospf_lsa *lsa); extern void ospf_apiserver_clients_lsa_change_notify (u_char msgtype, struct ospf_lsa *lsa); #endif /* _OSPF_APISERVER_H */ quagga-1.2.4/ospfd/ospf_asbr.c000066400000000000000000000157721325323223500162340ustar00rootroot00000000000000/* * 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 *) XCALLOC (MTYPE_OSPF_EXTERNAL_INFO, sizeof (struct external_info)); new->type = type; ospf_reset_route_map_set_values (&new->route_map_set); return new; } static 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, ifindex_t ifindex, struct in_addr nexthop, route_tag_t tag) { 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.", ospf_redist_string(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 = tag; if (rn) rn->info = new; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("Redistribute[%s]: %s/%d external info created.", ospf_redist_string(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, SPF_FLAG_ASBR_STATUS_CHANGE); ospf_router_lsa_update (ospf); } void ospf_redistribute_withdraw (struct ospf *ospf, u_char type) { struct route_node *rn; struct external_info *ei; /* 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_free (ei); route_unlock_node (rn); rn->info = NULL; } } quagga-1.2.4/ospfd/ospf_asbr.h000066400000000000000000000053571325323223500162370ustar00rootroot00000000000000/* * 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. */ ifindex_t ifindex; /* Nexthop address. */ struct in_addr nexthop; /* Additional Route tag: this is the wire type */ 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 extern void ospf_external_route_remove (struct ospf *, struct prefix_ipv4 *); extern struct external_info *ospf_external_info_new (u_char); extern void ospf_reset_route_map_set_values (struct route_map_set_values *); extern int ospf_route_map_set_compare (struct route_map_set_values *, struct route_map_set_values *); extern struct external_info *ospf_external_info_add (u_char, struct prefix_ipv4, ifindex_t, struct in_addr, route_tag_t); extern void ospf_external_info_delete (u_char, struct prefix_ipv4); extern struct external_info *ospf_external_info_lookup (u_char, struct prefix_ipv4 *); extern struct ospf_route *ospf_external_route_lookup (struct ospf *, struct prefix_ipv4 *); extern void ospf_asbr_status_update (struct ospf *, u_char); extern void ospf_redistribute_withdraw (struct ospf *, u_char); extern void ospf_asbr_check (void); extern void ospf_schedule_asbr_check (void); extern void ospf_asbr_route_install_lsa (struct ospf_lsa *); extern struct ospf_lsa *ospf_external_info_find_lsa (struct ospf *, struct prefix_ipv4 *p); #endif /* _ZEBRA_OSPF_ASBR_H */ quagga-1.2.4/ospfd/ospf_ase.c000066400000000000000000000575401325323223500160540ustar00rootroot00000000000000/* * 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" 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; struct listnode *node; struct 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 (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or)) 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 (ALL_LIST_ELEMENTS_RO (chosen, node, or)) 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) { struct listnode *node; struct ospf_route *or; route_unlock_node (rn); for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or)) if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) return or; } return NULL; } static void ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop) { struct listnode *node; struct ospf_path *op; for (ALL_LIST_ELEMENTS_RO (ro->paths, node, op)) if (op->nexthop.s_addr == 0) op->nexthop.s_addr = nexthop.s_addr; } static int ospf_ase_forward_address_check (struct ospf *ospf, struct in_addr fwd_addr) { struct listnode *ifn; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, ifn, oi)) if (if_is_operative (oi->ifp)) if (oi->type != OSPF_IFTYPE_VIRTUALLINK) if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr)) return 0; return 1; } #if 0 /* Calculate ASBR route. */ static 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) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found", inet_ntoa (asbr.prefix)); return NULL; } if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR"); return NULL; } if (al->e[0].fwd_addr.s_addr != 0) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Forwarding address is not 0.0.0.0."); if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Forwarding address is one of our addresses, Ignore."); return NULL; } if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Couldn't find a route to the forwarding address."); return NULL; } route_unlock_node (rn); if ((asbr_route = rn->info) == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Somehow OSPF route to ASBR is lost"); return NULL; } } return asbr_route; } #endif static 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)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: type-1 created."); new->path_type = OSPF_PATH_TYPE1_EXTERNAL; new->cost = asbr_route->cost + metric; /* X + Y */ } else { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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->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; if (lsa->data->type == OSPF_AS_NSSA_LSA) if (IS_DEBUG_OSPF_NSSA) zlog_debug ("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_debug ("ospf_ase_calc(): Rejecting Local Xlt'd"); return 0; } if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Metric is OSPF_LS_INFINITY"); return 0; } if (IS_LSA_MAXAGE (lsa)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Can't find originating ASBR route"); return 0; } if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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))) { route_unlock_node(rn); if (rn->info == NULL) zlog_info ("Route[External]: 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))) route_unlock_node(rn); if (!rn || (or = rn->info) == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("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) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Old route is better"); /* do nothing */ } /* Routes are equal */ else { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Routes are equal"); ospf_route_copy_nexthops (or, asbr_route->paths); 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; } static 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; struct listnode *n1; struct 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->paths->count != newor->paths->count) return 0; /* Check each path. */ for (n1 = listhead (or->paths), n2 = listhead (newor->paths); n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2)) { op = listgetdata (n1); newop = listgetdata (n2); if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) return 0; if (op->ifindex != newop->ifindex) return 0; } if (or->u.ext.tag != newor->u.ext.tag) return 0; return 1; } static 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; } static int ospf_ase_calculate_timer (struct thread *t) { struct ospf *ospf; struct ospf_lsa *lsa; struct route_node *rn; struct listnode *node; struct ospf_area *area; struct timeval start_time, stop_time; ospf = THREAD_ARG (t); ospf->t_ase_calc = NULL; if (ospf->ase_calc) { ospf->ase_calc = 0; quagga_gettime(QUAGGA_CLK_MONOTONIC, &start_time); /* Calculate external route for each AS-external-LSA */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_ase_calculate_route (ospf, lsa); /* This version simple adds to the table all NSSA areas */ if (ospf->anyNSSA) for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("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); } /* kevinm: And add the NSSA routes in ospf_top */ LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa) ospf_ase_calculate_route(ospf,lsa); /* 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 (); quagga_gettime(QUAGGA_CLK_MONOTONIC, &stop_time); zlog_info ("SPF Processing Time(usecs): External Routes: %lld\n", (stop_time.tv_sec - start_time.tv_sec)*1000000LL+ (stop_time.tv_usec - start_time.tv_usec)); } 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; struct 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(); else route_unlock_node (rn); /* We assume that if LSA is deleted from DB is is also deleted from this RT */ listnode_add (lst, ospf_lsa_lock (lsa)); /* external_lsas lst */ } void ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top) { struct route_node *rn; struct prefix_ipv4 p; struct 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_lookup (top->external_lsas, (struct prefix *) &p); if (rn) { lst = rn->info; listnode_delete (lst, lsa); ospf_lsa_unlock (&lsa); /* external_lsas list */ route_unlock_node (rn); } } void ospf_ase_external_lsas_finish (struct route_table *rt) { struct route_node *rn; struct ospf_lsa *lsa; struct list *lst; struct listnode *node, *nnode; for (rn = route_top (rt); rn; rn = route_next (rn)) if ((lst = rn->info) != NULL) { for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa)) ospf_lsa_unlock (&lsa); /* external_lsas lst */ list_delete (lst); } route_table_finish (rt); } void ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa) { struct list *lsas; struct 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) { route_unlock_node (rn); if (rn->info) return; } rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p); assert (rn); assert (rn->info); lsas = rn->info; route_unlock_node (rn); for (ALL_LIST_ELEMENTS_RO (lsas, node, lsa)) 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; route_unlock_node (rn); } /* 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); } } 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); } quagga-1.2.4/ospfd/ospf_ase.h000066400000000000000000000033321325323223500160470ustar00rootroot00000000000000/* * 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 extern struct ospf_route *ospf_find_asbr_route (struct ospf *, struct route_table *, struct prefix_ipv4 *); extern struct ospf_route *ospf_find_asbr_route_through_area (struct route_table *, struct prefix_ipv4 *, struct ospf_area *); extern int ospf_ase_calculate_route (struct ospf *, struct ospf_lsa *); extern void ospf_ase_calculate_schedule (struct ospf *); extern void ospf_ase_calculate_timer_add (struct ospf *); extern void ospf_ase_external_lsas_finish (struct route_table *); extern void ospf_ase_incremental_update (struct ospf *, struct ospf_lsa *); extern void ospf_ase_register_external_lsa (struct ospf_lsa *, struct ospf *); extern void ospf_ase_unregister_external_lsa (struct ospf_lsa *, struct ospf *); #endif /* _ZEBRA_OSPF_ASE_H */ quagga-1.2.4/ospfd/ospf_dump.c000066400000000000000000001372261325323223500162510ustar00rootroot00000000000000/* * 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 "sockopt.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" const 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" }, }; const int ospf_ism_state_msg_max = OSPF_ISM_STATE_MAX; const struct message ospf_nsm_state_msg[] = { { NSM_DependUpon, "DependUpon" }, { NSM_Deleted, "Deleted" }, { 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" }, }; const int ospf_nsm_state_msg_max = OSPF_NSM_STATE_MAX; const 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" }, }; const int ospf_lsa_type_msg_max = OSPF_MAX_LSA; const 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)" }, }; const int ospf_link_state_id_type_msg_max = OSPF_MAX_LSA; const 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" }, }; const int ospf_network_type_msg_max = OSPF_IFTYPE_MAX; /* AuType */ const struct message ospf_auth_type_str[] = { { OSPF_AUTH_NULL, "Null" }, { OSPF_AUTH_SIMPLE, "Simple" }, { OSPF_AUTH_CRYPTOGRAPHIC, "Cryptographic" }, }; const size_t ospf_auth_type_str_max = sizeof (ospf_auth_type_str) / sizeof (ospf_auth_type_str[0]); /* 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; unsigned long conf_debug_ospf_te = 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; unsigned long term_debug_ospf_te = 0; const char * ospf_redist_string(u_int route_type) { return (route_type == ZEBRA_ROUTE_MAX) ? "Default" : zebra_route_string(route_type); } #define OSPF_AREA_STRING_MAXLEN 16 const 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 const 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); } return buf; } #define OSPF_IF_STRING_MAXLEN 40 const 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)); } const char * ospf_timeval_dump (struct timeval *t, char *buf, size_t size) { /* Making formatted timer strings. */ #define MINUTE_IN_SECONDS 60 #define HOUR_IN_SECONDS (60*MINUTE_IN_SECONDS) #define DAY_IN_SECONDS (24*HOUR_IN_SECONDS) #define WEEK_IN_SECONDS (7*DAY_IN_SECONDS) unsigned long w, d, h, m, s, ms, us; if (!t) return "inactive"; w = d = h = m = s = ms = us = 0; memset (buf, 0, size); us = t->tv_usec; if (us >= 1000) { ms = us / 1000; us %= 1000; } if (ms >= 1000) { t->tv_sec += ms / 1000; ms %= 1000; } if (t->tv_sec > WEEK_IN_SECONDS) { w = t->tv_sec / WEEK_IN_SECONDS; t->tv_sec -= w * WEEK_IN_SECONDS; } if (t->tv_sec > DAY_IN_SECONDS) { d = t->tv_sec / DAY_IN_SECONDS; t->tv_sec -= d * DAY_IN_SECONDS; } if (t->tv_sec >= HOUR_IN_SECONDS) { h = t->tv_sec / HOUR_IN_SECONDS; t->tv_sec -= h * HOUR_IN_SECONDS; } if (t->tv_sec >= MINUTE_IN_SECONDS) { m = t->tv_sec / MINUTE_IN_SECONDS; t->tv_sec -= m * MINUTE_IN_SECONDS; } if (w > 99) snprintf (buf, size, "%ldw%1ldd", w, d); else if (w) snprintf (buf, size, "%ldw%1ldd%02ldh", w, d, h); else if (d) snprintf (buf, size, "%1ldd%02ldh%02ldm", d, h, m); else if (h) snprintf (buf, size, "%ldh%02ldm%02lds", h, m, (long)t->tv_sec); else if (m) snprintf (buf, size, "%ldm%02lds", m, (long)t->tv_sec); else if (ms) snprintf (buf, size, "%ld.%03lds", (long)t->tv_sec, ms); else snprintf (buf, size, "%ld usecs", (long)t->tv_usec); return buf; } const char * ospf_timer_dump (struct thread *t, char *buf, size_t size) { struct timeval result; if (!t) return "inactive"; result = tv_sub (t->u.sands, recent_relative_time()); return ospf_timeval_dump (&result, buf, size); } #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|%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" : "-", (options & OSPF_OPTION_MT) ? "M/T" : "-"); return buf; } static 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_debug ("Hello"); zlog_debug (" NetworkMask %s", inet_ntoa (hello->network_mask)); zlog_debug (" HelloInterval %d", ntohs (hello->hello_interval)); zlog_debug (" Options %d (%s)", hello->options, ospf_options_dump (hello->options)); zlog_debug (" RtrPriority %d", hello->priority); zlog_debug (" RtrDeadInterval %ld", (u_long)ntohl (hello->dead_interval)); zlog_debug (" DRouter %s", inet_ntoa (hello->d_router)); zlog_debug (" BDRouter %s", inet_ntoa (hello->bd_router)); length -= OSPF_HEADER_SIZE + OSPF_HELLO_MIN_SIZE; zlog_debug (" # Neighbors %d", length / 4); for (i = 0; length > 0; i++, length -= sizeof (struct in_addr)) zlog_debug (" Neighbor %s", inet_ntoa (hello->neighbors[i])); } static 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) { const char *lsah_type = LOOKUP (ospf_lsa_type_msg, lsah->type); zlog_debug (" LSA Header"); zlog_debug (" LS age %d", ntohs (lsah->ls_age)); zlog_debug (" Options %d (%s)", lsah->options, ospf_options_dump (lsah->options)); zlog_debug (" LS type %d (%s)", lsah->type, (lsah->type ? lsah_type : "unknown type")); zlog_debug (" Link State ID %s", inet_ntoa (lsah->id)); zlog_debug (" Advertising Router %s", inet_ntoa (lsah->adv_router)); zlog_debug (" LS sequence number 0x%lx", (u_long)ntohl (lsah->ls_seqnum)); zlog_debug (" LS checksum 0x%x", ntohs (lsah->checksum)); zlog_debug (" length %d", ntohs (lsah->length)); } static 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; } static 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_debug (" Router-LSA"); zlog_debug (" flags %s", ospf_router_lsa_flags_dump (rl->flags, buf, BUFSIZ)); zlog_debug (" # links %d", ntohs (rl->links)); len = ntohs (rl->header.length) - OSPF_LSA_HEADER_SIZE - 4; for (i = 0; len > 0; i++) { zlog_debug (" Link ID %s", inet_ntoa (rl->link[i].link_id)); zlog_debug (" Link Data %s", inet_ntoa (rl->link[i].link_data)); zlog_debug (" Type %d", (u_char) rl->link[i].type); zlog_debug (" TOS %d", (u_char) rl->link[i].tos); zlog_debug (" metric %d", ntohs (rl->link[i].metric)); len -= 12; } } static 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_debug (" Network-LSA"); /* zlog_debug ("LSA total size %d", ntohs (nl->header.length)); zlog_debug ("Network-LSA size %d", ntohs (nl->header.length) - OSPF_LSA_HEADER_SIZE); */ zlog_debug (" Network Mask %s", inet_ntoa (nl->mask)); zlog_debug (" # Attached Routers %d", cnt); for (i = 0; i < cnt; i++) zlog_debug (" Attached Router %s", inet_ntoa (nl->routers[i])); } static 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_debug (" Summary-LSA"); zlog_debug (" 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_debug (" TOS=%d metric %d", sl->tos, GET_METRIC (sl->metric)); } static 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_debug (" %s", ospf_lsa_type_msg[al->header.type].str); zlog_debug (" 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_debug (" 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_debug (" Forwarding address %s", inet_ntoa (al->e[i].fwd_addr)); zlog_debug (" External Route Tag %u", al->e[i].route_tag); } } static void ospf_lsa_header_list_dump (struct stream *s, u_int16_t length) { struct lsa_header *lsa; zlog_debug (" # 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_getp (s, OSPF_LSA_HEADER_SIZE); length -= OSPF_LSA_HEADER_SIZE; } } static 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_debug ("Database Description"); zlog_debug (" Interface MTU %d", ntohs (dd->mtu)); zlog_debug (" Options %d (%s)", dd->options, ospf_options_dump (dd->options)); zlog_debug (" Flags %d (%s)", dd->flags, ospf_dd_flags_dump (dd->flags, dd_flags, sizeof dd_flags)); zlog_debug (" Sequence Number 0x%08lx", (u_long)ntohl (dd->dd_seqnum)); length -= OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE; stream_forward_getp (s, OSPF_DB_DESC_MIN_SIZE); ospf_lsa_header_list_dump (s, length); stream_set_getp (s, gp); } static 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_debug ("Link State Request"); zlog_debug (" # 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_debug (" LS type %d", ls_type); zlog_debug (" Link State ID %s", inet_ntoa (ls_id)); zlog_debug (" Advertising Router %s", inet_ntoa (adv_router)); } stream_set_getp (s, sp); } static 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_debug ("Link State Update"); zlog_debug (" # LSAs %d", count); while (length > 0 && count > 0) { if (length < OSPF_HEADER_SIZE || length % 4 != 0) { zlog_debug (" 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; case OSPF_AS_NSSA_LSA: ospf_as_external_lsa_dump (s, length); break; case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_dump (s, length); break; default: break; } stream_forward_getp (s, lsa_len); length -= lsa_len; count--; } stream_set_getp (s, sp); } static 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_debug ("Link State Acknowledgment"); ospf_lsa_header_list_dump (s, length); stream_set_getp (s, sp); } /* Expects header to be in host order */ void ospf_ip_header_dump (struct ip *iph) { /* IP Header dump. */ zlog_debug ("ip_v %d", iph->ip_v); zlog_debug ("ip_hl %d", iph->ip_hl); zlog_debug ("ip_tos %d", iph->ip_tos); zlog_debug ("ip_len %d", iph->ip_len); zlog_debug ("ip_id %u", (u_int32_t) iph->ip_id); zlog_debug ("ip_off %u", (u_int32_t) iph->ip_off); zlog_debug ("ip_ttl %d", iph->ip_ttl); zlog_debug ("ip_p %d", iph->ip_p); zlog_debug ("ip_sum 0x%x", (u_int32_t) iph->ip_sum); zlog_debug ("ip_src %s", inet_ntoa (iph->ip_src)); zlog_debug ("ip_dst %s", inet_ntoa (iph->ip_dst)); } static void ospf_header_dump (struct ospf_header *ospfh) { char buf[9]; u_int16_t auth_type = ntohs (ospfh->auth_type); zlog_debug ("Header"); zlog_debug (" Version %d", ospfh->version); zlog_debug (" Type %d (%s)", ospfh->type, LOOKUP (ospf_packet_type_str, ospfh->type)); zlog_debug (" Packet Len %d", ntohs (ospfh->length)); zlog_debug (" Router ID %s", inet_ntoa (ospfh->router_id)); zlog_debug (" Area ID %s", inet_ntoa (ospfh->area_id)); zlog_debug (" Checksum 0x%x", ntohs (ospfh->checksum)); zlog_debug (" AuType %s", LOOKUP (ospf_auth_type_str, auth_type)); switch (auth_type) { case OSPF_AUTH_NULL: break; case OSPF_AUTH_SIMPLE: memset (buf, 0, 9); strncpy (buf, (char *) ospfh->u.auth_data, 8); zlog_debug (" Simple Password %s", buf); break; case OSPF_AUTH_CRYPTOGRAPHIC: zlog_debug (" Cryptographic Authentication"); zlog_debug (" Key ID %d", ospfh->u.crypt.key_id); zlog_debug (" Auth Data Len %d", ospfh->u.crypt.auth_data_len); zlog_debug (" Sequence number %ld", (u_long)ntohl (ospfh->u.crypt.crypt_seqnum)); break; default: zlog_debug ("* 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_getp (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_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_OFF (i, flag); else TERM_DEBUG_PACKET_OFF (i, flag); } #ifdef DEBUG /* for (i = 0; i < 5; i++) zlog_debug ("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 (debug_ospf_te, debug_ospf_te_cmd, "debug ospf te", DEBUG_STR OSPF_STR "OSPF-TE information\n") { if (vty->node == CONFIG_NODE) CONF_DEBUG_ON (te, TE); TERM_DEBUG_ON (te, TE); return CMD_SUCCESS; } DEFUN (no_debug_ospf_te, no_debug_ospf_te_cmd, "no debug ospf te", NO_STR DEBUG_STR OSPF_STR "OSPF-TE information\n") { if (vty->node == CONFIG_NODE) CONF_DEBUG_OFF (te, TE); TERM_DEBUG_OFF (te, TE); 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, "OSPF debugging status:%s", VTY_NEWLINE); /* Show debug status for events. */ if (IS_DEBUG_OSPF(event,EVENT)) vty_out (vty, " OSPF event debugging is on%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", LOOKUP (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", LOOKUP (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", LOOKUP (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); } /* Show debug status for NSSA. */ if (IS_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA) vty_out (vty, " OSPF NSSA debugging is on%s", VTY_NEWLINE); return CMD_SUCCESS; } /* Debug node. */ static struct cmd_node debug_node = { DEBUG_NODE, "", 1 /* VTYSH */ }; static int config_write_debug (struct vty *vty) { int write = 0; int i, r; const char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"}; const 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 nsm 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); install_element (ENABLE_NODE, &debug_ospf_nssa_cmd); install_element (ENABLE_NODE, &debug_ospf_te_cmd); 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); install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd); install_element (ENABLE_NODE, &no_debug_ospf_te_cmd); 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); install_element (CONFIG_NODE, &debug_ospf_nssa_cmd); install_element (CONFIG_NODE, &debug_ospf_te_cmd); 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); install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd); install_element (CONFIG_NODE, &no_debug_ospf_te_cmd); } quagga-1.2.4/ospfd/ospf_dump.h000066400000000000000000000117111325323223500162440ustar00rootroot00000000000000/* * 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 #define OSPF_DEBUG_TE 0x04 /* 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(nssa,NSSA) #define IS_DEBUG_OSPF_TE IS_DEBUG_OSPF(te,TE) #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) #ifdef ORIGINAL_CODING #else /* ORIGINAL_CODING */ struct stream; #endif /* ORIGINAL_CODING */ #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; extern unsigned long term_debug_ospf_te; /* Message Strings. */ extern char *ospf_lsa_type_str[]; extern const struct message ospf_auth_type_str[]; extern const size_t ospf_auth_type_str_max; /* Prototypes. */ extern const char *ospf_area_name_string (struct ospf_area *); extern const char *ospf_area_desc_string (struct ospf_area *); extern const char *ospf_if_name_string (struct ospf_interface *); extern void ospf_nbr_state_message (struct ospf_neighbor *, char *, size_t); extern char *ospf_options_dump (u_char); extern const char *ospf_timer_dump (struct thread *, char *, size_t); extern const char *ospf_timeval_dump (struct timeval *, char *, size_t); extern void ospf_ip_header_dump (struct ip *); extern void ospf_packet_dump (struct stream *); extern void ospf_lsa_header_dump (struct lsa_header *); extern void debug_init (void); /* Appropriate buffer size to use with ospf_timer_dump and ospf_timeval_dump: */ #define OSPF_TIME_DUMP_SIZE 16 #endif /* _ZEBRA_OSPF_DUMP_H */ quagga-1.2.4/ospfd/ospf_flood.c000066400000000000000000000746561325323223500164160ustar00rootroot00000000000000/* * 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)); /* delayed LSA Ack */ } /* 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; } static 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; struct listnode *node; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Process self-originated LSA seq 0x%x", new->data->type, inet_ntoa (new->data->id), ntohl(new->data->ls_seqnum)); /* 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 */ if (area->router_lsa_self) area->router_lsa_self->data->ls_seqnum = new->data->ls_seqnum; ospf_router_lsa_update_area (area); return; case OSPF_NETWORK_LSA: case OSPF_OPAQUE_LINK_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 (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) /* These are sanity check. */ 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; } if (new->data->type == OSPF_OPAQUE_LINK_LSA) { ospf_opaque_lsa_refresh (new); return; } if (oi->network_lsa_self) oi->network_lsa_self->data->ls_seqnum = new->data->ls_seqnum; /* Schedule network-LSA origination. */ ospf_network_lsa_update (oi); return; } break; case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: ospf_schedule_abr_task (ospf); break; case OSPF_AS_EXTERNAL_LSA : case OSPF_AS_NSSA_LSA: if ( (new->data->type == OSPF_AS_EXTERNAL_LSA) && CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT)) { ospf_translated_nssa_refresh (ospf, NULL, new); return; } 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; 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; 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; 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_debug ("LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), (void *)current, dump_lsa_key (new)); lsa_ack_flag = 0; oi = nbr->oi; /* 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_debug ("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 (recent_relative_time (), current->tv_recv), msec2tv (ospf->min_ls_arrival)) < 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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); /* 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. */ if (current) { switch (current->data->type) { case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_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. */ if (! (new = ospf_lsa_install (ospf, nbr->oi, new))) return -1; /* unknown LSA type or any other error condition */ /* 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. */ static 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_debug ("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_debug ("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_debug ("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); } } } if (IS_OPAQUE_LSA (lsa->data->type)) { if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Skip this neighbor: Not Opaque-capable."); continue; } } /* If the new LSA was received from this neighbor, examine the next neighbor. */ #ifdef ORIGINAL_CODING if (inbr) if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id)) continue; #else /* ORIGINAL_CODING */ 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_debug ("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_debug ("Skip this neighbor: lsah->adv_router == onbr"); continue; } } #endif /* ORIGINAL_CODING */ /* 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)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through_interface(): " "DR/BDR NOT SEND to int %s", IF_NAME (oi)); 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) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through_interface(): " "ISM_Backup NOT SEND to int %s", IF_NAME (oi)); 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). */ /* XXX HASSO: Is this IS_DEBUG_OSPF_NSSA really correct? */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through_interface(): " "DR/BDR sending upd to int %s", IF_NAME (oi)); /* 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) { struct listnode *node, *nnode; struct ospf_interface *oi; 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 (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) { if (area->area_id.s_addr != OSPF_AREA_BACKBONE && oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; 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_debug ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", (void *)lsa->oi, (void *)oi); continue; } 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) { struct listnode *node; struct ospf_area *area; 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. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) /* Translated from 7 */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("Flood/AS: NSSA TRANSLATED LSA"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { int continue_flag = 0; struct listnode *if_node; struct ospf_interface *oi; 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 */ /* Type-7, flood NSSA area */ if (lsa->data->type == OSPF_AS_NSSA_LSA && area == lsa->area) /* We will send it. */ continue_flag = 0; else continue_flag = 1; /* Skip this NSSA area for Type-5's et al */ break; case OSPF_AREA_TYPE_MAX: case OSPF_AREA_STUB: continue_flag = 1; /* Skip this area. */ break; case OSPF_AREA_DEFAULT: default: /* No Type-7 into normal area */ if (lsa->data->type == OSPF_AS_NSSA_LSA) continue_flag = 1; /* skip Type-7 */ else 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 (ALL_LIST_ELEMENTS_RO (area->oiflist, if_node, oi)) { /* 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. */ #ifdef ORIGINAL_CODING switch (lsa->data->type) { case OSPF_ROUTER_LSA: case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */ case OSPF_OPAQUE_AREA_LSA: lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); break; case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ case OSPF_OPAQUE_AS_LSA: lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* Type-7 Only received within NSSA, then flooded */ case OSPF_AS_NSSA_LSA: /* Any P-bit was installed with the Type-7. */ lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); break; default: break; } #else /* ORIGINAL_CODING */ /* * 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 */ case OSPF_OPAQUE_AS_LSA: lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* 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_debug ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); /* Fallthrough */ default: lsa_ack_flag = ospf_flood_through_area (lsa->area, inbr, lsa); break; } #endif /* ORIGINAL_CODING */ 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_debug ("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_debug ("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_debug ("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_debug ("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); } static 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) { struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) ospf_ls_retransmit_delete_nbr_if (oi, lsa); } void ospf_ls_retransmit_delete_nbr_as (struct ospf *ospf, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) ospf_ls_retransmit_delete_nbr_if (oi, 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) { /* Reset the lsa origination time such that it gives more time for the ACK to be received and avoid retransmissions */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); lsa->tv_recv = recent_relative_time (); lsa->tv_orig = lsa->tv_recv; 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) { /* Reset the lsa origination time such that it gives more time for the ACK to be received and avoid retransmissions */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); lsa->tv_recv = recent_relative_time (); lsa->tv_orig = lsa->tv_recv; ospf_flood_through_as (ospf, NULL, lsa); ospf_lsa_maxage (ospf, lsa); } void ospf_lsa_flush (struct ospf *ospf, struct ospf_lsa *lsa) { lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); switch (lsa->data->type) { case OSPF_ROUTER_LSA: case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA: case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: ospf_lsa_flush_area (lsa, lsa->area); break; case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_LSA: ospf_lsa_flush_as (ospf, lsa); break; default: zlog_info ("%s: Unknown LSA type %u", __func__, lsa->data->type); break; } } quagga-1.2.4/ospfd/ospf_flood.h000066400000000000000000000062741325323223500164120ustar00rootroot00000000000000/* * 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 extern int ospf_flood (struct ospf *, struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *); extern int ospf_flood_through (struct ospf *, struct ospf_neighbor *, struct ospf_lsa *); extern int ospf_flood_through_area (struct ospf_area *, struct ospf_neighbor *, struct ospf_lsa *); extern int ospf_flood_through_as (struct ospf *, struct ospf_neighbor *, struct ospf_lsa *); extern unsigned long ospf_ls_request_count (struct ospf_neighbor *); extern int ospf_ls_request_isempty (struct ospf_neighbor *); extern struct ospf_lsa *ospf_ls_request_new (struct lsa_header *); extern void ospf_ls_request_free (struct ospf_lsa *); extern void ospf_ls_request_add (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_request_delete (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_request_delete_all (struct ospf_neighbor *); extern struct ospf_lsa *ospf_ls_request_lookup (struct ospf_neighbor *, struct ospf_lsa *); extern unsigned long ospf_ls_retransmit_count (struct ospf_neighbor *); extern unsigned long ospf_ls_retransmit_count_self (struct ospf_neighbor *, int); extern int ospf_ls_retransmit_isempty (struct ospf_neighbor *); extern void ospf_ls_retransmit_add (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_clear (struct ospf_neighbor *); extern struct ospf_lsa *ospf_ls_retransmit_lookup (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_area (struct ospf_area *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_as (struct ospf *, struct ospf_lsa *); extern void ospf_ls_retransmit_add_nbr_all (struct ospf_interface *, struct ospf_lsa *); extern void ospf_flood_lsa_area (struct ospf_lsa *, struct ospf_area *); extern void ospf_flood_lsa_as (struct ospf_lsa *); extern void ospf_lsa_flush_area (struct ospf_lsa *, struct ospf_area *); extern void ospf_lsa_flush_as (struct ospf *, struct ospf_lsa *); extern void ospf_lsa_flush (struct ospf *, struct ospf_lsa *); extern struct external_info *ospf_external_info_check (struct ospf_lsa *); extern void ospf_lsdb_init (struct ospf_lsdb *); #endif /* _ZEBRA_OSPF_FLOOD_H */ quagga-1.2.4/ospfd/ospf_ia.c000066400000000000000000000470431325323223500156720ustar00rootroot00000000000000/* * 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" static 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; struct listnode *node; if ((rn = route_node_lookup (rtrs, (struct prefix *) abr)) == NULL) return NULL; route_unlock_node (rn); for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or)) if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id) && (or->u.std.flags & ROUTER_LSA_BORDER)) return or; return NULL; } static 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_debug ("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_debug ("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->paths); 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_debug ("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); } } static 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_debug ("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_debug ("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_debug ("ospf_ia_router_route(): merging the new route"); ospf_route_copy_nexthops (or, abr_or->paths); ospf_route_free (new_or); return; } /* New route is worse */ else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_router_route(): skipping the new route"); ospf_route_free (new_or); return; } } ospf_route_copy_nexthops (new_or, abr_or->paths); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_router_route(): adding the new route"); listnode_add (rn->info, new_or); } static 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_debug ("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; /* XXX: This check seems dubious to me. If an ABR has already decided * to consider summaries received in this area, then why would one wish * to exclude default? */ if (IS_OSPF_ABR(ospf) && 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; new_or->u.std.external_routing = area->external_routing; 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; } static 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 :( */ } static 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_debug ("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_debug ("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; new_or->u.std.external_routing = area->external_routing; 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_debug ("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_debug ("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_debug ("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_debug ("ospf_update_network_route(): new route is worse"); return; } if (or->cost == cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): " "new route is same distance, adding nexthops"); ospf_route_copy_nexthops (or, abr_or->paths); } if (or->cost > cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): " "new route is better, overriding nexthops"); ospf_route_subst_nexthops (or, abr_or->paths); 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; or->u.std.external_routing = area->external_routing; /* Note that we can do this only in Shortcut ABR mode, because standard ABR must leave the route type and area unchanged */ } } } static 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_debug ("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)) return; /* no BB area, not Shortcut ABR, exiting */ /* find the backbone route, if possible */ if ((ospf->backbone == NULL) || !(or = ospf_find_asbr_route_through_area (rtrs, p, ospf->backbone))) { 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; new_or->u.std.external_routing = area->external_routing; 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_debug ("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->paths); else if (or->cost > cost) { ospf_route_subst_nexthops (or, abr_or->paths); 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 */ } } static 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_debug ("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_debug ("process_transit_summaries(): metric is infinity, skip"); return 0; } if (IS_LSA_MAXAGE (lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("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; } static 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_debug ("ospf_ia_routing():start"); if (IS_OSPF_ABR (ospf)) { struct listnode *node; struct ospf_area *area; switch (ospf->abr_type) { case OSPF_ABR_STAND: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing():Standard ABR"); if ((area = ospf->backbone)) { struct listnode *node; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_ia_routing():backbone area found"); zlog_debug ("ospf_ia_routing():examining summaries"); } OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) 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_debug ("ospf_ia_routing():backbone area NOT found"); break; case OSPF_ABR_IBM: case OSPF_ABR_CISCO: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_ia_routing(): backbone area found"); zlog_debug ("ospf_ia_routing(): examining BB summaries"); } OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) 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_debug ("ospf_ia_routing(): " "Active BB connection not found"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); } break; case OSPF_ABR_SHORTCUT: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_ia_routing(): backbone area found"); zlog_debug ("ospf_ia_routing(): examining BB summaries"); } OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); } for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) 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 { struct listnode *node; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing():not ABR, considering all areas"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); } } quagga-1.2.4/ospfd/ospf_ia.h000066400000000000000000000027371325323223500157000ustar00rootroot00000000000000/* * 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)); \ } extern void ospf_ia_routing (struct ospf *, struct route_table *, struct route_table *); extern int ospf_area_is_transit (struct ospf_area *); #endif /* _ZEBRA_OSPF_IA_H */ quagga-1.2.4/ospfd/ospf_interface.c000066400000000000000000000764101325323223500172410ustar00rootroot00000000000000/* * 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_update_area (oi->area); } } } /* Simulate down/up on the interface. This is needed, for example, when the MTU changes. */ void ospf_if_reset(struct interface *ifp) { 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; ospf_if_down(oi); ospf_if_up(oi); } } 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_if_reset_type (struct interface *ifp, u_char type) { struct route_node *rn; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; u_char orig_ism_state; if (!oi) continue; orig_ism_state = oi->state; OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); oi->type = IF_DEF_PARAMS (ifp)->type; if (orig_ism_state > ISM_Down) OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); } } /* lookup oi for specified prefix/ifp */ struct ospf_interface * ospf_if_table_lookup (struct interface *ifp, struct prefix *prefix) { struct prefix p; struct route_node *rn; struct ospf_interface *rninfo = NULL; p = *prefix; p.prefixlen = IPV4_MAX_PREFIXLEN; /* route_node_get implicitely locks */ if ((rn = route_node_lookup (IF_OIFS (ifp), &p))) { rninfo = (struct ospf_interface *) rn->info; route_unlock_node (rn); } return rninfo; } static 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); /* rn->info should either be NULL or equal to this oi * as route_node_get may return an existing node */ assert (!rn->info || rn->info == oi); rn->info = oi; } static 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; if ((oi = ospf_if_table_lookup (ifp, p)) == NULL) { oi = XCALLOC (MTYPE_OSPF_IF, sizeof (struct ospf_interface)); memset (oi, 0, sizeof (struct ospf_interface)); } else return oi; /* Set zebra interface pointer. */ oi->ifp = ifp; oi->address = p; ospf_add_to_if (ifp, oi); listnode_add (ospf->oiflist, oi); /* 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); /* Set pseudo neighbor to Null */ oi->nbr_self = NULL; oi->ls_upd_queue = route_table_init (); oi->t_ls_upd_event = NULL; oi->t_ls_ack_direct = NULL; oi->crypt_seqnum = time (NULL); ospf_opaque_type9_lsa_init (oi); 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; struct listnode *node, *nnode; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; struct ospf_lsa *lsa; /* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */ /* delete all static neighbors attached to this interface */ for (ALL_LIST_ELEMENTS (oi->nbr_nbma, node, nnode, nbr_nbma)) { 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 (ALL_LIST_ELEMENTS (oi->ls_ack, node, nnode, lsa)) ospf_lsa_unlock (&lsa); /* oi->ls_ack */ list_delete_all_node (oi->ls_ack); oi->crypt_seqnum = 0; /* Empty link state update queue */ ospf_ls_upd_queue_empty (oi); /* Reset pseudo neighbor. */ ospf_nbr_self_reset (oi); } void ospf_if_free (struct ospf_interface *oi) { ospf_if_down (oi); assert (oi->state == ISM_Down); ospf_opaque_type9_lsa_term (oi); /* 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); thread_cancel_event (master, oi); memset (oi, 0, sizeof (*oi)); XFREE (MTYPE_OSPF_IF, oi); } /* * check if interface with given address is configured and * return it if yes. special treatment for PtP networks. */ struct ospf_interface * ospf_if_is_configured (struct ospf *ospf, struct in_addr *address) { struct listnode *node, *nnode; struct ospf_interface *oi; struct prefix_ipv4 addr; addr.family = AF_INET; addr.prefix = *address; addr.prefixlen = IPV4_MAX_PREFIXLEN; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) if (oi->type != OSPF_IFTYPE_VIRTUALLINK) { if (oi->type == OSPF_IFTYPE_POINTOPOINT) { /* special leniency: match if addr is anywhere on peer subnet */ if (prefix_match(CONNECTED_PREFIX(oi->connected), (struct prefix *)&addr)) return oi; } else { if (IPV4_ADDR_SAME (address, &oi->address->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_exists (struct ospf_interface *oic) { struct listnode *node; struct ospf *ospf; struct ospf_interface *oi; if ((ospf = ospf_lookup ()) == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (oi == oic) return oi; return NULL; } /* Lookup OSPF interface by router LSA posistion */ struct ospf_interface * ospf_if_lookup_by_lsa_pos (struct ospf_area *area, int lsa_pos) { struct listnode *node; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) { if (lsa_pos >= oi->lsa_pos_beg && lsa_pos < oi->lsa_pos_end) return oi; } return NULL; } struct ospf_interface * ospf_if_lookup_by_local_addr (struct ospf *ospf, struct interface *ifp, struct in_addr address) { struct listnode *node; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (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) { struct listnode *node; struct ospf_interface *oi; /* Check each Interface. */ for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { if (oi->type != OSPF_IFTYPE_VIRTUALLINK) { struct prefix ptmp; prefix_copy (&ptmp, CONNECTED_PREFIX(oi->connected)); apply_mask (&ptmp); if (prefix_same (&ptmp, (struct prefix *) p)) return oi; } } return NULL; } /* determine receiving interface by ifp and source address */ struct ospf_interface * ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr src, struct interface *ifp) { struct route_node *rn; struct prefix_ipv4 addr; struct ospf_interface *oi, *match; addr.family = AF_INET; addr.prefix = src; addr.prefixlen = IPV4_MAX_BITLEN; match = NULL; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { oi = rn->info; if (!oi) /* oi can be NULL for PtP aliases */ continue; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; if (if_is_loopback (oi->ifp)) continue; if (prefix_match (CONNECTED_PREFIX(oi->connected), (struct prefix *) &addr)) { if ( (match == NULL) || (match->address->prefixlen < oi->address->prefixlen) ) 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; } } } static struct ospf_if_params * ospf_new_if_params (void) { struct ospf_if_params *oip; oip = XCALLOC (MTYPE_OSPF_IF_PARAMS, sizeof (struct ospf_if_params)); if (!oip) return NULL; 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, fast_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 (); oip->network_lsa_seqnum = htonl(OSPF_INITIAL_SEQUENCE_NUMBER); 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.family = AF_INET; 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, fast_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 && ntohl (oip->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER) { 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.family = AF_INET; 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 = XCALLOC (MTYPE_OSPF_IF_INFO, 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; IF_DEF_PARAMS (ifp)->mtu_ignore = OSPF_MTU_IGNORE_DEFAULT; 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), fast_hello); IF_DEF_PARAMS (ifp)->fast_hello = OSPF_FAST_HELLO_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_type); IF_DEF_PARAMS (ifp)->auth_type = OSPF_AUTH_NOTSET; rc = ospf_opaque_new_if (ifp); return rc; } static int ospf_if_delete_hook (struct interface *ifp) { int rc = 0; struct route_node *rn; rc = ospf_opaque_del_if (ifp); route_table_finish (IF_OIFS (ifp)); for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn)) if (rn->info) ospf_del_if_params (rn->info); route_table_finish (IF_OIFS_PARAMS (ifp)); ospf_del_if_params ((struct ospf_if_params *) IF_DEF_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; } void ospf_if_set_multicast(struct ospf_interface *oi) { if ((oi->state > ISM_Loopback) && (oi->type != OSPF_IFTYPE_LOOPBACK) && (oi->type != OSPF_IFTYPE_VIRTUALLINK) && (OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_ACTIVE)) { /* The interface should belong to the OSPF-all-routers group. */ if (!OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) && (ospf_if_add_allspfrouters(oi->ospf, oi->address, oi->ifp->ifindex) >= 0)) /* Set the flag only if the system call to join succeeded. */ OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); } else { /* The interface should NOT belong to the OSPF-all-routers group. */ if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) { /* Only actually drop if this is the last reference */ if (OI_MEMBER_COUNT(oi, MEMBER_ALLROUTERS) == 1) ospf_if_drop_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex); /* Unset the flag regardless of whether the system call to leave the group succeeded, since it's much safer to assume that we are not a member. */ OI_MEMBER_LEFT(oi,MEMBER_ALLROUTERS); } } if (((oi->type == OSPF_IFTYPE_BROADCAST) || (oi->type == OSPF_IFTYPE_POINTOPOINT)) && ((oi->state == ISM_DR) || (oi->state == ISM_Backup)) && (OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_ACTIVE)) { /* The interface should belong to the OSPF-designated-routers group. */ if (!OI_MEMBER_CHECK(oi, MEMBER_DROUTERS) && (ospf_if_add_alldrouters(oi->ospf, oi->address, oi->ifp->ifindex) >= 0)) /* Set the flag only if the system call to join succeeded. */ OI_MEMBER_JOINED(oi, MEMBER_DROUTERS); } else { /* The interface should NOT belong to the OSPF-designated-routers group */ if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { /* drop only if last reference */ if (OI_MEMBER_COUNT(oi, MEMBER_DROUTERS) == 1) ospf_if_drop_alldrouters(oi->ospf, oi->address, oi->ifp->ifindex); /* Unset the flag regardless of whether the system call to leave the group succeeded, since it's much safer to assume that we are not a member. */ OI_MEMBER_LEFT(oi, MEMBER_DROUTERS); } } } 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 { struct ospf *ospf = ospf_lookup (); if (ospf != NULL) ospf_adjust_sndbuflen (ospf, oi->ifp->mtu); else zlog_warn ("%s: ospf_lookup() returned NULL", __func__); 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); /* delete position in router LSA */ oi->lsa_pos_beg = 0; oi->lsa_pos_end = 0; /* Shutdown packet reception and sending */ ospf_if_stream_unset (oi); 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 = XCALLOC (MTYPE_OSPF_VL_DATA, 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_debug ("ospf_vl_new(): Start"); if (vlink_count == OSPF_VL_MAX_COUNT) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): Alarm: " "cannot create more than OSPF_MAX_VL_COUNT virtual links"); return NULL; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): creating pseudo zebra interface"); snprintf (ifname, sizeof(ifname), "VLINK%d", vlink_count); vi = if_create (ifname, strnlen(ifname, sizeof(ifname))); /* Ensure that linkdetection is not enabled on the stub interfaces * created for OSPF virtual links. */ UNSET_FLAG(vi->status, ZEBRA_INTERFACE_LINKDETECTION); 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_debug ("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; vlink_count++; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): Created name: %s", ifname); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_vl_new(): set associated area to the backbone"); /* Add pseudo neighbor. */ ospf_nbr_self_reset (voi); ospf_area_add_if (voi->area, voi); ospf_if_stream_set (voi); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): Stop"); return voi; } static 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--; } /* Look up vl_data for given peer, optionally qualified to be in the * specified area. NULL area returns first found.. */ struct ospf_vl_data * ospf_vl_lookup (struct ospf *ospf, struct ospf_area *area, struct in_addr vl_peer) { struct ospf_vl_data *vl_data; struct listnode *node; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("%s: Looking for %s", __func__, inet_ntoa (vl_peer)); if (area) zlog_debug ("%s: in area %s", __func__, inet_ntoa (area->area_id)); } for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: VL %s, peer %s", __func__, vl_data->vl_oi->ifp->name, inet_ntoa (vl_data->vl_peer)); if (area && !IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) continue; if (IPV4_ADDR_SAME (&vl_data->vl_peer, &vl_peer)) return vl_data; } return NULL; } static 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); } static int ospf_vl_set_params (struct ospf_vl_data *vl_data, struct vertex *v) { int changed = 0; struct ospf_interface *voi; struct listnode *node; struct vertex_parent *vp = NULL; unsigned 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 (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { vl_data->nexthop.oi = vp->nexthop->oi; vl_data->nexthop.router = vp->nexthop->router; if (!IPV4_ADDR_SAME(&voi->address->u.prefix4, &vl_data->nexthop.oi->address->u.prefix4)) changed = 1; voi->address->u.prefix4 = vl_data->nexthop.oi->address->u.prefix4; voi->address->prefixlen = vl_data->nexthop.oi->address->prefixlen; break; /* We take the first interface. */ } rl = (struct router_lsa *)v->lsa; /* use SPF determined backlink index in struct vertex * for virtual link destination address */ if (vp && vp->backlink >= 0) { if (!IPV4_ADDR_SAME (&vl_data->peer_addr, &rl->link[vp->backlink].link_data)) changed = 1; vl_data->peer_addr = rl->link[vp->backlink].link_data; } else { /* This is highly odd, there is no backlink index * there should be due to the ospf_spf_has_link() check * in SPF. Lets warn and try pick a link anyway. */ zlog_warn ("ospf_vl_set_params: No backlink for %s!", vl_data->vl_oi->ifp->name); for (i = 0; i < ntohs (rl->links); i++) { switch (rl->link[i].type) { case LSA_LINK_TYPE_VIRTUALLINK: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("found back link through VL"); case LSA_LINK_TYPE_TRANSIT: case LSA_LINK_TYPE_POINTOPOINT: if (!IPV4_ADDR_SAME (&vl_data->peer_addr, &rl->link[i].link_data)) changed = 1; vl_data->peer_addr = rl->link[i].link_data; } } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: %s peer address: %s, cost: %d,%schanged", __func__, vl_data->vl_oi->ifp->name, inet_ntoa(vl_data->peer_addr), voi->output_cost, (changed ? " " : " un")); return changed; } void ospf_vl_up_check (struct ospf_area *area, struct in_addr rid, struct vertex *v) { struct ospf *ospf = area->ospf; struct listnode *node; struct ospf_vl_data *vl_data; struct ospf_interface *oi; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_vl_up_check(): Start"); zlog_debug ("ospf_vl_up_check(): Router ID is %s", inet_ntoa (rid)); zlog_debug ("ospf_vl_up_check(): Area is %s", inet_ntoa (area->area_id)); } for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) { if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("%s: considering VL, %s in area %s", __func__, vl_data->vl_oi->ifp->name, inet_ntoa (vl_data->vl_area_id)); zlog_debug ("%s: peer ID: %s", __func__, 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_debug ("ospf_vl_up_check(): this VL matched"); if (oi->state == ISM_Down) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_up_check(): VL is down, waking it up"); SET_FLAG (oi->ifp->flags, IFF_UP); OSPF_ISM_EVENT_EXECUTE(oi,ISM_InterfaceUp); } if (ospf_vl_set_params (vl_data, v)) { if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog_debug ("ospf_vl_up_check: VL cost change," " scheduling router lsa refresh"); if (ospf->backbone) ospf_router_lsa_update_area (ospf->backbone); else if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog_debug ("ospf_vl_up_check: VL cost change, no backbone!"); } } } } void ospf_vl_unapprove (struct ospf *ospf) { struct listnode *node; struct ospf_vl_data *vl_data; for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) UNSET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED); } void ospf_vl_shut_unapproved (struct ospf *ospf) { struct listnode *node, *nnode; struct ospf_vl_data *vl_data; for (ALL_LIST_ELEMENTS (ospf->vlinks, node, nnode, vl_data)) 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_debug ("counting fully adjacent virtual neighbors in area %s", inet_ntoa (area->area_id)); zlog_debug ("there are %d of them", area->full_vls); } return area->full_vls; } int ospf_vls_in_area (struct ospf_area *area) { struct listnode *node; struct ospf_vl_data *vl_data; int c = 0; for (ALL_LIST_ELEMENTS_RO (area->ospf->vlinks, node, vl_data)) if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) c++; return c; } struct crypt_key * ospf_crypt_key_new () { return XCALLOC (MTYPE_OSPF_CRYPT_KEY, sizeof (struct crypt_key)); } void ospf_crypt_key_add (struct list *crypt, struct crypt_key *ck) { listnode_add (crypt, ck); } struct crypt_key * ospf_crypt_key_lookup (struct list *auth_crypt, u_char key_id) { struct listnode *node; struct crypt_key *ck; for (ALL_LIST_ELEMENTS_RO (auth_crypt, node, ck)) if (ck->key_id == key_id) return ck; return NULL; } int ospf_crypt_key_delete (struct list *auth_crypt, u_char key_id) { struct listnode *node, *nnode; struct crypt_key *ck; for (ALL_LIST_ELEMENTS (auth_crypt, node, nnode, ck)) { if (ck->key_id == key_id) { listnode_delete (auth_crypt, ck); XFREE (MTYPE_OSPF_CRYPT_KEY, ck); return 1; } } return 0; } u_char ospf_default_iftype(struct interface *ifp) { if (if_is_pointopoint (ifp)) return OSPF_IFTYPE_POINTOPOINT; else if (if_is_loopback (ifp)) return OSPF_IFTYPE_LOOPBACK; else return OSPF_IFTYPE_BROADCAST; } void ospf_if_init () { /* Initialize Zebra interface data structure. */ om->iflist = iflist; if_add_hook (IF_NEW_HOOK, ospf_if_new_hook); if_add_hook (IF_DELETE_HOOK, ospf_if_delete_hook); } quagga-1.2.4/ospfd/ospf_interface.h000066400000000000000000000270231325323223500172420ustar00rootroot00000000000000/* * 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 #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #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) /* Despite the name, this macro probably is for specialist use only */ #define OSPF_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config) /* Test whether an OSPF interface parameter is set, generally, given some * existing ospf interface */ #define OSPF_IF_PARAM_IS_SET(O,P) \ (OSPF_IF_PARAM_CONFIGURED ((O)->params, P) || \ OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp)->P)) #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: no sending or receiving (no need to join multicast groups) */ DECLARE_IF_PARAM (u_char, priority); /* OSPF Interface priority */ DECLARE_IF_PARAM (struct in_addr, if_area); /* Enable OSPF on this interface with area if_area */ DECLARE_IF_PARAM (u_char, type); /* type of interface */ #define OSPF_IF_ACTIVE 0 #define OSPF_IF_PASSIVE 1 #define OSPF_IF_PASSIVE_STATUS(O) \ (OSPF_IF_PARAM_CONFIGURED((O)->params, passive_interface) ? \ (O)->params->passive_interface : \ (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp), passive_interface) ? \ IF_DEF_PARAMS((O)->ifp)->passive_interface : \ (O)->ospf->passive_interface_default)) DECLARE_IF_PARAM (u_int32_t, v_hello); /* Hello Interval */ DECLARE_IF_PARAM (u_int32_t, v_wait); /* Router Dead Interval */ /* MTU mismatch check (see RFC2328, chap 10.6) */ DECLARE_IF_PARAM (u_char, mtu_ignore); /* Fast-Hellos */ DECLARE_IF_PARAM (u_char, fast_hello); /* Authentication data. */ u_char auth_simple[OSPF_AUTH_SIMPLE_SIZE + 1]; /* Simple password. */ u_char auth_simple__config:1; DECLARE_IF_PARAM (struct list *, auth_crypt); /* List of Auth cryptographic data. */ DECLARE_IF_PARAM (int, auth_type); /* OSPF authentication type */ /* Other, non-configuration state */ u_int32_t network_lsa_seqnum; /* Network LSA seqnum */ }; enum { MEMBER_ALLROUTERS = 0, MEMBER_DROUTERS, MEMBER_MAX, }; struct ospf_if_info { struct ospf_if_params *def_params; struct route_table *params; struct route_table *oifs; unsigned int membership_counts[MEMBER_MAX]; /* multicast group refcnts */ }; 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 vertex_nexthop nexthop; /* Nexthop router and oi to use */ 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; /* Position range in Router LSA */ uint16_t lsa_pos_beg; /* inclusive, >= */ uint16_t lsa_pos_end; /* exclusive, < */ /* 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; /* State of Interface State Machine. */ u_char state; /* To which multicast groups do we currently belong? */ u_char multicast_memberships; #define OI_MEMBER_FLAG(M) (1 << (M)) #define OI_MEMBER_COUNT(O,M) (IF_OSPF_IF_INFO(oi->ifp)->membership_counts[(M)]) #define OI_MEMBER_CHECK(O,M) \ (CHECK_FLAG((O)->multicast_memberships, OI_MEMBER_FLAG(M))) #define OI_MEMBER_JOINED(O,M) \ do { \ SET_FLAG ((O)->multicast_memberships, OI_MEMBER_FLAG(M)); \ IF_OSPF_IF_INFO((O)->ifp)->membership_counts[(M)]++; \ } while (0) #define OI_MEMBER_LEFT(O,M) \ do { \ UNSET_FLAG ((O)->multicast_memberships, OI_MEMBER_FLAG(M)); \ IF_OSPF_IF_INFO((O)->ifp)->membership_counts[(M)]--; \ } while (0) 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. */ struct list *nbr_nbma; /* self-originated LSAs. */ struct ospf_lsa *network_lsa_self; /* network-LSA. */ struct list *opaque_lsa_self; /* Type-9 Opaque-LSAs */ struct route_table *ls_upd_queue; struct list *ls_ack; /* Link State Acknowledgment list. */ struct { 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_opaque_lsa_self; /* Type-9 Opaque-LSAs */ 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. */ extern char *ospf_if_name (struct ospf_interface *); extern struct ospf_interface *ospf_if_new (struct ospf *, struct interface *, struct prefix *); extern void ospf_if_cleanup (struct ospf_interface *); extern void ospf_if_free (struct ospf_interface *); extern int ospf_if_up (struct ospf_interface *); extern int ospf_if_down (struct ospf_interface *); extern int ospf_if_is_up (struct ospf_interface *); extern struct ospf_interface *ospf_if_exists (struct ospf_interface *); extern struct ospf_interface *ospf_if_lookup_by_lsa_pos (struct ospf_area *, int); extern struct ospf_interface *ospf_if_lookup_by_local_addr (struct ospf *, struct interface *, struct in_addr); extern struct ospf_interface *ospf_if_lookup_by_prefix (struct ospf *, struct prefix_ipv4 *); extern struct ospf_interface *ospf_if_table_lookup (struct interface *, struct prefix *); extern struct ospf_interface *ospf_if_addr_local (struct in_addr); extern struct ospf_interface *ospf_if_lookup_recv_if (struct ospf *, struct in_addr, struct interface *); extern struct ospf_interface *ospf_if_is_configured (struct ospf *, struct in_addr *); extern struct ospf_if_params *ospf_lookup_if_params (struct interface *, struct in_addr); extern struct ospf_if_params *ospf_get_if_params (struct interface *, struct in_addr); extern void ospf_del_if_params (struct ospf_if_params *); extern void ospf_free_if_params (struct interface *, struct in_addr); extern void ospf_if_update_params (struct interface *, struct in_addr); extern int ospf_if_new_hook (struct interface *); extern void ospf_if_init (void); extern void ospf_if_stream_set (struct ospf_interface *); extern void ospf_if_stream_unset (struct ospf_interface *); extern void ospf_if_reset_variables (struct ospf_interface *); extern void ospf_if_reset_type (struct interface *, u_char type); extern int ospf_if_is_enable (struct ospf_interface *); extern int ospf_if_get_output_cost (struct ospf_interface *); extern void ospf_if_recalculate_output_cost (struct interface *); /* Simulate down/up on the interface. */ extern void ospf_if_reset (struct interface *); extern struct ospf_interface *ospf_vl_new (struct ospf *, struct ospf_vl_data *); extern struct ospf_vl_data *ospf_vl_data_new (struct ospf_area *, struct in_addr); extern struct ospf_vl_data *ospf_vl_lookup (struct ospf *, struct ospf_area *, struct in_addr); extern void ospf_vl_data_free (struct ospf_vl_data *); extern void ospf_vl_add (struct ospf *, struct ospf_vl_data *); extern void ospf_vl_delete (struct ospf *, struct ospf_vl_data *); extern void ospf_vl_up_check (struct ospf_area *, struct in_addr, struct vertex *); extern void ospf_vl_unapprove (struct ospf *); extern void ospf_vl_shut_unapproved (struct ospf *); extern int ospf_full_virtual_nbrs (struct ospf_area *); extern int ospf_vls_in_area (struct ospf_area *); extern struct crypt_key *ospf_crypt_key_lookup (struct list *, u_char); extern struct crypt_key *ospf_crypt_key_new (void); extern void ospf_crypt_key_add (struct list *, struct crypt_key *); extern int ospf_crypt_key_delete (struct list *, u_char); extern u_char ospf_default_iftype (struct interface *ifp); /* Set all multicast memberships appropriately based on the type and state of the interface. */ extern void ospf_if_set_multicast (struct ospf_interface *); #endif /* _ZEBRA_OSPF_INTERFACE_H */ quagga-1.2.4/ospfd/ospf_ism.c000066400000000000000000000441421325323223500160660ustar00rootroot00000000000000/* * 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" #include "ospfd/ospf_snmp.h" /* elect DR and BDR. Refer to RFC2319 section 9.4 */ static struct ospf_neighbor * ospf_dr_election_sub (struct list *routers) { struct listnode *node; struct ospf_neighbor *nbr, *max = NULL; /* Choose highest router priority. In case of tie, choose highest Router ID. */ for (ALL_LIST_ELEMENTS_RO (routers, node, nbr)) { 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; } static struct ospf_neighbor * ospf_elect_dr (struct ospf_interface *oi, struct list *el_list) { struct list *dr_list; struct listnode *node; struct ospf_neighbor *nbr, *dr = NULL, *bdr = NULL; dr_list = list_new (); /* Add neighbors to the list. */ for (ALL_LIST_ELEMENTS_RO (el_list, node, nbr)) { /* 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; } static struct ospf_neighbor * ospf_elect_bdr (struct ospf_interface *oi, struct list *el_list) { struct list *bdr_list, *no_dr_list; struct listnode *node; struct ospf_neighbor *nbr, *bdr = NULL; bdr_list = list_new (); no_dr_list = list_new (); /* Add neighbors to the list. */ for (ALL_LIST_ELEMENTS_RO (el_list, node, nbr)) { /* 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; } static 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; } static void ospf_dr_eligible_routers (struct route_table *nbrs, struct 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. */ static 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); } static int ospf_dr_election (struct ospf_interface *oi) { struct in_addr old_dr, old_bdr; int old_state, new_state; struct list *el_list; /* 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. */ ospf_elect_bdr (oi, el_list); ospf_elect_dr (oi, el_list); new_state = ospf_ism_state (oi); zlog_debug ("DR-Election[1st]: Backup %s", inet_ntoa (BDR (oi))); zlog_debug ("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_debug ("DR-Election[2nd]: Backup %s", inet_ntoa (BDR (oi))); zlog_debug ("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); 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_HELLO_TIMER_ON (oi); return 0; } static 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. */ static 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_MSEC_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_MSEC_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_HELLO_TIMER_ON (oi); 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_HELLO_TIMER_ON (oi); 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_HELLO_TIMER_ON (oi); OSPF_ISM_TIMER_OFF (oi->t_wait); OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); break; } } static 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; } static 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. */ static int ism_interface_down (struct ospf_interface *oi) { ospf_if_cleanup (oi); return 0; } static int ism_backup_seen (struct ospf_interface *oi) { return ospf_dr_election (oi); } static int ism_wait_timer (struct ospf_interface *oi) { return ospf_dr_election (oi); } static int ism_neighbor_change (struct ospf_interface *oi) { return ospf_dr_election (oi); } static int ism_ignore (struct ospf_interface *oi) { if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: ism_ignore called", IF_NAME (oi)); return 0; } /* Interface State Machine */ struct { int (*func) (struct ospf_interface *); 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 const char *ospf_ism_event_str[] = { "NoEvent", "InterfaceUp", "WaitTimer", "BackupSeen", "NeighborChange", "LoopInd", "UnLoopInd", "InterfaceDown", }; static 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_DEBUG, "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++; #ifdef HAVE_SNMP /* Terminal state or regression */ if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther) || (state == ISM_PointToPoint) || (state < old_state)) { /* ospfVirtIfStateChange */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) ospfTrapVirtIfStateChange (oi); /* ospfIfStateChange */ else ospfTrapIfStateChange (oi); } #endif /* Set multicast memberships appropriately for new state. */ ospf_if_set_multicast(oi); if (old_state == ISM_Down || state == ISM_Down) ospf_check_abr_status (oi->ospf); /* Originate router-LSA. */ 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_update_area (oi->area); /* Originate network-LSA. */ if (old_state != ISM_DR && state == ISM_DR) ospf_network_lsa_update (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_lsa_unlock (&oi->network_lsa_self); oi->network_lsa_self = NULL; } ospf_opaque_ism_change (oi, old_state); /* 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_DEBUG, "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; } quagga-1.2.4/ospfd/ospf_ism.h000066400000000000000000000102651325323223500160720ustar00rootroot00000000000000/* * 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 /* Because DR/DROther values are exhanged wrt RFC */ #define ISM_SNMP(x) (((x) == ISM_DROther) ? ISM_DR : \ ((x) == ISM_DR) ? ISM_DROther : (x)) /* 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) \ do { \ if (!(T)) \ (T) = thread_add_timer (master, (F), oi, (V)); \ } while (0) #define OSPF_ISM_TIMER_MSEC_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer_msec (master, (F), oi, (V)); \ } while (0) /* convenience macro to set hello timer correctly, according to * whether fast-hello is set or not */ #define OSPF_HELLO_TIMER_ON(O) \ do { \ if (OSPF_IF_PARAM ((O), fast_hello)) \ OSPF_ISM_TIMER_MSEC_ON ((O)->t_hello, ospf_hello_timer, \ 1000 / OSPF_IF_PARAM ((O), fast_hello)); \ else \ OSPF_ISM_TIMER_ON ((O)->t_hello, ospf_hello_timer, \ OSPF_IF_PARAM ((O), v_hello)); \ } while (0) /* Macro for OSPF ISM timer turn off. */ #define OSPF_ISM_TIMER_OFF(X) \ do { \ if (X) \ { \ thread_cancel (X); \ (X) = NULL; \ } \ } while (0) /* 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. */ extern int ospf_ism_event (struct thread *); extern void ism_change_status (struct ospf_interface *, int); extern int ospf_hello_timer (struct thread *thread); #endif /* _ZEBRA_OSPF_ISM_H */ quagga-1.2.4/ospfd/ospf_lsa.c000066400000000000000000003130551325323223500160570ustar00rootroot00000000000000/* * 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 "checksum.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_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_abr.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 msec2tv (int a) { struct timeval ret; ret.tv_sec = 0; ret.tv_usec = a * 1000; return tv_adjust (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; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); delta = tv_sub (now, lsa->tv_orig); if (tv_cmp (delta, msec2tv (OSPF_MIN_LS_INTERVAL)) < 0) { delay = tv_ceil (tv_sub (msec2tv (OSPF_MIN_LS_INTERVAL), delta)); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("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; age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (recent_relative_time (), lsa->tv_recv)); return age; } /* Fletcher Checksum -- Refer to RFC1008. */ /* All the offsets are zero-based. The offsets in the RFC1008 are one-based. */ u_int16_t ospf_lsa_checksum (struct lsa_header *lsa) { u_char *buffer = (u_char *) &lsa->options; int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */ /* Skip the AGE field */ u_int16_t len = ntohs(lsa->length) - options_offset; /* Checksum offset starts from "options" field, not the beginning of the lsa_header struct. The offset is 14, rather than 16. */ int checksum_offset = (u_char *) &lsa->checksum - buffer; return fletcher_checksum(buffer, len, checksum_offset); } int ospf_lsa_checksum_valid (struct lsa_header *lsa) { u_char *buffer = (u_char *) &lsa->options; int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */ /* Skip the AGE field */ u_int16_t len = ntohs(lsa->length) - options_offset; return(fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); } /* Create OSPF LSA. */ struct ospf_lsa * ospf_lsa_new () { struct ospf_lsa *new; new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); new->flags = 0; new->lock = 1; new->retransmit_counter = 0; new->tv_recv = recent_relative_time (); 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_debug ("LSA: duplicated %p (new: %p)", (void *)lsa, (void *)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_debug ("LSA: freed %p", (void *)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 || !*lsa) return; (*lsa)->lock--; assert ((*lsa)->lock >= 0); if ((*lsa)->lock == 0) { assert (CHECK_FLAG ((*lsa)->flags, OSPF_LSA_DISCARD)); ospf_lsa_free (*lsa); *lsa = NULL; } } /* 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) { return XCALLOC (MTYPE_OSPF_LSA_DATA, size); } /* 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_debug ("LSA[Type%d:%s]: data freed %p", lsah->type, inet_ntoa (lsah->id), (void *)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 (OSPF_LSA_INITIAL_AGE); lsah->options = options; lsah->type = type; lsah->id = id; lsah->adv_router = router_id; lsah->ls_seqnum = htonl (OSPF_INITIAL_SEQUENCE_NUMBER); stream_forward_endp (s, OSPF_LSA_HEADER_SIZE); } /* router-LSA related functions. */ /* Get router-LSA flags. */ static 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, ROUTER_LSA_EXTERNAL); /* If ASBR set External flag */ else if (IS_OSPF_ASBR (area->ospf)) SET_FLAG (flags, ROUTER_LSA_EXTERNAL); /* Set ABR dependent flags */ if (IS_OSPF_ABR (area->ospf)) { SET_FLAG (flags, ROUTER_LSA_BORDER); /* If Area is NSSA and we are both ABR and unconditional translator, * set Nt bit to inform other routers. */ if ( (area->external_routing == OSPF_AREA_NSSA) && (area->NSSATranslatorRole == OSPF_NSSA_ROLE_ALWAYS)) SET_FLAG (flags, ROUTER_LSA_NT); } 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; } /* Determine cost of link, taking RFC3137 stub-router support into * consideration */ static u_int16_t ospf_link_cost (struct ospf_interface *oi) { /* RFC3137 stub router support */ if (!CHECK_FLAG (oi->area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) return oi->output_cost; else return OSPF_OUTPUT_COST_INFINITE; } /* Set a link information. */ static char link_info_set (struct stream *s, struct in_addr id, struct in_addr data, u_char type, u_char tos, u_int16_t cost) { /* LSA stream is initially allocated to OSPF_MAX_LSA_SIZE, suits * vast majority of cases. Some rare routers with lots of links need more. * we try accomodate those here. */ if (STREAM_WRITEABLE(s) < OSPF_ROUTER_LSA_LINK_SIZE) { size_t ret = OSPF_MAX_LSA_SIZE; /* Can we enlarge the stream still? */ if (STREAM_SIZE(s) == OSPF_MAX_LSA_SIZE) { /* we futz the size here for simplicity, really we need to account * for just: * IP Header - (sizeof (struct ip)) * OSPF Header - OSPF_HEADER_SIZE * LSA Header - OSPF_LSA_HEADER_SIZE * MD5 auth data, if MD5 is configured - OSPF_AUTH_MD5_SIZE. * * Simpler just to subtract OSPF_MAX_LSA_SIZE though. */ ret = stream_resize (s, OSPF_MAX_PACKET_SIZE - OSPF_MAX_LSA_SIZE); } if (ret == OSPF_MAX_LSA_SIZE) { zlog_warn ("%s: Out of space in LSA stream, left %zd, size %zd", __func__, STREAM_REMAIN (s), STREAM_SIZE (s)); return 0; } } /* 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. */ return 1; } /* Describe Point-to-Point link (Section 12.4.1.1). */ static int lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi) { int links = 0; struct ospf_neighbor *nbr; struct in_addr id, mask; u_int16_t cost = ospf_link_cost (oi); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("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. */ links += link_info_set (s, nbr->router_id, oi->address->u.prefix4, LSA_LINK_TYPE_POINTOPOINT, 0, cost); } /* Regardless of the state of the neighboring router, we must add a Type 3 link (stub network). N.B. Options 1 & 2 share basically the same logic. */ masklen2ip (oi->address->prefixlen, &mask); id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & mask.s_addr; links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); return links; } /* Describe Broadcast Link. */ static int lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) { struct ospf_neighbor *dr; struct in_addr id, mask; u_int16_t cost = ospf_link_cost (oi); /* Describe Type 3 Link. */ if (oi->state == ISM_Waiting) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Interface %s is in state Waiting. " "Adding stub interface", oi->ifp->name); masklen2ip (oi->address->prefixlen, &mask); id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); } 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) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Interface %s has a DR. " "Adding transit interface", oi->ifp->name); return link_info_set (s, DR (oi), oi->address->u.prefix4, LSA_LINK_TYPE_TRANSIT, 0, cost); } /* Describe type 3 link. */ else { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Interface %s has no DR. " "Adding stub interface", oi->ifp->name); masklen2ip (oi->address->prefixlen, &mask); id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); } } static 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; return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); } /* Describe Virtual Link. */ static int lsa_link_virtuallink_set (struct stream *s, struct ospf_interface *oi) { struct ospf_neighbor *nbr; u_int16_t cost = ospf_link_cost (oi); if (oi->state == ISM_PointToPoint) if ((nbr = ospf_nbr_lookup_ptop (oi))) if (nbr->state == NSM_Full) { return link_info_set (s, nbr->router_id, oi->address->u.prefix4, LSA_LINK_TYPE_VIRTUALLINK, 0, cost); } 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.*/ /* from "edward rrr" http://marc.theaimsgroup.com/?l=zebra&m=100739222210507&w=2 */ static 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; u_int16_t cost = ospf_link_cost (oi); mask.s_addr = 0xffffffff; id.s_addr = oi->address->u.prefix4.s_addr; links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("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) { links += link_info_set (s, nbr->router_id, oi->address->u.prefix4, LSA_LINK_TYPE_POINTOPOINT, 0, cost); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("PointToMultipoint: set link to %s", inet_ntoa(oi->address->u.prefix4)); } return links; } /* Set router-LSA link information. */ static int router_lsa_link_set (struct stream *s, struct ospf_area *area) { struct listnode *node; struct ospf_interface *oi; int links = 0; for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) { struct interface *ifp = oi->ifp; /* Check interface is up, OSPF is enable. */ if (if_is_operative (ifp)) { if (oi->state != ISM_Down) { oi->lsa_pos_beg = links; /* 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); } oi->lsa_pos_end = links; } } } return links; } /* Set router-LSA body. */ static 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 = stream_get_endp(s); /* 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); } static int ospf_stub_router_timer (struct thread *t) { struct ospf_area *area = THREAD_ARG (t); area->t_stub_router = NULL; SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); /* clear stub route state and generate router-lsa refresh, don't * clobber an administratively set stub-router state though. */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) return 0; UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); ospf_router_lsa_update_area (area); return 0; } static void ospf_stub_router_check (struct ospf_area *area) { /* area must either be administratively configured to be stub * or startup-time stub-router must be configured and we must in a pre-stub * state. */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) { SET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); return; } /* not admin-stubbed, check whether startup stubbing is configured and * whether it's not been done yet */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED)) return; if (area->ospf->stub_router_startup_time == OSPF_STUB_ROUTER_UNCONFIGURED) { /* stub-router is hence done forever for this area, even if someone * tries configure it (take effect next restart). */ SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); return; } /* startup stub-router configured and not yet done */ SET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); OSPF_AREA_TIMER_ON (area->t_stub_router, ospf_stub_router_timer, area->ospf->stub_router_startup_time); } /* Create new router-LSA. */ static 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_debug ("LSA[Type1]: Create router-LSA instance"); /* check whether stub-router is desired, and if this is the first * router LSA. */ ospf_stub_router_check (area); /* Create a stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); /* Set LSA common header fields. */ lsa_header_set (s, LSA_OPTIONS_GET (area) | LSA_OPTIONS_NSSA_GET (area), OSPF_ROUTER_LSA, ospf->router_id, ospf->router_id); /* Set router-LSA body fields. */ ospf_router_lsa_body_set (s, area); /* Set length. */ length = stream_get_endp (s); lsah = (struct lsa_header *) STREAM_DATA (s); lsah->length = htons (length); /* Now, create OSPF LSA instance. */ if ( (new = ospf_lsa_new ()) == NULL) { zlog_err ("%s: Unable to create new lsa", __func__); return NULL; } new->area = area; SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); /* 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. */ static struct ospf_lsa * ospf_router_lsa_originate (struct ospf_area *area) { struct ospf_lsa *new; /* Create new router-LSA instance. */ if ( (new = ospf_router_lsa_new (area)) == NULL) { zlog_err ("%s: ospf_router_lsa_new returned NULL", __func__); return NULL; } /* Sanity check. */ if (new->data->adv_router.s_addr == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("LSA[Type%d:%s]: Originate router-LSA %p", new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } return new; } /* Refresh router-LSA. */ static 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); /* Unregister LSA from refresh-list */ ospf_refresher_unregister_lsa (area->ospf, lsa); /* Create new router-LSA instance. */ if ( (new = ospf_router_lsa_new (area)) == NULL) { zlog_err ("%s: ospf_router_lsa_new returned NULL", __func__); return NULL; } 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_debug ("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_update_area (struct ospf_area *area) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("[router-LSA]: (router-LSA area update)"); /* Now refresh router-LSA. */ if (area->router_lsa_self) ospf_lsa_refresh (area->ospf, area->router_lsa_self); /* Newly originate router-LSA. */ else ospf_router_lsa_originate (area); return 0; } int ospf_router_lsa_update (struct ospf *ospf) { struct listnode *node, *nnode; struct ospf_area *area; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("Timer[router-LSA Update]: (timer expire)"); for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { struct ospf_lsa *lsa = area->router_lsa_self; struct router_lsa *rl; const 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_debug("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_debug("LSA[Type%d:%s]: Refresh router-LSA for Area %s", lsa->data->type, inet_ntoa (lsa->data->id), area_str); ospf_refresher_unregister_lsa (ospf, lsa); 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_update_area (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_update_area (area); } } return 0; } /* network-LSA related functions. */ /* Originate Network-LSA. */ static 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); } static struct ospf_lsa * ospf_network_lsa_new (struct ospf_interface *oi) { struct stream *s; struct ospf_lsa *new; struct lsa_header *lsah; struct ospf_if_params *oip; 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_debug ("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. */ if ( (new = ospf_lsa_new ()) == NULL) { zlog_err ("%s: ospf_lsa_new returned NULL", __func__); return NULL; } new->area = oi->area; SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); /* Copy LSA to store. */ new->data = ospf_lsa_data_new (length); memcpy (new->data, lsah, length); stream_free (s); /* Remember prior network LSA sequence numbers, even if we stop * originating one for this oi, to try avoid re-originating LSAs with a * prior sequence number, and thus speed up adjency forming & convergence. */ if ((oip = ospf_lookup_if_params (oi->ifp, oi->address->u.prefix4))) { new->data->ls_seqnum = oip->network_lsa_seqnum; new->data->ls_seqnum = lsa_seqnum_increment (new); } else { oip = ospf_get_if_params (oi->ifp, oi->address->u.prefix4); ospf_if_update_params (oi->ifp, oi->address->u.prefix4); } oip->network_lsa_seqnum = new->data->ls_seqnum; return new; } /* Originate network-LSA. */ void ospf_network_lsa_update (struct ospf_interface *oi) { struct ospf_lsa *new; if (oi->network_lsa_self != NULL) { ospf_lsa_refresh (oi->ospf, oi->network_lsa_self); return; } /* Create new network-LSA instance. */ new = ospf_network_lsa_new (oi); if (new == NULL) return; /* 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_debug ("LSA[Type%d:%s]: Originate network-LSA %p", new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } return; } static struct ospf_lsa * ospf_network_lsa_refresh (struct ospf_lsa *lsa) { struct ospf_area *area = lsa->area; struct ospf_lsa *new, *new2; struct ospf_if_params *oip; struct ospf_interface *oi; assert (lsa->data); /* Retrieve the oi for the network LSA */ oi = ospf_if_lookup_by_local_addr (area->ospf, NULL, lsa->data->id); if (oi == NULL) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: network-LSA refresh: " "no oi found, ick, ignoring.", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_lsa_header_dump (lsa->data); } return NULL; } /* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_area (area, lsa); /* Unregister LSA from refresh-list */ ospf_refresher_unregister_lsa (area->ospf, lsa); /* Create new network-LSA instance. */ new = ospf_network_lsa_new (oi); if (new == NULL) return NULL; oip = ospf_lookup_if_params (oi->ifp, oi->address->u.prefix4); assert (oip != NULL); oip->network_lsa_seqnum = new->data->ls_seqnum = lsa_seqnum_increment (lsa); new2 = ospf_lsa_install (area->ospf, oi, new); assert (new2 == new); /* Flood LSA through aera. */ ospf_flood_through_area (area, NULL, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: network-LSA refresh", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } return new; } static 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. */ static 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); } static 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 (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_SUMMARY_LSA); return NULL; } if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("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 | OSPF_LSA_SELF_CHECKED); /* 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); if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_SUMMARY_LSA); return NULL; } /* Create new summary-LSA instance. */ if ( !(new = ospf_summary_lsa_new (area, (struct prefix *) p, metric, id))) return NULL; /* 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_debug ("LSA[Type%d:%s]: Originate summary-LSA %p", new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } return new; } static 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); if (!new) return NULL; new->data->ls_seqnum = lsa_seqnum_increment (lsa); 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_debug ("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. */ static void ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p, u_int32_t metric) { /* Put Network Mask. */ stream_put_ipv4 (s, (u_int32_t) 0); /* Set # TOS. */ stream_putc (s, (u_char) 0); /* Set metric. */ stream_put_ospf_metric (s, metric); } static 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 (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_ASBR_SUMMARY_LSA); return NULL; } if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("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 | OSPF_LSA_SELF_CHECKED); /* 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); if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_ASBR_SUMMARY_LSA); return NULL; } /* Create new summary-LSA instance. */ new = ospf_summary_asbr_lsa_new (area, (struct prefix *) p, metric, id); if (!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_debug ("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p", new->data->type, inet_ntoa (new->data->id), (void *)new); ospf_lsa_header_dump (new->data); } return new; } static 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); if (!new) return NULL; new->data->ls_seqnum = lsa_seqnum_increment (lsa); 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_debug ("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*/ static struct in_addr ospf_external_lsa_nexthop_get (struct ospf *ospf, struct in_addr nexthop) { struct in_addr fwd; struct prefix nh; struct listnode *node; struct ospf_interface *oi; 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; /* XXX/SCALE: If there were a lot of oi's on an ifp, then it'd be * better to make use of the per-ifp table of ois. */ for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (if_is_operative (oi->ifp)) if (oi->address->family == AF_INET) if (prefix_match (oi->address, &nh)) return nexthop; return fwd; } /* 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_operative (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; struct listnode *node; struct ospf_interface *oi; fwd.s_addr = 0; best_default.s_addr = 0; for (ALL_LIST_ELEMENTS_RO (area->ospf->oiflist, node, oi)) { if (if_is_operative (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; if (best_default.s_addr != 0) return best_default; return fwd; } #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. */ static 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 */ stream_putl (s, ei->tag); } /* Create new external-LSA. */ static 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_debug ("LSA[Type5]: External info is NULL, can't originate"); return NULL; } if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("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_debug ("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 | OSPF_LSA_SELF_CHECKED); /* Copy LSA data to store, discard stream. */ new->data = ospf_lsa_data_new (length); memcpy (new->data, lsah, length); stream_free (s); return new; } /* As Type-7 */ static void ospf_install_flood_nssa (struct ospf *ospf, struct ospf_lsa *lsa, struct external_info *ei) { struct ospf_lsa *new; struct as_external_lsa *extlsa; struct ospf_area *area; struct listnode *node, *nnode; /* LSA may be a Type-5 originated via translation of a Type-7 LSA * which originated from an NSSA area. In which case it should not be * flooded back to NSSA areas. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) return; /* 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 (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { /* Don't install Type-7 LSA's into nonNSSA area */ if (area->external_routing != OSPF_AREA_NSSA) continue; /* make lsa duplicate, lock=1 */ new = ospf_lsa_dup (lsa); new->area = area; new->data->type = OSPF_AS_NSSA_LSA; /* set P-bit if not ABR */ if (! IS_OSPF_ABR (ospf)) { SET_FLAG(new->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 new */ extlsa = (struct as_external_lsa *)(new->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_debug ("LSA[Type-7]: Could not build FWD-ADDR"); ospf_lsa_discard (new); return; } } /* install also as Type-7 */ ospf_lsa_install (ospf, NULL, new); /* Remove Old, Lock New = 2 */ /* will send each copy, lock=2+n */ ospf_flood_through_as (ospf, NULL, new); /* all attached NSSA's, no AS/STUBs */ } } static struct ospf_lsa * ospf_lsa_translated_nssa_new (struct ospf *ospf, struct ospf_lsa *type7) { struct ospf_lsa *new; struct as_external_lsa *ext, *extnew; struct external_info ei; ext = (struct as_external_lsa *)(type7->data); /* need external_info struct, fill in bare minimum */ ei.p.family = AF_INET; ei.p.prefix = type7->data->id; ei.p.prefixlen = ip_masklen (ext->mask); ei.type = ZEBRA_ROUTE_OSPF; ei.nexthop = ext->header.adv_router; ei.route_map_set.metric = -1; ei.route_map_set.metric_type = -1; ei.tag = 0; if ( (new = ospf_external_lsa_new (ospf, &ei, &type7->data->id)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_nssa_translate_originate(): Could not originate " "Translated Type-5 for %s", inet_ntoa (ei.p.prefix)); return NULL; } extnew = (struct as_external_lsa *)(new->data); /* copy over Type-7 data to new */ extnew->e[0].tos = ext->e[0].tos; extnew->e[0].route_tag = ext->e[0].route_tag; extnew->e[0].fwd_addr.s_addr = ext->e[0].fwd_addr.s_addr; new->data->ls_seqnum = type7->data->ls_seqnum; /* add translated flag, checksum and lock new lsa */ SET_FLAG (new->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7 */ new = ospf_lsa_lock (new); return new; } /* Originate Translated Type-5 for supplied Type-7 NSSA LSA */ struct ospf_lsa * ospf_translated_nssa_originate (struct ospf *ospf, struct ospf_lsa *type7) { struct ospf_lsa *new; struct as_external_lsa *extnew; /* we cant use ospf_external_lsa_originate() as we need to set * the OSPF_LSA_LOCAL_XLT flag, must originate by hand */ if ( (new = ospf_lsa_translated_nssa_new (ospf, type7)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_originate(): Could not translate " "Type-7, Id %s, to Type-5", inet_ntoa (type7->data->id)); return NULL; } extnew = (struct as_external_lsa *)new; if (IS_DEBUG_OSPF_NSSA) { zlog_debug ("ospf_translated_nssa_originate(): " "translated Type 7, installed:"); ospf_lsa_header_dump (new->data); zlog_debug (" Network mask: %d",ip_masklen (extnew->mask)); zlog_debug (" Forward addr: %s", inet_ntoa (extnew->e[0].fwd_addr)); } if ( (new = ospf_lsa_install (ospf, NULL, new)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_lsa_translated_nssa_originate(): " "Could not install LSA " "id %s", inet_ntoa (type7->data->id)); return NULL; } ospf->lsa_originate_count++; ospf_flood_through_as (ospf, NULL, new); return new; } /* Refresh Translated from NSSA AS-external-LSA. */ struct ospf_lsa * ospf_translated_nssa_refresh (struct ospf *ospf, struct ospf_lsa *type7, struct ospf_lsa *type5) { struct ospf_lsa *new = NULL; /* Sanity checks. */ assert (type7 || type5); if (!(type7 || type5)) return NULL; if (type7) assert (type7->data); if (type5) assert (type5->data); assert (ospf->anyNSSA); /* get required data according to what has been given */ if (type7 && type5 == NULL) { /* find the translated Type-5 for this Type-7 */ struct as_external_lsa *ext = (struct as_external_lsa *)(type7->data); struct prefix_ipv4 p = { .prefix = type7->data->id, .prefixlen = ip_masklen (ext->mask), .family = AF_INET, }; type5 = ospf_external_info_find_lsa (ospf, &p); } else if (type5 && type7 == NULL) { /* find the type-7 from which supplied type-5 was translated, * ie find first type-7 with same LSA Id. */ struct listnode *ln, *lnn; struct route_node *rn; struct ospf_lsa *lsa; struct ospf_area *area; for (ALL_LIST_ELEMENTS (ospf->areas, ln, lnn, area)) { if (area->external_routing != OSPF_AREA_NSSA && !type7) continue; LSDB_LOOP (NSSA_LSDB(area), rn, lsa) { if (lsa->data->id.s_addr == type5->data->id.s_addr) { type7 = lsa; break; } } } } /* do we have type7? */ if (!type7) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): no Type-7 found for " "Type-5 LSA Id %s", inet_ntoa (type5->data->id)); return NULL; } /* do we have valid translated type5? */ if (type5 == NULL || !CHECK_FLAG (type5->flags, OSPF_LSA_LOCAL_XLT) ) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): No translated Type-5 " "found for Type-7 with Id %s", inet_ntoa (type7->data->id)); return NULL; } /* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_as (ospf, type5); /* create new translated LSA */ if ( (new = ospf_lsa_translated_nssa_new (ospf, type7)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): Could not translate " "Type-7 for %s to Type-5", inet_ntoa (type7->data->id)); return NULL; } if ( !(new = ospf_lsa_install (ospf, NULL, new)) ) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): Could not install " "translated LSA, Id %s", inet_ntoa (type7->data->id)); return NULL; } /* Flood LSA through area. */ ospf_flood_through_as (ospf, NULL, new); return new; } 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_debug ("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); /* If there is any attached NSSA, do special handling */ if (ospf->anyNSSA && /* stay away from translated LSAs! */ !(CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT))) ospf_install_flood_nssa (ospf, new, ei); /* Install/Flood Type-7 to all NSSAs */ /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate AS-external-LSA %p", new->data->type, inet_ntoa (new->data->id), (void *)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; } static 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) { struct prefix_ipv4 p; struct in_addr nexthop; struct external_info *ei; struct ospf *ospf; ospf = THREAD_ARG (thread); p.family = AF_INET; p.prefix.s_addr = 0; p.prefixlen = 0; if (ospf->default_originate == 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, 0); } if ((ei = ospf_default_external_info (ospf))) ospf_external_lsa_originate (ospf, ei); return 0; } /* Flush any NSSA LSAs for given prefix */ void ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p) { struct listnode *node, *nnode; struct ospf_lsa *lsa; struct ospf_area *area; for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { if (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_debug ("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); } } } } /* 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, ifindex_t ifindex /*, struct in_addr nexthop */) { struct ospf_lsa *lsa; if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("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_debug ("LSA: There is no such AS-external-LSA %s/%d in LSDB", inet_ntoa (p->prefix), p->prefixlen); return; } /* If LSA is selforiginated, not a translated LSA, and there is * NSSA area, flush Type-7 LSA's at first. */ if (IS_LSA_SELF(lsa) && (ospf->anyNSSA) && !(CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))) ospf_nssa_lsa_flush (ospf, p); /* Sweep LSA from Link State Retransmit List. */ ospf_ls_retransmit_delete_nbr_as (ospf, lsa); /* There must be no self-originated LSA in rtrs_external. */ #if 0 /* Remove External route from Zebra. */ ospf_zebra_delete ((struct prefix_ipv4 *) p, &nexthop); #endif 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_debug ("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_debug ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", (void *)lsa); ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); ospf_refresher_unregister_lsa (ospf, 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. */ struct ospf_lsa * 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)) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Could not be refreshed, " "redist check fail", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_external_lsa_flush (ospf, ei->type, &ei->p, ei->ifindex /*, ei->nexthop */); return NULL; } if (!changed && !force) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Not refreshed, not changed/forced", lsa->data->type, inet_ntoa (lsa->data->id)); return NULL; } /* 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_debug ("LSA[Type%d:%s]: Could not be refreshed", lsa->data->type, inet_ntoa (lsa->data->id)); return NULL; } new->data->ls_seqnum = lsa_seqnum_increment (lsa); ospf_lsa_install (ospf, NULL, new); /* As type-5. */ /* Flood LSA through AS. */ ospf_flood_through_as (ospf, NULL, new); /* If any attached NSSA, install as Type-7, flood to all NSSA Areas */ if (ospf->anyNSSA && !(CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT))) ospf_install_flood_nssa (ospf, new, ei); /* Install/Flood per new rules */ /* Register self-originated LSA to refresh queue. * Translated LSAs should not be registered, but refreshed upon * refresh of the Type-7 */ if ( !CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT) ) ospf_refresher_register_lsa (ospf, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: AS-external-LSA refresh", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } return new; } /* LSA installation functions. */ /* Install router-LSA to an area. */ static 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 (IS_LSA_SELF (new)) { /* Only install LSA if it is originated/refreshed by us. * If LSA was received by flooding, the RECEIVED flag is set so do * not link the LSA */ if (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED)) return new; /* ignore stale LSA */ /* Set self-originated router-LSA. */ ospf_lsa_unlock (&area->router_lsa_self); area->router_lsa_self = ospf_lsa_lock (new); ospf_refresher_register_lsa (ospf, new); } if (rt_recalc) ospf_spf_calculate_schedule (ospf, SPF_FLAG_ROUTER_LSA_INSTALL); 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. */ static 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 (IS_LSA_SELF (new)) { /* 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 (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED)) return new; /* ignore stale LSA */ ospf_lsa_unlock (&oi->network_lsa_self); oi->network_lsa_self = ospf_lsa_lock (new); ospf_refresher_register_lsa (ospf, new); } if (rt_recalc) ospf_spf_calculate_schedule (ospf, SPF_FLAG_NETWORK_LSA_INSTALL); return new; } /* Install summary-LSA to an area. */ static 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. */ #if 0 /* This doesn't exist yet... */ ospf_summary_incremental_update(new); */ #else /* #if 0 */ ospf_spf_calculate_schedule (ospf, SPF_FLAG_SUMMARY_LSA_INSTALL); #endif /* #if 0 */ } if (IS_LSA_SELF (new)) ospf_refresher_register_lsa (ospf, new); return new; } /* Install ASBR-summary-LSA to an area. */ static 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. */ #if 0 /* These don't exist yet... */ ospf_summary_incremental_update(new); /* Isn't this done by the above call? - RFC 2328 Section 16.5 implies it should be */ /* ospf_ase_calculate_schedule(); */ #else /* #if 0 */ ospf_spf_calculate_schedule (ospf, SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL); #endif /* #if 0 */ } /* register LSA to refresh-list. */ if (IS_LSA_SELF (new)) ospf_refresher_register_lsa (ospf, new); return new; } /* Install AS-external-LSA. */ static 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); } if (new->data->type == OSPF_AS_NSSA_LSA) { /* 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)) return new; else { /* Try refresh type-5 translated LSA for this LSA, if one exists. * New translations will be taken care of by the abr_task. */ ospf_translated_nssa_refresh (ospf, new, NULL); ospf_schedule_abr_task(ospf); } } /* Register self-originated LSA to refresh queue. * Leave Translated LSAs alone if NSSA is enabled */ if (IS_LSA_SELF (new) && !CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT ) ) 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; if (!lsdb) { zlog_warn ("%s: Called with NULL lsdb!", __func__); if (!lsa) zlog_warn ("%s: and NULL LSA!", __func__); else zlog_warn ("LSA[Type%d:%s]: not associated with LSDB!", lsa->data->type, inet_ntoa (lsa->data->id)); return; } 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: ospf_ase_unregister_external_lsa (old, ospf); ospf_ls_retransmit_delete_nbr_as (ospf, old); break; case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (ospf, old); break; case OSPF_AS_NSSA_LSA: ospf_ls_retransmit_delete_nbr_area (old->area, old); ospf_ase_unregister_external_lsa (old, ospf); break; 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) { /* kevinm */ case OSPF_AS_NSSA_LSA: if (lsa->area) lsdb = lsa->area->lsdb; else lsdb = ospf->lsdb; break; case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_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; /* Sequence number check (Section 14.1 of rfc 2328) "Premature aging is used when it is time for a self-originated LSA's sequence number field to wrap. At this point, the current LSA instance (having LS sequence number MaxSequenceNumber) must be prematurely aged and flushed from the routing domain before a new instance with sequence number equal to InitialSequenceNumber can be originated. " */ if (ntohl(lsa->data->ls_seqnum) - 1 == OSPF_MAX_SEQUENCE_NUMBER) { if (ospf_lsa_is_self_originated(ospf, lsa)) { lsa->data->ls_seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER); if (!IS_LSA_MAXAGE(lsa)) lsa->flags |= OSPF_LSA_PREMATURE_AGE; lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) { zlog_debug ("ospf_lsa_install() Premature Aging " "lsa 0x%p, seqnum 0x%x", (void *)lsa, ntohl(lsa->data->ls_seqnum)); ospf_lsa_header_dump (lsa->data); } } else { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("ospf_lsa_install() got an lsa with seq 0x80000000 " "that was not self originated. Ignoring\n"); ospf_lsa_header_dump (lsa->data); } return old; } } /* discard old LSA from LSDB */ if (old != NULL) ospf_discard_from_db (ospf, lsdb, lsa); /* Calculate Checksum if self-originated?. */ if (IS_LSA_SELF (lsa)) ospf_lsa_checksum (lsa->data); /* Insert LSA to LSDB. */ ospf_lsdb_add (lsdb, lsa); lsa->lsdb = lsdb; /* 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; 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; case OSPF_AS_NSSA_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); default: /* type-6,8,9....nothing special */ 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: case OSPF_OPAQUE_AS_LSA: case OSPF_AS_NSSA_LSA: zlog_debug ("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_debug ("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, or lsa is being prematurely aged (it's getting flushed out of the area), set LSA on MaxAge LSA list. */ if (IS_LSA_MAXAGE (new)) { if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) zlog_debug ("LSA[Type%d:%s]: Install LSA 0x%p, MaxAge", new->data->type, inet_ntoa (new->data->id), (void *)lsa); ospf_lsa_maxage (ospf, lsa); } return new; } int ospf_check_nbr_status (struct ospf *ospf) { struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { 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; } static int ospf_maxage_lsa_remover (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct ospf_lsa *lsa; struct route_node *rn; int reschedule = 0; ospf->t_maxage = NULL; if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[MaxAge]: remover Start"); reschedule = !ospf_check_nbr_status (ospf); if (!reschedule) for (rn = route_top(ospf->maxage_lsa); rn; rn = route_next(rn)) { if ((lsa = rn->info) == NULL) { continue; } /* There is at least one neighbor from which we still await an ack * for that LSA, so we are not allowed to remove it from our lsdb yet * as per RFC 2328 section 14 para 4 a) */ if (lsa->retransmit_counter > 0) { reschedule = 1; continue; } /* TODO: maybe convert this function to a work-queue */ if (thread_should_yield (thread)) { OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 0); route_unlock_node(rn); /* route_top/route_next */ return 0; } /* Remove LSA from the LSDB */ if (IS_LSA_SELF (lsa)) if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: LSA 0x%lx is self-originated: ", lsa->data->type, inet_ntoa (lsa->data->id), (u_long)lsa); if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: MaxAge LSA removed from list", lsa->data->type, inet_ntoa (lsa->data->id)); if (CHECK_FLAG (lsa->flags, OSPF_LSA_PREMATURE_AGE)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("originating new lsa for lsa 0x%p\n", (void *)lsa); ospf_lsa_refresh (ospf, lsa); } /* Remove from lsdb. */ if (lsa->lsdb) { ospf_discard_from_db (ospf, lsa->lsdb, lsa); ospf_lsdb_delete (lsa->lsdb, lsa); } else zlog_warn ("%s: LSA[Type%d:%s]: No associated LSDB!", __func__, lsa->data->type, inet_ntoa (lsa->data->id)); } /* 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, ospf->maxage_delay); return 0; } void ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) { struct route_node *rn; struct prefix_ptr lsa_prefix; lsa_prefix.family = 0; lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; lsa_prefix.prefix = (uintptr_t) lsa; if ((rn = route_node_lookup(ospf->maxage_lsa, (struct prefix *)&lsa_prefix))) { if (rn->info == lsa) { UNSET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); ospf_lsa_unlock (&lsa); /* maxage_lsa */ rn->info = NULL; route_unlock_node (rn); /* unlock node because lsa is deleted */ } route_unlock_node (rn); /* route_node_lookup */ } } /* Add LSA onto the MaxAge list, and schedule for removal. * This does *not* lead to the LSA being flooded, that must be taken * care of elsewhere, see, e.g., ospf_lsa_flush* (which are callers of this * function). */ void ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) { struct prefix_ptr lsa_prefix; struct route_node *rn; /* When we saw a MaxAge LSA flooded to us, we put it on the list and schedule the MaxAge LSA remover. */ if (CHECK_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: %p already exists on MaxAge LSA list", lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa); return; } lsa_prefix.family = 0; lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; lsa_prefix.prefix = (uintptr_t) lsa; if ((rn = route_node_get (ospf->maxage_lsa, (struct prefix *)&lsa_prefix)) != NULL) { if (rn->info != NULL) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[%s]: found LSA (%p) in table for LSA %p %d", dump_lsa_key (lsa), rn->info, (void *)lsa, lsa_prefix.prefixlen); route_unlock_node (rn); } else { rn->info = ospf_lsa_lock(lsa); SET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); } } else { zlog_err("Unable to allocate memory for maxage lsa\n"); assert(0); } if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa)); OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, ospf->maxage_delay); } static int ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) { /* Stay away from any Local Translated Type-7 LSAs */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) return 0; 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_debug("LSA[%s]: is MaxAge", dump_lsa_key (lsa)); switch (lsa->data->type) { 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; case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: ospf_ase_incremental_update (ospf, lsa); break; default: ospf_spf_calculate_schedule (ospf, SPF_FLAG_MAXAGE); break; } ospf_lsa_maxage (ospf, lsa); } if (IS_LSA_MAXAGE (lsa) && !ospf_lsa_is_self_originated (ospf, lsa)) if (LS_AGE (lsa) > OSPF_LSA_MAXAGE + 30) printf ("Eek! Shouldn't happen!\n"); 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; struct ospf_area *area; struct listnode *node, *nnode; ospf->t_maxage_walker = NULL; for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { 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); 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); LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); } /* for AS-external-LSAs. */ if (ospf->lsdb) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, 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) { struct ospf *ospf = ospf_lookup(); assert(ospf); switch (type) { case OSPF_ROUTER_LSA: case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA: case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_LSA: return ospf_lsdb_lookup_by_id (ospf->lsdb, type, id, adv_router); 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); 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); case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* Currently not used. */ break; default: break; } return NULL; } struct ospf_lsa * ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah) { struct ospf_lsa *match; /* * 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. */ 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_debug ("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; if (CHECK_FLAG ((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED)) return 1; /* May be a stale LSA in the LSBD */ 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; } #ifdef ORIGINAL_CODING void ospf_lsa_flush_self_originated (struct ospf_neighbor *nbr, struct ospf_lsa *self, struct ospf_lsa *new) { u_int32_t seqnum; /* Adjust LS Sequence Number. */ seqnum = ntohl (new->data->ls_seqnum) + 1; self->data->ls_seqnum = htonl (seqnum); /* Recalculate LSA checksum. */ ospf_lsa_checksum (self->data); /* Reflooding LSA. */ /* 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 (nbr->oi->type == OSPF_IFTYPE_NBMA) { struct route_node *rn; struct ospf_neighbor *onbr; for (rn = route_top (nbr->oi->nbrs); rn; rn = route_next (rn)) if ((onbr = rn->info) != NULL) if (onbr != nbr->oi->nbr_self && onbr->status >= NSM_Exchange) ospf_ls_upd_send_lsa (onbr, self, OSPF_SEND_PACKET_DIRECT); } else ospf_ls_upd_send_lsa (nbr, self, OSPF_SEND_PACKET_INDIRECT); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Flush self-originated LSA", self->data->type, inet_ntoa (self->data->id)); } #else /* ORIGINAL_CODING */ 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_debug ("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) { /* Opaque wants to be notified of flushes */ case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_refresh (lsa); break; default: ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush (ospf, lsa); break; } return 0; } void ospf_flush_self_originated_lsas_now (struct ospf *ospf) { struct listnode *node, *nnode; struct listnode *node2, *nnode2; struct ospf_area *area; struct ospf_interface *oi; struct ospf_lsa *lsa; struct route_node *rn; int need_to_flush_ase = 0; for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { if ((lsa = area->router_lsa_self) != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush_area (lsa, area); ospf_lsa_unlock (&area->router_lsa_self); area->router_lsa_self = NULL; } for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi)) { if ((lsa = oi->network_lsa_self) != NULL && oi->state == ISM_DR && oi->full_nbrs > 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_refresher_unregister_lsa (ospf, oi->network_lsa_self); ospf_lsa_flush_area (oi->network_lsa_self, area); ospf_lsa_unlock (&oi->network_lsa_self); oi->network_lsa_self = NULL; } 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); 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); } if (need_to_flush_ase) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, 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; } #endif /* ORIGINAL_CODING */ /* 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) { struct listnode *node; struct ospf_interface *oi; /* This LSA is already checked. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED)) return IS_LSA_SELF (lsa); /* 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 (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { /* 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 IS_LSA_SELF (lsa); } } return IS_LSA_SELF (lsa); } /* 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_debug ("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_debug ("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_FLOOD_AREA 1 #define LSA_ACTION_FLUSH_AREA 2 struct lsa_action { u_char action; struct ospf_area *area; struct ospf_lsa *lsa; }; static int ospf_lsa_action (struct thread *t) { struct lsa_action *data; data = THREAD_ARG (t); if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) zlog_debug ("LSA[Action]: Performing scheduled LSA action: %d", data->action); switch (data->action) { case LSA_ACTION_FLOOD_AREA: ospf_flood_through_area (data->area, NULL, data->lsa); break; case LSA_ACTION_FLUSH_AREA: ospf_lsa_flush_area (data->lsa, data->area); break; } ospf_lsa_unlock (&data->lsa); /* Message */ 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 = XCALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); data->action = LSA_ACTION_FLOOD_AREA; data->area = area; data->lsa = ospf_lsa_lock (lsa); /* Message / Flood area */ 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 = XCALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); data->action = LSA_ACTION_FLUSH_AREA; data->area = area; data->lsa = ospf_lsa_lock (lsa); /* Message / Flush area */ thread_add_event (master, ospf_lsa_action, data, 0); } /* LSA Refreshment functions. */ struct ospf_lsa * ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) { struct external_info *ei; struct ospf_lsa *new = NULL; assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); assert (IS_LSA_SELF (lsa)); assert (lsa->lock > 0); switch (lsa->data->type) { /* Router and Network LSAs are processed differently. */ case OSPF_ROUTER_LSA: new = ospf_router_lsa_refresh (lsa); break; case OSPF_NETWORK_LSA: new = ospf_network_lsa_refresh (lsa); break; case OSPF_SUMMARY_LSA: new = ospf_summary_lsa_refresh (ospf, lsa); break; case OSPF_ASBR_SUMMARY_LSA: new = ospf_summary_asbr_lsa_refresh (ospf, lsa); break; case OSPF_AS_EXTERNAL_LSA: /* Translated from NSSA Type-5s are refreshed when * from refresh of Type-7 - do not refresh these directly. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) break; ei = ospf_external_info_check (lsa); if (ei) new = ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); else ospf_lsa_flush_as (ospf, lsa); break; case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_refresh (lsa); break; default: break; } return new; } void ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa) { u_int16_t index, current_index; assert (lsa->lock > 0); assert (IS_LSA_SELF (lsa)); 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 + (quagga_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_debug ("LSA[Refresh]: lsa %s with age %d added to index %d", inet_ntoa (lsa->data->id), 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_queue */ lsa->refresh_list = index; if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh:%s]: ospf_refresher_register_lsa(): " "setting refresh_list on lsa %p (slod %d)", inet_ntoa (lsa->data->id), (void *)lsa, index); } } void ospf_refresher_unregister_lsa (struct ospf *ospf, struct ospf_lsa *lsa) { assert (lsa->lock > 0); assert (IS_LSA_SELF (lsa)); if (lsa->refresh_list >= 0) { struct 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_queue */ lsa->refresh_list = -1; } } int ospf_lsa_refresh_walker (struct thread *t) { struct list *refresh_list; struct listnode *node, *nnode; struct ospf *ospf = THREAD_ARG (t); struct ospf_lsa *lsa; int i; struct list *lsa_to_refresh = list_new (); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh]:ospf_lsa_refresh_walker(): start"); i = ospf->lsa_refresh_queue.index; /* Note: if clock has jumped backwards, then time change could be negative, so we are careful to cast the expression to unsigned before taking modulus. */ ospf->lsa_refresh_queue.index = ((unsigned long)(ospf->lsa_refresh_queue.index + (quagga_time (NULL) - ospf->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY)) % OSPF_LSA_REFRESHER_SLOTS; if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("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_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): " "refresh index %d", i); refresh_list = ospf->lsa_refresh_queue.qs [i]; assert (i >= 0); ospf->lsa_refresh_queue.qs [i] = NULL; if (refresh_list) { for (ALL_LIST_ELEMENTS (refresh_list, node, nnode, lsa)) { if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh:%s]: ospf_lsa_refresh_walker(): " "refresh lsa %p (slot %d)", inet_ntoa (lsa->data->id), (void *)lsa, i); assert (lsa->lock > 0); list_delete_node (refresh_list, node); lsa->refresh_list = -1; listnode_add (lsa_to_refresh, lsa); } 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 = quagga_time (NULL); for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa)) { ospf_lsa_refresh (ospf, lsa); assert (lsa->lock > 0); ospf_lsa_unlock (&lsa); /* lsa_refresh_queue & temp for lsa_to_refresh*/ } list_delete (lsa_to_refresh); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): end"); return 0; } quagga-1.2.4/ospfd/ospf_lsa.h000066400000000000000000000271521325323223500160640ustar00rootroot00000000000000/* * 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 #include "stream.h" /* OSPF LSA Range definition. */ #define OSPF_MIN_LSA 1 /* begin range here */ #define OSPF_MAX_LSA 12 /* 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 20U #define OSPF_ROUTER_LSA_LINK_SIZE 12U #define OSPF_ROUTER_LSA_TOS_SIZE 4U #define OSPF_MAX_LSA_SIZE 1500U /* 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; u_int32_t 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 #define OSPF_LSA_LOCAL_XLT 0x20 #define OSPF_LSA_PREMATURE_AGE 0x40 #define OSPF_LSA_IN_MAXAGE 0x80 /* 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; /* Flags for the SPF calculation. */ int stat; #define LSA_SPF_NOT_EXPLORED -1 #define LSA_SPF_IN_SPFTREE -2 /* If stat >= 0, stat is LSA position in candidates heap. */ /* 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; /* For Type-9 Opaque-LSAs */ struct ospf_interface *oi; }; /* 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 /* The routers always translates Type-7 */ #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) #define IS_ROUTER_LSA_NT(x) ((x)->flags & ROUTER_LSA_NT) /* 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. */ #define OSPF_ROUTER_LSA_MIN_SIZE 4U /* w/0 link descriptors */ /* There is an edge case, when number of links in a Router-LSA may be 0 without breaking the specification. A router, which has no other links to backbone area besides one virtual link, will not put any VL descriptor blocks into the Router-LSA generated for area 0 until a full adjacency over the VL is reached (RFC2328 12.4.1.3). In this case the Router-LSA initially received by the other end of the VL will have 0 link descriptor blocks, but soon will be replaced with the next revision having 1 descriptor block. */ 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. */ #define OSPF_NETWORK_LSA_MIN_SIZE 8U /* w/1 router-ID */ struct network_lsa { struct lsa_header header; struct in_addr mask; struct in_addr routers[1]; }; /* OSPF Summary-LSAs structure. */ #define OSPF_SUMMARY_LSA_MIN_SIZE 8U /* w/1 TOS metric block */ struct summary_lsa { struct lsa_header header; struct in_addr mask; u_char tos; u_char metric[3]; }; /* OSPF AS-external-LSAs structure. */ #define OSPF_AS_EXTERNAL_LSA_MIN_SIZE 16U /* w/1 TOS forwarding block */ 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]; }; #include "ospfd/ospf_opaque.h" /* 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) /* Prototypes. */ /* XXX: Eek, time functions, similar are in lib/thread.c */ extern struct timeval tv_adjust (struct timeval); extern int tv_ceil (struct timeval); extern int tv_floor (struct timeval); extern struct timeval int2tv (int); extern struct timeval msec2tv (int); extern struct timeval tv_add (struct timeval, struct timeval); extern struct timeval tv_sub (struct timeval, struct timeval); extern int tv_cmp (struct timeval, struct timeval); extern int get_age (struct ospf_lsa *); extern u_int16_t ospf_lsa_checksum (struct lsa_header *); extern int ospf_lsa_checksum_valid (struct lsa_header *); extern int ospf_lsa_refresh_delay (struct ospf_lsa *); extern const char *dump_lsa_key (struct ospf_lsa *); extern u_int32_t lsa_seqnum_increment (struct ospf_lsa *); extern void lsa_header_set (struct stream *, u_char, u_char, struct in_addr, struct in_addr); extern struct ospf_neighbor *ospf_nbr_lookup_ptop (struct ospf_interface *); extern int ospf_check_nbr_status (struct ospf *); /* Prototype for LSA primitive. */ extern struct ospf_lsa *ospf_lsa_new (void); extern struct ospf_lsa *ospf_lsa_dup (struct ospf_lsa *); extern void ospf_lsa_free (struct ospf_lsa *); extern struct ospf_lsa *ospf_lsa_lock (struct ospf_lsa *); extern void ospf_lsa_unlock (struct ospf_lsa **); extern void ospf_lsa_discard (struct ospf_lsa *); extern struct lsa_header *ospf_lsa_data_new (size_t); extern struct lsa_header *ospf_lsa_data_dup (struct lsa_header *); extern void ospf_lsa_data_free (struct lsa_header *); /* Prototype for various LSAs */ extern int ospf_router_lsa_update (struct ospf *); extern int ospf_router_lsa_update_area (struct ospf_area *); extern void ospf_network_lsa_update (struct ospf_interface *); extern struct ospf_lsa *ospf_summary_lsa_originate (struct prefix_ipv4 *, u_int32_t, struct ospf_area *); extern struct ospf_lsa *ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *, u_int32_t, struct ospf_area *); extern struct ospf_lsa *ospf_lsa_install (struct ospf *, struct ospf_interface *, struct ospf_lsa *); extern void ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p); extern void ospf_external_lsa_flush (struct ospf *, u_char, struct prefix_ipv4 *, ifindex_t /* , struct in_addr nexthop */); extern struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *); extern struct ospf_lsa *ospf_external_lsa_originate (struct ospf *, struct external_info *); extern int ospf_external_lsa_originate_timer (struct thread *); extern int ospf_default_originate_timer (struct thread *); extern struct ospf_lsa *ospf_lsa_lookup (struct ospf_area *, u_int32_t, struct in_addr, struct in_addr); extern struct ospf_lsa *ospf_lsa_lookup_by_id (struct ospf_area *, u_int32_t, struct in_addr); extern struct ospf_lsa *ospf_lsa_lookup_by_header (struct ospf_area *, struct lsa_header *); extern int ospf_lsa_more_recent (struct ospf_lsa *, struct ospf_lsa *); extern int ospf_lsa_different (struct ospf_lsa *, struct ospf_lsa *); extern void ospf_flush_self_originated_lsas_now (struct ospf *); extern int ospf_lsa_is_self_originated (struct ospf *, struct ospf_lsa *); extern struct ospf_lsa *ospf_lsa_lookup_by_prefix (struct ospf_lsdb *, u_char, struct prefix_ipv4 *, struct in_addr); extern void ospf_lsa_maxage (struct ospf *, struct ospf_lsa *); extern u_int32_t get_metric (u_char *); extern int ospf_lsa_maxage_walker (struct thread *); extern struct ospf_lsa *ospf_lsa_refresh (struct ospf *, struct ospf_lsa *); extern void ospf_external_lsa_refresh_default (struct ospf *); extern void ospf_external_lsa_refresh_type (struct ospf *, u_char, int); extern struct ospf_lsa *ospf_external_lsa_refresh (struct ospf *, struct ospf_lsa *, struct external_info *, int); extern struct in_addr ospf_lsa_unique_id (struct ospf *, struct ospf_lsdb *, u_char, struct prefix_ipv4 *); extern void ospf_schedule_lsa_flood_area (struct ospf_area *, struct ospf_lsa *); extern void ospf_schedule_lsa_flush_area (struct ospf_area *, struct ospf_lsa *); extern void ospf_refresher_register_lsa (struct ospf *, struct ospf_lsa *); extern void ospf_refresher_unregister_lsa (struct ospf *, struct ospf_lsa *); extern int ospf_lsa_refresh_walker (struct thread *); extern void ospf_lsa_maxage_delete (struct ospf *, struct ospf_lsa *); extern void ospf_discard_from_db (struct ospf *, struct ospf_lsdb *, struct ospf_lsa*); extern int is_prefix_default (struct prefix_ipv4 *); extern int metric_type (struct ospf *, u_char); extern int metric_value (struct ospf *, u_char); extern struct in_addr ospf_get_nssa_ip (struct ospf_area *); extern int ospf_translated_nssa_compare (struct ospf_lsa *, struct ospf_lsa *); extern struct ospf_lsa *ospf_translated_nssa_refresh (struct ospf *, struct ospf_lsa *, struct ospf_lsa *); extern struct ospf_lsa *ospf_translated_nssa_originate (struct ospf *, struct ospf_lsa *); #endif /* _ZEBRA_OSPF_LSA_H */ quagga-1.2.4/ospfd/ospf_lsdb.c000066400000000000000000000162231325323223500162210ustar00rootroot00000000000000/* * 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 ls_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa) { if (lp && lsa && lsa->data) { lp->family = 0; lp->prefixlen = 64; lp->id = lsa->data->id; lp->adv_router = lsa->data->adv_router; } } static void ospf_lsdb_delete_entry (struct ospf_lsdb *lsdb, struct route_node *rn) { struct ospf_lsa *lsa = rn->info; if (!lsa) return; assert (rn->table == lsdb->type[lsa->data->type].db); if (IS_LSA_SELF (lsa)) lsdb->type[lsa->data->type].count_self--; lsdb->type[lsa->data->type].count--; lsdb->type[lsa->data->type].checksum -= ntohs(lsa->data->checksum); 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); /* lsdb */ return; } /* 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; ls_prefix_set (&lp, lsa); rn = route_node_get (table, (struct prefix *)&lp); /* nothing to do? */ if (rn->info && rn->info == lsa) { route_unlock_node (rn); return; } /* purge old entry? */ if (rn->info) ospf_lsdb_delete_entry (lsdb, rn); if (IS_LSA_SELF (lsa)) lsdb->type[lsa->data->type].count_self++; lsdb->type[lsa->data->type].count++; lsdb->total++; #ifdef MONITOR_LSDB_CHANGE if (lsdb->new_lsa_hook != NULL) (* lsdb->new_lsa_hook)(lsa); #endif /* MONITOR_LSDB_CHANGE */ lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum); rn->info = ospf_lsa_lock (lsa); /* lsdb */ } void ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) { struct route_table *table; struct prefix_ls lp; struct route_node *rn; if (!lsdb) { zlog_warn ("%s: Called with NULL LSDB", __func__); if (lsa) zlog_warn ("LSA[Type%d:%s]: LSA %p, lsa->lsdb %p", lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa, (void *)lsa->lsdb); return; } if (!lsa) { zlog_warn ("%s: Called with NULL LSA", __func__); return; } assert (lsa->data->type < OSPF_MAX_LSA); table = lsdb->type[lsa->data->type].db; ls_prefix_set (&lp, lsa); if ((rn = route_node_lookup (table, (struct prefix *) &lp))) { if (rn->info == lsa) ospf_lsdb_delete_entry (lsdb, rn); route_unlock_node (rn); /* route_node_lookup */ } } void ospf_lsdb_delete_all (struct ospf_lsdb *lsdb) { struct route_table *table; struct route_node *rn; 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 (rn->info != NULL) ospf_lsdb_delete_entry (lsdb, rn); } } void ospf_lsdb_clean_stat (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) lsa->stat = LSA_SPF_NOT_EXPLORED; } } 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; ls_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 { if ((rn = route_node_lookup (table, (struct prefix *) &lp)) == NULL) return NULL; 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 int ospf_lsdb_checksum (struct ospf_lsdb *lsdb, int type) { return lsdb->type[type].checksum; } unsigned long ospf_lsdb_isempty (struct ospf_lsdb *lsdb) { return (lsdb->total == 0); } quagga-1.2.4/ospfd/ospf_lsdb.h000066400000000000000000000071761325323223500162350ustar00rootroot00000000000000/* * 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; unsigned int checksum; 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. */ extern struct ospf_lsdb *ospf_lsdb_new (void); extern void ospf_lsdb_init (struct ospf_lsdb *); extern void ospf_lsdb_free (struct ospf_lsdb *); extern void ospf_lsdb_cleanup (struct ospf_lsdb *); extern void ls_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa); extern void ospf_lsdb_add (struct ospf_lsdb *, struct ospf_lsa *); extern void ospf_lsdb_delete (struct ospf_lsdb *, struct ospf_lsa *); extern void ospf_lsdb_delete_all (struct ospf_lsdb *); /* Set all stats to -1 (LSA_SPF_NOT_EXPLORED). */ extern void ospf_lsdb_clean_stat (struct ospf_lsdb *lsdb); extern struct ospf_lsa *ospf_lsdb_lookup (struct ospf_lsdb *, struct ospf_lsa *); extern struct ospf_lsa *ospf_lsdb_lookup_by_id (struct ospf_lsdb *, u_char, struct in_addr, struct in_addr); extern struct ospf_lsa *ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *, u_char, struct in_addr, struct in_addr, int); extern unsigned long ospf_lsdb_count_all (struct ospf_lsdb *); extern unsigned long ospf_lsdb_count (struct ospf_lsdb *, int); extern unsigned long ospf_lsdb_count_self (struct ospf_lsdb *, int); extern unsigned int ospf_lsdb_checksum (struct ospf_lsdb *, int); extern unsigned long ospf_lsdb_isempty (struct ospf_lsdb *); #endif /* _ZEBRA_OSPF_LSDB_H */ quagga-1.2.4/ospfd/ospf_main.c000066400000000000000000000167151325323223500162270ustar00rootroot00000000000000/* * 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 #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 "privs.h" #include "sigevent.h" #include "zclient.h" #include "vrf.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" /* ospfd privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, }; struct zebra_privs_t ospfd_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #if defined(VTY_GROUP) .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), .cap_num_i = 0 }; /* Configuration filename and directory. */ 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'}, { "socket", required_argument, NULL, 'z'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "apiserver", no_argument, NULL, 'a'}, { "version", no_argument, NULL, 'v'}, { 0 } }; /* OSPFd program name */ /* Master of threads. */ struct thread_master *master; /* Process ID saved for use by init system */ const char *pid_file = PATH_OSPFD_PID; #ifdef SUPPORT_OSPF_API extern int ospf_apiserver_enable; #endif /* SUPPORT_OSPF_API */ /* Help information display. */ static void __attribute__ ((noreturn)) 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\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -a. --apiserver Enable OSPF apiserver\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog (NULL, LOG_INFO, "SIGHUP received"); } /* SIGINT / SIGTERM handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); ospf_terminate (); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } struct quagga_signal_t ospf_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* OSPFd main routine. */ int main (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = OSPF_VTY_PORT; int daemon_mode = 0; char *config_file = NULL; char *progname; int dryrun = 0; /* Set umask before anything for security */ umask (0027); #ifdef SUPPORT_OSPF_API /* OSPF apiserver is disabled by default. */ ospf_apiserver_enable = 0; #endif /* SUPPORT_OSPF_API */ /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); while (1) { int opt; opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:avC", 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 'z': zclient_serv_path_set (optarg); break; case 'P': /* Deal with atoi() returning 0 on failure, and ospfd not listening on ospfd port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = OSPF_VTY_PORT; break; case 'u': ospfd_privs.user = optarg; break; case 'g': ospfd_privs.group = optarg; break; #ifdef SUPPORT_OSPF_API case 'a': ospf_apiserver_enable = 1; break; #endif /* SUPPORT_OSPF_API */ case 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Invoked by a priviledged user? -- endo. */ if (geteuid () != 0) { errno = EPERM; perror (progname); exit (1); } zlog_default = openzlog (progname, ZLOG_OSPF, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* OSPF master init. */ ospf_master_init (); /* Initializations. */ master = om->master; /* Library inits. */ zprivs_init (&ospfd_privs); signal_init (master, array_size(ospf_signals), ospf_signals); cmd_init (1); debug_init (); vty_init (master); memory_init (); vrf_init (); access_list_init (); prefix_list_init (); /* OSPFd inits. */ ospf_if_init (); ospf_zebra_init (master); /* OSPF vty inits. */ ospf_vty_init (); ospf_vty_show_init (); ospf_vty_clear_init (); ospf_route_map_init (); #ifdef HAVE_SNMP ospf_snmp_init (); #endif /* HAVE_SNMP */ ospf_opaque_init (); /* Get configuration file. */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if (dryrun) return(0); /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("OSPFd daemon failed: %s", strerror(errno)); exit (1); } /* Process id file create. */ pid_output (pid_file); /* Create VTY socket */ vty_serv_sock (vty_addr, vty_port, OSPF_VTYSH_PATH); /* Print banner. */ zlog_notice ("OSPFd %s starting: vty@%d", QUAGGA_VERSION, vty_port); thread_main (master); /* Not reached. */ return (0); } quagga-1.2.4/ospfd/ospf_neighbor.c000066400000000000000000000306051325323223500170720ustar00rootroot00000000000000/* * 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" /* Fill in the the 'key' as appropriate to retrieve the entry for nbr * from the ospf_interface's nbrs table. Indexed by interface address * for all cases except Virtual-link and PointToPoint interfaces, where * neighbours are indexed by router-ID instead. */ static void ospf_nbr_key (struct ospf_interface *oi, struct ospf_neighbor *nbr, struct prefix *key) { key->family = AF_INET; key->prefixlen = IPV4_MAX_BITLEN; /* vlinks are indexed by router-id */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK || oi->type == OSPF_IFTYPE_POINTOPOINT) key->u.prefix4 = nbr->router_id; else key->u.prefix4 = nbr->src; return; } struct ospf_neighbor * ospf_nbr_new (struct ospf_interface *oi) { struct ospf_neighbor *nbr; /* Allcate new neighbor. */ nbr = XCALLOC (MTYPE_OSPF_NEIGHBOR, 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; /* get appropriate prefix 'key' */ ospf_nbr_key (oi, nbr, &p); rn = route_node_lookup (oi->nbrs, &p); if (rn) { /* If lookup for a NBR succeeds, the leaf route_node could * only exist because there is (or was) a nbr there. * If the nbr was deleted, the leaf route_node should have * lost its last refcount too, and be deleted. * Therefore a looked-up leaf route_node in nbrs table * should never have NULL info. */ assert (rn->info); 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); } else { /* * This neighbor was not found, but before we move on and * free the neighbor structre, make sure that it was not * indexed incorrectly and ended up in the "worng" place */ /* Reverse the lookup rules */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK || oi->type == OSPF_IFTYPE_POINTOPOINT) p.u.prefix4 = nbr->src; else p.u.prefix4 = nbr->router_id; rn = route_node_lookup (oi->nbrs, &p); if (rn){ /* We found the neighbor! * Now make sure it is not the exact same neighbor * structure that we are about to free */ if (nbr == rn->info){ /* Same neighbor, drop the reference to it */ rn->info = NULL; route_unlock_node (rn); } 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; } /* reset nbr_self */ void ospf_nbr_self_reset (struct ospf_interface *oi) { if (oi->nbr_self) ospf_nbr_delete (oi->nbr_self); oi->nbr_self = ospf_nbr_new (oi); ospf_nbr_add_self (oi); } /* Add self to nbr list. */ void ospf_nbr_add_self (struct ospf_interface *oi) { struct prefix p; struct route_node *rn; /* Initial state */ oi->nbr_self->address = *oi->address; 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->state = NSM_TwoWay; 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; case OSPF_AREA_NSSA: UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); break; } /* Add nbr_self to nbrs table */ ospf_nbr_key (oi, oi->nbr_self, &p); rn = route_node_get (oi->nbrs, &p); if (rn->info) { /* There is already pseudo neighbor. */ assert (oi->nbr_self == 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; } 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; } /* lookup nbr by address - use this only if you know you must * otherwise use the ospf_nbr_lookup() wrapper, which deals * with virtual link and PointToPoint neighbours */ 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; /* See comment in ospf_nbr_delete */ assert (rn->info); 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) { struct 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 (ALL_LIST_ELEMENTS_RO (top->oiflist, node, oi)) { if ((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_debug ("Renegotiate optional capabilities with neighbor(%s)", inet_ntoa (nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); } } return; } struct ospf_neighbor * ospf_nbr_lookup (struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh) { if (oi->type == OSPF_IFTYPE_VIRTUALLINK || oi->type == OSPF_IFTYPE_POINTOPOINT) return (ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id)); else return (ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src)); } static struct ospf_neighbor * ospf_nbr_add (struct ospf_interface *oi, struct ospf_header *ospfh, struct prefix *p) { struct ospf_neighbor *nbr; nbr = ospf_nbr_new (oi); nbr->state = NSM_Down; nbr->src = p->u.prefix4; memcpy (&nbr->address, p, sizeof (struct prefix)); nbr->nbr_nbma = NULL; if (oi->type == OSPF_IFTYPE_NBMA) { struct ospf_nbr_nbma *nbr_nbma; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (oi->nbr_nbma, node, nbr_nbma)) { if (IPV4_ADDR_SAME(&nbr_nbma->addr, &nbr->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_debug ("NSM[%s:%s]: start", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); return nbr; } struct ospf_neighbor * ospf_nbr_get (struct ospf_interface *oi, struct ospf_header *ospfh, struct ip *iph, struct prefix *p) { struct route_node *rn; struct prefix key; struct ospf_neighbor *nbr; key.family = AF_INET; key.prefixlen = IPV4_MAX_BITLEN; if (oi->type == OSPF_IFTYPE_VIRTUALLINK || oi->type == OSPF_IFTYPE_POINTOPOINT) key.u.prefix4 = ospfh->router_id;/* index vlink and ptp nbrs by router-id */ else 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; memcpy (&nbr->address, p, sizeof (struct prefix)); } } else { rn->info = nbr = ospf_nbr_add (oi, ospfh, p); } nbr->router_id = ospfh->router_id; return nbr; } quagga-1.2.4/ospfd/ospf_neighbor.h000066400000000000000000000077541325323223500171100ustar00rootroot00000000000000/* * 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 #include /* 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; /* NBMA configured neighbour */ struct ospf_nbr_nbma *nbr_nbma; /* Statistics */ struct timeval ts_last_progress; /* last advance of NSM */ struct timeval ts_last_regress; /* last regressive NSM change */ const char *last_regress_str; /* Event which last regressed NSM */ u_int32_t state_change; /* NSM state change counter */ }; /* 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. */ extern struct ospf_neighbor *ospf_nbr_new (struct ospf_interface *); extern void ospf_nbr_free (struct ospf_neighbor *); extern void ospf_nbr_delete (struct ospf_neighbor *); extern int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int); extern void ospf_nbr_self_reset (struct ospf_interface *); extern void ospf_nbr_add_self (struct ospf_interface *); extern int ospf_nbr_count (struct ospf_interface *, int); extern int ospf_nbr_count_opaque_capable (struct ospf_interface *); extern struct ospf_neighbor *ospf_nbr_get (struct ospf_interface *, struct ospf_header *, struct ip *, struct prefix *); extern struct ospf_neighbor *ospf_nbr_lookup (struct ospf_interface *, struct ip *, struct ospf_header *); extern struct ospf_neighbor *ospf_nbr_lookup_by_addr (struct route_table *, struct in_addr *); extern struct ospf_neighbor *ospf_nbr_lookup_by_routerid (struct route_table *, struct in_addr *); extern void ospf_renegotiate_optional_capabilities (struct ospf *top); #endif /* _ZEBRA_OSPF_NEIGHBOR_H */ quagga-1.2.4/ospfd/ospf_network.c000066400000000000000000000205331325323223500167650ustar00rootroot00000000000000/* * 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 "privs.h" extern struct zebra_privs_t ospfd_privs; #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" #include "ospfd/ospf_dump.h" /* Join to the OSPF ALL SPF ROUTERS multicast group. */ int ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, htonl (OSPF_ALLSPFROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit " "on # of multicast group memberships has been exceeded?", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); else zlog_debug ("interface %s [%u] join AllSPFRouters Multicast group.", inet_ntoa (p->u.prefix4), ifindex); return ret; } int ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, htonl (OSPF_ALLSPFROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " "ifindex %u, AllSPFRouters): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); else zlog_debug ("interface %s [%u] leave AllSPFRouters Multicast group.", inet_ntoa (p->u.prefix4), ifindex); return ret; } /* Join to the OSPF ALL Designated ROUTERS multicast group. */ int ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, htonl (OSPF_ALLDROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " "ifindex %u, AllDRouters): %s; perhaps a kernel limit " "on # of multicast group memberships has been exceeded?", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); else zlog_debug ("interface %s [%u] join AllDRouters Multicast group.", inet_ntoa (p->u.prefix4), ifindex); return ret; } int ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, htonl (OSPF_ALLDROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " "ifindex %u, AllDRouters): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); else zlog_debug ("interface %s [%u] leave AllDRouters Multicast group.", inet_ntoa (p->u.prefix4), ifindex); return ret; } int ospf_if_ipmulticast (struct ospf *top, struct prefix *p, ifindex_t 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) for fd %d: %s", top->fd, safe_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) for fd %d: %s", top->fd, safe_strerror (errno)); ret = setsockopt_ipv4_multicast_if (top->fd, ifindex); if (ret < 0) zlog_warn("can't setsockopt IP_MULTICAST_IF(fd %d, addr %s, " "ifindex %u): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); return ret; } int ospf_sock_init (void) { int ospf_sock; int ret, hincl = 1; if ( ospfd_privs.change (ZPRIVS_RAISE) ) zlog_err ("ospf_sock_init: could not raise privs, %s", safe_strerror (errno) ); ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); if (ospf_sock < 0) { int save_errno = errno; if ( ospfd_privs.change (ZPRIVS_LOWER) ) zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); zlog_err ("ospf_read_sock_init: socket: %s", safe_strerror (save_errno)); exit(1); } #ifdef IP_HDRINCL /* we will include IP header with packet */ ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl)); if (ret < 0) { int save_errno = errno; if ( ospfd_privs.change (ZPRIVS_LOWER) ) zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); zlog_warn ("Can't set IP_HDRINCL option for fd %d: %s", ospf_sock, safe_strerror(save_errno)); } #elif defined (IPTOS_PREC_INTERNETCONTROL) #warning "IP_HDRINCL not available on this system" #warning "using IPTOS_PREC_INTERNETCONTROL" ret = setsockopt_ipv4_tos(ospf_sock, IPTOS_PREC_INTERNETCONTROL); if (ret < 0) { int save_errno = errno; if ( ospfd_privs.change (ZPRIVS_LOWER) ) zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); zlog_warn ("can't set sockopt IP_TOS %d to socket %d: %s", tos, ospf_sock, safe_strerror(save_errno)); close (ospf_sock); /* Prevent sd leak. */ return ret; } #else /* !IPTOS_PREC_INTERNETCONTROL */ #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL" zlog_warn ("IP_HDRINCL option not available"); #endif /* IP_HDRINCL */ ret = setsockopt_ifindex (AF_INET, ospf_sock, 1); if (ret < 0) zlog_warn ("Can't set pktinfo option for fd %d", ospf_sock); if (ospfd_privs.change (ZPRIVS_LOWER)) { zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); } return ospf_sock; } void ospf_adjust_sndbuflen (struct ospf * ospf, unsigned int buflen) { int ret, newbuflen; /* Check if any work has to be done at all. */ if (ospf->maxsndbuflen >= buflen) return; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("%s: adjusting OSPF send buffer size to %d", __func__, buflen); if (ospfd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno)); /* Now we try to set SO_SNDBUF to what our caller has requested * (the MTU of a newly added interface). However, if the OS has * truncated the actual buffer size to somewhat less size, try * to detect it and update our records appropriately. The OS * may allocate more buffer space, than requested, this isn't * a error. */ ret = setsockopt_so_sendbuf (ospf->fd, buflen); newbuflen = getsockopt_so_sendbuf (ospf->fd); if (ret < 0 || newbuflen < 0 || newbuflen < (int) buflen) zlog_warn ("%s: tried to set SO_SNDBUF to %u, but got %d", __func__, buflen, newbuflen); if (newbuflen >= 0) ospf->maxsndbuflen = (unsigned int)newbuflen; else zlog_warn ("%s: failed to get SO_SNDBUF", __func__); if (ospfd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno)); } quagga-1.2.4/ospfd/ospf_network.h000066400000000000000000000027261325323223500167760ustar00rootroot00000000000000/* * 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. */ extern int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, ifindex_t); extern int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, ifindex_t); extern int ospf_if_add_alldrouters (struct ospf *, struct prefix *, ifindex_t); extern int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, ifindex_t); extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, ifindex_t); extern int ospf_sock_init (void); extern void ospf_adjust_sndbuflen (struct ospf *, unsigned int); #endif /* _ZEBRA_OSPF_NETWORK_H */ quagga-1.2.4/ospfd/ospf_nsm.c000066400000000000000000000715501325323223500160760ustar00rootroot00000000000000/* * 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" #include "ospfd/ospf_snmp.h" static void nsm_clear_adj (struct ospf_neighbor *); /* OSPF NSM Timer functions. */ static 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; } static int ospf_db_desc_timer (struct thread *thread) { struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); nbr->t_db_desc = NULL; if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) zlog (NULL, LOG_DEBUG, "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. * * Set/clear any timers whose condition is implicit to the neighbour * state. There may be other timers which are set/unset according to other * state. * * We rely on this function to properly clear timers in lower states, * particularly before deleting a neighbour. */ static void nsm_timer_set (struct ospf_neighbor *nbr) { switch (nbr->state) { case NSM_Deleted: case NSM_Down: OSPF_NSM_TIMER_OFF (nbr->t_inactivity); OSPF_NSM_TIMER_OFF (nbr->t_hello_reply); case NSM_Attempt: case NSM_Init: case NSM_TwoWay: OSPF_NSM_TIMER_OFF (nbr->t_db_desc); OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); OSPF_NSM_TIMER_OFF (nbr->t_ls_req); 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); OSPF_NSM_TIMER_OFF (nbr->t_ls_req); 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: case NSM_Full: default: OSPF_NSM_TIMER_OFF (nbr->t_db_desc); break; } } /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with * the given neighbour */ static int nsm_should_adj (struct ospf_neighbor *nbr) { struct ospf_interface *oi = nbr->oi; /* These network types must always form adjacencies. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT || oi->type == OSPF_IFTYPE_VIRTUALLINK /* Router itself is the DRouter or the BDRouter. */ || IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)) /* Neighboring Router is the DRouter or the BDRouter. */ || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi)) || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi))) return 1; return 0; } /* OSPF NSM functions. */ static int nsm_packet_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; } static int nsm_start (struct ospf_neighbor *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; } static int nsm_twoway_received (struct ospf_neighbor *nbr) { return (nsm_should_adj (nbr) ? NSM_ExStart : NSM_TwoWay); } 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); } static int ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */ if (nbr->oi && ospf_if_exists (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; } /* Stay away from any Local Translated Type-7 LSAs */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) return 0; 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. */ static 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); /* 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); } if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP)) { LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, 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); 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); /* Send Link State Request. */ if (nbr->t_ls_req == NULL) ospf_ls_req_send (nbr); return 0; } static int nsm_exchange_done (struct ospf_neighbor *nbr) { if (ospf_ls_request_isempty (nbr)) return NSM_Full; if (nbr->t_ls_req == NULL) ospf_ls_req_send (nbr); return NSM_Loading; } static int nsm_adj_ok (struct ospf_neighbor *nbr) { int next_state = nbr->state; int adj = nsm_should_adj (nbr); if (nbr->state == NSM_TwoWay && adj == 1) next_state = NSM_ExStart; else if (nbr->state >= NSM_ExStart && adj == 0) next_state = NSM_TwoWay; return next_state; } /* Clear adjacency related state for a neighbour, intended where nbr * transitions from > ExStart (i.e. a Full or forming adjacency) * to <= ExStart. */ static void nsm_clear_adj (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); if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) UNSET_FLAG (nbr->options, OSPF_OPTION_O); } static int nsm_kill_nbr (struct ospf_neighbor *nbr) { /* killing nbr_self is invalid */ if (nbr == nbr->oi->nbr_self) { assert (nbr != nbr->oi->nbr_self); return 0; } 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_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)", IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4)); } return 0; } /* Neighbor State Machine */ struct { int (*func) (struct ospf_neighbor *); int next_state; } NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = { { /* DependUpon: dummy state. */ { NULL, NSM_DependUpon }, /* NoEvent */ { NULL, NSM_DependUpon }, /* PacketReceived */ { NULL, NSM_DependUpon }, /* Start */ { NULL, NSM_DependUpon }, /* 2-WayReceived */ { NULL, NSM_DependUpon }, /* NegotiationDone */ { NULL, NSM_DependUpon }, /* ExchangeDone */ { NULL, NSM_DependUpon }, /* BadLSReq */ { NULL, NSM_DependUpon }, /* LoadingDone */ { NULL, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_DependUpon }, /* SeqNumberMismatch */ { NULL, NSM_DependUpon }, /* 1-WayReceived */ { NULL, NSM_DependUpon }, /* KillNbr */ { NULL, NSM_DependUpon }, /* InactivityTimer */ { NULL, NSM_DependUpon }, /* LLDown */ }, { /* Deleted: dummy state. */ { NULL, NSM_Deleted }, /* NoEvent */ { NULL, NSM_Deleted }, /* PacketReceived */ { NULL, NSM_Deleted }, /* Start */ { NULL, NSM_Deleted }, /* 2-WayReceived */ { NULL, NSM_Deleted }, /* NegotiationDone */ { NULL, NSM_Deleted }, /* ExchangeDone */ { NULL, NSM_Deleted }, /* BadLSReq */ { NULL, NSM_Deleted }, /* LoadingDone */ { NULL, NSM_Deleted }, /* AdjOK? */ { NULL, NSM_Deleted }, /* SeqNumberMismatch */ { NULL, NSM_Deleted }, /* 1-WayReceived */ { NULL, NSM_Deleted }, /* KillNbr */ { NULL, NSM_Deleted }, /* InactivityTimer */ { NULL, NSM_Deleted }, /* LLDown */ }, { /* Down: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Init }, /* PacketReceived */ { nsm_start, NSM_Attempt }, /* Start */ { NULL, NSM_Down }, /* 2-WayReceived */ { NULL, NSM_Down }, /* NegotiationDone */ { NULL, NSM_Down }, /* ExchangeDone */ { NULL, NSM_Down }, /* BadLSReq */ { NULL, NSM_Down }, /* LoadingDone */ { NULL, NSM_Down }, /* AdjOK? */ { NULL, NSM_Down }, /* SeqNumberMismatch */ { NULL, NSM_Down }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Attempt: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Init }, /* PacketReceived */ { NULL, NSM_Attempt }, /* Start */ { NULL, NSM_Attempt }, /* 2-WayReceived */ { NULL, NSM_Attempt }, /* NegotiationDone */ { NULL, NSM_Attempt }, /* ExchangeDone */ { NULL, NSM_Attempt }, /* BadLSReq */ { NULL, NSM_Attempt }, /* LoadingDone */ { NULL, NSM_Attempt }, /* AdjOK? */ { NULL, NSM_Attempt }, /* SeqNumberMismatch */ { NULL, NSM_Attempt }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Init: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Init }, /* PacketReceived */ { NULL, NSM_Init }, /* Start */ { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */ { NULL, NSM_Init }, /* NegotiationDone */ { NULL, NSM_Init }, /* ExchangeDone */ { NULL, NSM_Init }, /* BadLSReq */ { NULL, NSM_Init }, /* LoadingDone */ { NULL, NSM_Init }, /* AdjOK? */ { NULL, NSM_Init }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* 2-Way: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_TwoWay }, /* HelloReceived */ { NULL, NSM_TwoWay }, /* Start */ { NULL, NSM_TwoWay }, /* 2-WayReceived */ { NULL, NSM_TwoWay }, /* NegotiationDone */ { NULL, NSM_TwoWay }, /* ExchangeDone */ { NULL, NSM_TwoWay }, /* BadLSReq */ { NULL, NSM_TwoWay }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_TwoWay }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* ExStart: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_ExStart }, /* PacaketReceived */ { NULL, NSM_ExStart }, /* Start */ { NULL, NSM_ExStart }, /* 2-WayReceived */ { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */ { NULL, NSM_ExStart }, /* ExchangeDone */ { NULL, NSM_ExStart }, /* BadLSReq */ { NULL, NSM_ExStart }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_ExStart }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Exchange: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Exchange }, /* PacketReceived */ { NULL, NSM_Exchange }, /* Start */ { NULL, NSM_Exchange }, /* 2-WayReceived */ { NULL, NSM_Exchange }, /* NegotiationDone */ { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */ { NULL, NSM_ExStart }, /* BadLSReq */ { NULL, NSM_Exchange }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_ExStart }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Loading: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Loading }, /* PacketReceived */ { NULL, NSM_Loading }, /* Start */ { NULL, NSM_Loading }, /* 2-WayReceived */ { NULL, NSM_Loading }, /* NegotiationDone */ { NULL, NSM_Loading }, /* ExchangeDone */ { NULL, NSM_ExStart }, /* BadLSReq */ { NULL, NSM_Full }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_ExStart }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Full: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Full }, /* PacketReceived */ { NULL, NSM_Full }, /* Start */ { NULL, NSM_Full }, /* 2-WayReceived */ { NULL, NSM_Full }, /* NegotiationDone */ { NULL, NSM_Full }, /* ExchangeDone */ { NULL, NSM_ExStart }, /* BadLSReq */ { NULL, NSM_Full }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_ExStart }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, }; static const char *ospf_nsm_event_str[] = { "NoEvent", "PacketReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone", "BadLSReq", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "1-WayReceived", "KillNbr", "InactivityTimer", "LLDown", }; static void nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event) { /* Logging change of status. */ if (IS_DEBUG_OSPF (nsm, NSM_STATUS)) zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), LOOKUP (ospf_nsm_state_msg, next_state), ospf_nsm_event_str [event]); /* Optionally notify about adjacency changes */ if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) || (next_state == NSM_Full) || (next_state < nbr->state))) zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)", inet_ntoa (nbr->router_id), IF_NAME (nbr->oi), LOOKUP (ospf_nsm_state_msg, nbr->state), LOOKUP (ospf_nsm_state_msg, next_state), ospf_nsm_event_str [event]); /* Advance in NSM */ if (next_state > nbr->state) nbr->ts_last_progress = recent_relative_time (); else /* regression in NSM */ { nbr->ts_last_regress = recent_relative_time (); nbr->last_regress_str = ospf_nsm_event_str [event]; } } static 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; /* 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); /* Generate NeighborChange ISM event. * * In response to NeighborChange, DR election is rerun. The information * from the election process is required by the router-lsa construction. * * Therefore, trigger the event prior to refreshing the LSAs. */ 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; } /* 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); } /* XXX: Clearly some thing is wrong with refresh of external LSAs * this added to hack around defaults not refreshing after a timer * jump. */ ospf_external_lsa_refresh_default (oi->ospf); } 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); } zlog_info ("nsm_change_state(%s, %s -> %s): " "scheduling new router-LSA origination", inet_ntoa (nbr->router_id), LOOKUP(ospf_nsm_state_msg, old_state), LOOKUP(ospf_nsm_state_msg, state)); ospf_router_lsa_update_area (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_update_area (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; } else ospf_network_lsa_update (oi); } } ospf_opaque_nsm_change (nbr, old_state); /* State changes from > ExStart to <= ExStart should clear any Exchange * or Full/LSA Update related lists and state. * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK? */ if ((old_state > NSM_ExStart) && (state <= NSM_ExStart)) nsm_clear_adj (nbr); /* Start DD exchange protocol */ if (state == NSM_ExStart) { if (nbr->dd_seqnum == 0) nbr->dd_seqnum = quagga_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; /* Preserve old status? */ } /* Execute NSM event process. */ int ospf_nsm_event (struct thread *thread) { int event; int next_state; struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); event = THREAD_VAL (thread); if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), ospf_nsm_event_str [event]); next_state = NSM [nbr->state][event].next_state; /* Call function. */ if (NSM [nbr->state][event].func != NULL) { int func_state = (*(NSM [nbr->state][event].func))(nbr); if (NSM [nbr->state][event].next_state == NSM_DependUpon) next_state = func_state; else if (func_state) { /* There's a mismatch between the FSM tables and what an FSM * action/state-change function returned. State changes which * do not have conditional/DependUpon next-states should not * try set next_state. */ zlog_warn ("NSM[%s:%s]: %s (%s): " "Warning: action tried to change next_state to %s", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), ospf_nsm_event_str [event], LOOKUP (ospf_nsm_state_msg, func_state)); } } assert (next_state != NSM_DependUpon); /* If state is changed. */ if (next_state != nbr->state) { nsm_notice_state_change (nbr, next_state, event); #ifdef HAVE_SNMP int send_trap_virt = 0; int send_trap = 0; /* Terminal state or regression */ if ((next_state == NSM_Full) || (next_state == NSM_TwoWay) || (next_state < nbr->state)) { /* ospfVirtNbrStateChange */ if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK) send_trap_virt = 1; /* ospfNbrStateChange trap */ else /* To/From FULL, only managed by DR */ if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) || (nbr->oi->state == ISM_DR)) send_trap = 1; } #endif nsm_change_state (nbr, next_state); #ifdef HAVE_SNMP if (send_trap_virt) { ospfTrapVirtNbrStateChange(nbr); } else if (send_trap) { ospfTrapNbrStateChange(nbr); } #endif } /* Make sure timer is set. */ nsm_timer_set (nbr); /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor * is deleted. * * Rather than encode knowledge here of which events lead to NBR * delete, we take our cue from the NSM table, via the dummy * 'Deleted' neighbour state. */ if (nbr->state == NSM_Deleted) ospf_nbr_delete (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); } } quagga-1.2.4/ospfd/ospf_nsm.h000066400000000000000000000065651325323223500161070ustar00rootroot00000000000000/* * 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_Deleted 1 #define NSM_Down 2 #define NSM_Attempt 3 #define NSM_Init 4 #define NSM_TwoWay 5 #define NSM_ExStart 6 #define NSM_Exchange 7 #define NSM_Loading 8 #define NSM_Full 9 #define OSPF_NSM_STATE_MAX 10 /* OSPF Neighbor State Machine Event. */ #define NSM_NoEvent 0 #define NSM_PacketReceived 1 /* HelloReceived in the protocol */ #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. */ extern int ospf_nsm_event (struct thread *); extern void ospf_check_nbr_loading (struct ospf_neighbor *); extern int ospf_db_summary_isempty (struct ospf_neighbor *); extern int ospf_db_summary_count (struct ospf_neighbor *); extern void ospf_db_summary_clear (struct ospf_neighbor *); #endif /* _ZEBRA_OSPF_NSM_H */ quagga-1.2.4/ospfd/ospf_opaque.c000066400000000000000000001733511325323223500165750ustar00rootroot00000000000000/* * 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 MTYPE_TMP #define MTYPE_OPAQUE_INFO_PER_TYPE MTYPE_TMP #define MTYPE_OPAQUE_INFO_PER_ID MTYPE_TMP #include #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. *------------------------------------------------------------------------*/ #include "ospfd/ospf_te.h" #include "ospfd/ospf_ri.h" #ifdef SUPPORT_OSPF_API int ospf_apiserver_init (void); void ospf_apiserver_term (void); /* Init apiserver? It's disabled by default. */ int ospf_apiserver_enable; #endif /* SUPPORT_OSPF_API */ 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 (); if (ospf_mpls_te_init () != 0) exit (1); if (ospf_router_info_init () != 0) exit (1); #ifdef SUPPORT_OSPF_API if ((ospf_apiserver_enable) && (ospf_apiserver_init () != 0)) exit (1); #endif /* SUPPORT_OSPF_API */ return; } void ospf_opaque_term (void) { ospf_mpls_te_term (); ospf_router_info_term (); #ifdef SUPPORT_OSPF_API ospf_apiserver_term (); #endif /* SUPPORT_OSPF_API */ 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; case OPAQUE_TYPE_INTER_AS_LSA: name = "Inter-AS TE-v2 LSA"; break; case OPAQUE_TYPE_ROUTER_INFORMATION_LSA: name = "Router Information LSA"; break; default: if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) name = "Unassigned"; else { u_int32_t bigger_range = opaque_type; /* * Get around type-limits warning: comparison is always true due to limited range of data type */ if (OPAQUE_TYPE_RANGE_RESERVED (bigger_range)) 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); struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa); int (* new_lsa_hook)(struct ospf_lsa *lsa); int (* del_lsa_hook)(struct ospf_lsa *lsa); }; /* Handle LSA-9/10/11 altogether. */ static struct list *ospf_opaque_wildcard_funclist; static struct list *ospf_opaque_type9_funclist; static struct list *ospf_opaque_type10_funclist; static struct 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) { struct 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) { struct 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 struct list * ospf_get_opaque_funclist (u_char lsa_type) { struct 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; } /* XXX: such a huge argument list can /not/ be healthy... */ 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), struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa), int (* new_lsa_hook)(struct ospf_lsa *lsa), int (* del_lsa_hook)(struct ospf_lsa *lsa)) { struct 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 { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) 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", safe_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) { struct list *funclist; struct listnode *node, *nnode; struct ospf_opaque_functab *functab; if ((funclist = ospf_get_opaque_funclist (lsa_type)) != NULL) for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) { if (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); break; } } return; } static struct ospf_opaque_functab * ospf_opaque_functab_lookup (struct ospf_lsa *lsa) { struct list *funclist; struct 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 (ALL_LIST_ELEMENTS_RO (funclist, node, functab)) 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. */ struct 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", safe_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; struct listnode *node, *nnode; /* Control information per opaque-id may still exist. */ for (ALL_LIST_ELEMENTS (oipt->id_list, node, nnode, oipi)) { 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; struct list *listtop = NULL; struct listnode *node, *nnode; 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 (ALL_LIST_ELEMENTS (listtop, node, nnode, oipt)) 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", safe_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) { struct listnode *node, *nnode; struct opaque_info_per_id *oipi; u_int32_t key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); for (ALL_LIST_ELEMENTS (oipt->id_list, node, nnode, oipi)) 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_debug ("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_debug ("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 (struct list *funclist, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) 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 (struct list *funclist, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) 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 (struct list *funclist, struct ospf_interface *oi, int old_status) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->ism_change_hook != NULL) (* functab->ism_change_hook)(oi, old_status); return; } static void opaque_lsa_nsm_change_callback (struct list *funclist, struct ospf_neighbor *nbr, int old_status) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->nsm_change_hook != NULL) (* functab->nsm_change_hook)(nbr, old_status); return; } static void opaque_lsa_config_write_router_callback (struct list *funclist, struct vty *vty) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_router != NULL) (* functab->config_write_router)(vty); return; } static void opaque_lsa_config_write_if_callback (struct list *funclist, struct vty *vty, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_if != NULL) (* functab->config_write_if)(vty, ifp); return; } static void opaque_lsa_config_write_debug_callback (struct list *funclist, struct vty *vty) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_debug != NULL) (* functab->config_write_debug)(vty); return; } static int opaque_lsa_originate_callback (struct list *funclist, void *lsa_type_dependent) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) 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 (struct list *funclist, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; /* This function handles ALL types of LSAs, not only opaque ones. */ for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) 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 (struct list *funclist, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; /* This function handles ALL types of LSAs, not only opaque ones. */ for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) 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) { struct 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) { struct 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) { struct 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; struct 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_debug ("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) { struct 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) { struct 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) { struct 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_debug (" Opaque-Type %u (%s)", opaque_type, ospf_opaque_type_name (opaque_type)); zlog_debug (" Opaque-ID 0x%x", opaque_id); zlog_debug (" 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) { struct 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) { struct 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 (struct list *listtop, void *arg); void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) { struct ospf *top; struct ospf_area *area; struct listnode *node, *nnode; 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_debug ("ospf_opaque_lsa_originate_schedule: Not operational."); goto out; /* This is not an error. */ } 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_debug ("Schedule Type-9 Opaque-LSA origination in %d ms later.", delay); oi->t_opaque_lsa_self = thread_add_timer_msec (master, ospf_opaque_type9_lsa_originate, oi, delay); delay += top->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_debug ("Schedule Type-10 Opaque-LSA origination in %d ms later.", delay); area->t_opaque_lsa_self = thread_add_timer_msec (master, ospf_opaque_type10_lsa_originate, area, delay); delay += top->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_debug ("Schedule Type-11 Opaque-LSA origination in %d ms later.", delay); top->t_opaque_lsa_self = thread_add_timer_msec (master, ospf_opaque_type11_lsa_originate, top, delay); delay += top->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 (ALL_LIST_ELEMENTS (oi->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ 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 (ALL_LIST_ELEMENTS (area->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ 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 (ALL_LIST_ELEMENTS (top->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ 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_debug ("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_debug ("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_debug ("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 (struct list *listtop, void *arg) { struct listnode *node, *nnode; 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 (ALL_LIST_ELEMENTS (listtop, node, nnode, oipt)) { if (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_debug ("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; } struct ospf_lsa * ospf_opaque_lsa_refresh (struct ospf_lsa *lsa) { struct ospf *ospf; struct ospf_opaque_functab *functab; struct ospf_lsa *new = NULL; 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_debug ("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_flush (ospf, lsa); } else new = (* functab->lsa_refresher)(lsa); return new; } /*------------------------------------------------------------------------* * 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_msec (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_debug ("ospf_opaque_lsa_reoriginate_schedule: Not operational."); goto out; /* This is not an error. */ } /* 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_debug ("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 = top->min_ls_interval; /* XXX */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d" " ms 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_debug ("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_debug ("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; struct listnode *node, *nnode; 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 (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) { 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_debug ("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_debug ("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_debug ("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_debug ("Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).", oipt->opaque_type); rc = (* functab->lsa_originator)(top); out: return rc; } void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) { struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; struct ospf *top; int delay; 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_debug ("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: top = ospf_lookup (); if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL)) top = lsa0->area->ospf; ospf_ls_retransmit_delete_nbr_as (top, 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_debug ("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 * 1000); 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_debug ("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 opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; struct ospf *top; top = 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: if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL)) top = lsa0->area->ospf; ospf_ls_retransmit_delete_nbr_as (top, 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. */ 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_debug ("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_flush (top, lsa); out: return; } void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf *top; if ((top = oi_to_top (nbr->oi)) == NULL) return; /* * 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: ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AREA_LSA: ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AS_LSA: 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); return; } ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */ } /*------------------------------------------------------------------------* * Followings are util functions; probably be used by Opaque-LSAs only... *------------------------------------------------------------------------*/ 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; } quagga-1.2.4/ospfd/ospf_opaque.h000066400000000000000000000127701325323223500165770ustar00rootroot00000000000000/* * 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 #include "vty.h" #define IS_OPAQUE_LSA(type) \ ((type) == OSPF_OPAQUE_LINK_LSA || \ (type) == OSPF_OPAQUE_AREA_LSA || \ (type) == OSPF_OPAQUE_AS_LSA) /* * 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 #define OPAQUE_TYPE_L1VPN_LSA 5 #define OPAQUE_TYPE_ROUTER_INFORMATION_LSA 4 #define OPAQUE_TYPE_INTER_AS_LSA 6 #define OPAQUE_TYPE_MAX 6 /* 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) \ ( OPAQUE_TYPE_MAX <= (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. */ 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), struct ospf_lsa *(* 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 *, int rt_recalc); extern struct ospf_lsa *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_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); extern struct ospf *oi_to_top (struct ospf_interface *oi); #endif /* _ZEBRA_OSPF_OPAQUE_H */ quagga-1.2.4/ospfd/ospf_packet.c000066400000000000000000003434601325323223500165520ustar00rootroot00000000000000/* * 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 "sockopt.h" #include "checksum.h" #include "md5.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" /* Packet Type String. */ const struct message ospf_packet_type_str[] = { { OSPF_MSG_HELLO, "Hello" }, { OSPF_MSG_DB_DESC, "Database Description" }, { OSPF_MSG_LS_REQ, "Link State Request" }, { OSPF_MSG_LS_UPD, "Link State Update" }, { OSPF_MSG_LS_ACK, "Link State Acknowledgment" }, }; const size_t ospf_packet_type_str_max = sizeof (ospf_packet_type_str) / sizeof (ospf_packet_type_str[0]); /* Minimum (besides OSPF_HEADER_SIZE) lengths for OSPF packets of particular types, offset is the "type" field of a packet. */ static const u_int16_t ospf_packet_minlen[] = { 0, OSPF_HELLO_MIN_SIZE, OSPF_DB_DESC_MIN_SIZE, OSPF_LS_REQ_MIN_SIZE, OSPF_LS_UPD_MIN_SIZE, OSPF_LS_ACK_MIN_SIZE, }; /* Minimum (besides OSPF_LSA_HEADER_SIZE) lengths for LSAs of particular types, offset is the "LSA type" field. */ static const u_int16_t ospf_lsa_minlen[] = { 0, OSPF_ROUTER_LSA_MIN_SIZE, OSPF_NETWORK_LSA_MIN_SIZE, OSPF_SUMMARY_LSA_MIN_SIZE, OSPF_SUMMARY_LSA_MIN_SIZE, OSPF_AS_EXTERNAL_LSA_MIN_SIZE, 0, OSPF_AS_EXTERNAL_LSA_MIN_SIZE, 0, 0, 0, 0, }; /* for ospf_check_auth() */ static int ospf_check_sum (struct ospf_header *); /* OSPF authentication checking function */ static 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; } 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++; } /* Add new packet to head of fifo. */ static void ospf_fifo_push_head (struct ospf_fifo *fifo, struct ospf_packet *op) { op->next = fifo->head; if (fifo->tail == NULL) fifo->tail = op; fifo->head = 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) { if (!oi->obuf) { zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, " "destination %s) called with NULL obuf, ignoring " "(please report this bug)!\n", IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state), LOOKUP (ospf_packet_type_str, stream_getc_from(op->s, 1)), inet_ntoa (op->dst)); return; } /* Add packet to end of queue. */ ospf_fifo_push (oi->obuf, op); /* Debug of packet fifo*/ /* ospf_fifo_debug (oi->obuf); */ } static void ospf_packet_add_top (struct ospf_interface *oi, struct ospf_packet *op) { if (!oi->obuf) { zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, " "destination %s) called with NULL obuf, ignoring " "(please report this bug)!\n", IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state), LOOKUP (ospf_packet_type_str, stream_getc_from(op->s, 1)), inet_ntoa (op->dst)); return; } /* Add packet to head of queue. */ ospf_fifo_push_head (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 ospf_packet * ospf_packet_dup (struct ospf_packet *op) { struct ospf_packet *new; if (stream_get_endp(op->s) != op->length) /* XXX size_t */ zlog_warn ("ospf_packet_dup stream %lu ospf_packet %u size mismatch", (u_long)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); stream_copy (new->s, op->s); new->dst = op->dst; new->length = op->length; return new; } /* XXX inline */ static unsigned int ospf_packet_authspace (struct ospf_interface *oi) { int auth = 0; if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC) auth = OSPF_AUTH_MD5_SIZE; return auth; } static unsigned int ospf_packet_max (struct ospf_interface *oi) { int max; max = oi->ifp->mtu - ospf_packet_authspace(oi); max -= (OSPF_HEADER_SIZE + sizeof (struct ip)); return max; } static int ospf_check_md5_digest (struct ospf_interface *oi, struct ospf_header *ospfh) { MD5_CTX ctx; unsigned char digest[OSPF_AUTH_MD5_SIZE]; struct crypt_key *ck; struct ospf_neighbor *nbr; u_int16_t length = ntohs (ospfh->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. */ memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, ospfh, length); MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE); MD5Final(digest, &ctx); /* compare the two */ if (memcmp ((caddr_t)ospfh + length, 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. */ static int ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) { struct ospf_header *ospfh; unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0}; MD5_CTX ctx; void *ibuf; u_int32_t t; struct crypt_key *ck; const u_int8_t *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. Note that quagga_time /deliberately/ is not used here */ t = (time(NULL) & 0xFFFFFFFF); if (t > oi->crypt_seqnum) oi->crypt_seqnum = t; else 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 = (const u_int8_t *) digest; else { ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt))); auth_key = ck->auth_key; } /* Generate a digest for the entire packet + our secret key. */ memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, ibuf, ntohs (ospfh->length)); MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE); MD5Final(digest, &ctx); /* Append md5 digest to the end of the stream. */ stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE); /* 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) /* XXX size_t */ zlog_warn("ospf_make_md5_digest: length mismatch stream %lu ospf_packet %u", (u_long)stream_get_endp(op->s), op->length); return OSPF_AUTH_MD5_SIZE; } static 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) { struct list *update; struct ospf_lsdb *lsdb; int i; int retransmit_interval; 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 (recent_relative_time (), 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; } #ifdef WANT_OSPF_WRITE_FRAGMENT static void ospf_write_frags (int fd, struct ospf_packet *op, struct ip *iph, struct msghdr *msg, unsigned int maxdatasize, unsigned int mtu, int flags, u_char type) { #define OSPF_WRITE_FRAG_SHIFT 3 u_int16_t offset; struct iovec *iovp; int ret; assert ( op->length == stream_get_endp(op->s) ); assert (msg->msg_iovlen == 2); /* we can but try. * * SunOS, BSD and BSD derived kernels likely will clear ip_id, as * well as the IP_MF flag, making this all quite pointless. * * However, for a system on which IP_MF is left alone, and ip_id left * alone or else which sets same ip_id for each fragment this might * work, eg linux. * * XXX-TODO: It would be much nicer to have the kernel's use their * existing fragmentation support to do this for us. Bugs/RFEs need to * be raised against the various kernels. */ /* set More Frag */ iph->ip_off |= IP_MF; /* ip frag offset is expressed in units of 8byte words */ offset = maxdatasize >> OSPF_WRITE_FRAG_SHIFT; iovp = &msg->msg_iov[1]; while ( (stream_get_endp(op->s) - stream_get_getp (op->s)) > maxdatasize ) { /* data length of this frag is to next offset value */ iovp->iov_len = offset << OSPF_WRITE_FRAG_SHIFT; iph->ip_len = iovp->iov_len + sizeof (struct ip); assert (iph->ip_len <= mtu); sockopt_iphdrincl_swab_htosys (iph); ret = sendmsg (fd, msg, flags); sockopt_iphdrincl_swab_systoh (iph); if (ret < 0) zlog_warn ("*** ospf_write_frags: sendmsg failed to %s," " id %d, off %d, len %d, mtu %u failed with %s", inet_ntoa (iph->ip_dst), iph->ip_id, iph->ip_off, iph->ip_len, mtu, safe_strerror (errno)); if (IS_DEBUG_OSPF_PACKET (type - 1, SEND)) { zlog_debug ("ospf_write_frags: sent id %d, off %d, len %d to %s\n", iph->ip_id, iph->ip_off, iph->ip_len, inet_ntoa (iph->ip_dst)); if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) { zlog_debug ("-----------------IP Header Dump----------------------"); ospf_ip_header_dump (iph); zlog_debug ("-----------------------------------------------------"); } } iph->ip_off += offset; stream_forward_getp (op->s, iovp->iov_len); iovp->iov_base = STREAM_PNT (op->s); } /* setup for final fragment */ iovp->iov_len = stream_get_endp(op->s) - stream_get_getp (op->s); iph->ip_len = iovp->iov_len + sizeof (struct ip); iph->ip_off &= (~IP_MF); } #endif /* WANT_OSPF_WRITE_FRAGMENT */ static 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; struct listnode *node; #ifdef WANT_OSPF_WRITE_FRAGMENT static u_int16_t ipid = 0; u_int16_t maxdatasize; #endif /* WANT_OSPF_WRITE_FRAGMENT */ #define OSPF_WRITE_IPHL_SHIFT 2 ospf->t_write = NULL; node = listhead (ospf->oi_write_q); assert (node); oi = listgetdata (node); assert (oi); #ifdef WANT_OSPF_WRITE_FRAGMENT /* seed ipid static with low order bits of time */ if (ipid == 0) ipid = (time(NULL) & 0xffff); /* convenience - max OSPF data per packet, * and reliability - not more data, than our * socket can accept */ maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) - sizeof (struct ip); #endif /* WANT_OSPF_WRITE_FRAGMENT */ /* 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); /* Retrieve OSPF packet type. */ stream_set_getp (op->s, 1); type = stream_getc (op->s); /* reset get pointer */ stream_set_getp (op->s, 0); memset (&iph, 0, sizeof (struct ip)); memset (&sa_dst, 0, sizeof (sa_dst)); sa_dst.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sa_dst.sin_len = sizeof(sa_dst); #endif /* HAVE_STRUCT_SOCKADDR_IN_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) >> OSPF_WRITE_IPHL_SHIFT; /* it'd be very strange for header to not be 4byte-word aligned but.. */ if ( sizeof (struct ip) > (unsigned int)(iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) ) iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */ iph.ip_v = IPVERSION; iph.ip_tos = IPTOS_PREC_INTERNETCONTROL; iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length; #if defined(__DragonFly__) /* * DragonFly's raw socket expects ip_len/ip_off in network byte order. */ iph.ip_len = htons(iph.ip_len); #endif #ifdef WANT_OSPF_WRITE_FRAGMENT /* XXX-MT: not thread-safe at all.. * XXX: this presumes this is only programme sending OSPF packets * otherwise, no guarantee ipid will be unique */ iph.ip_id = ++ipid; #endif /* WANT_OSPF_WRITE_FRAGMENT */ 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 = (caddr_t) &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 << OSPF_WRITE_IPHL_SHIFT; iov[1].iov_base = STREAM_PNT (op->s); iov[1].iov_len = op->length; /* Sadly we can not rely on kernels to fragment packets because of either * IP_HDRINCL and/or multicast destination being set. */ #ifdef WANT_OSPF_WRITE_FRAGMENT if ( op->length > maxdatasize ) ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize, oi->ifp->mtu, flags, type); #endif /* WANT_OSPF_WRITE_FRAGMENT */ /* send final fragment (could be first) */ sockopt_iphdrincl_swab_htosys (&iph); ret = sendmsg (ospf->fd, &msg, flags); sockopt_iphdrincl_swab_systoh (&iph); if (ret < 0) zlog_warn ("*** sendmsg in ospf_write failed to %s, " "id %d, off %d, len %d, interface %s, mtu %u: %s", inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, oi->ifp->name, oi->ifp->mtu, safe_strerror (errno)); /* Show debug sending packet. */ if (IS_DEBUG_OSPF_PACKET (type - 1, SEND)) { if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) { zlog_debug ("-----------------------------------------------------"); ospf_ip_header_dump (&iph); stream_set_getp (op->s, 0); ospf_packet_dump (op->s); } zlog_debug ("%s sent to [%s] via [%s].", LOOKUP (ospf_packet_type_str, type), inet_ntoa (op->dst), IF_NAME (oi)); if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) zlog_debug ("-----------------------------------------------------"); } /* Now delete packet from queue. */ ospf_packet_delete (oi); /* Move this interface to the tail of write_q to serve everyone in a round robin fashion */ listnode_move_to_tail (ospf->oi_write_q, node); 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. */ static 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; int old_state; struct prefix p; /* 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)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) { zlog_debug ("ospf_header[%s/%s]: selforiginated, " "dropping.", LOOKUP (ospf_packet_type_str, ospfh->type), inet_ntoa (iph->ip_src)); } 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 on %s (configured prefix length is %d, but hello packet indicates %d).", inet_ntoa(ospfh->router_id), IF_NAME(oi), (int)oi->address->prefixlen, (int)p.prefixlen); return; } /* Compare Router Dead Interval. */ if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval)) { zlog_warn ("Packet %s [Hello:RECV]: RouterDeadInterval mismatch " "(expected %u, but received %u).", inet_ntoa(ospfh->router_id), OSPF_IF_PARAM(oi, v_wait), ntohl(hello->dead_interval)); return; } /* Compare Hello Interval - ignored if fast-hellos are set. */ if (OSPF_IF_PARAM (oi, fast_hello) == 0) { if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval)) { zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch " "(expected %u, but received %u).", inet_ntoa(ospfh->router_id), OSPF_IF_PARAM(oi, v_hello), ntohs(hello->hello_interval)); return; } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_MT)) { /* * 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 */ 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 */ } /* new for NSSA is to ensure that NP is on and E is off */ 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_debug ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id)); } else /* 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 %s [Hello:RECV]: my options: %x, his options %x", inet_ntoa(ospfh->router_id), OPTIONS (oi), hello->options); return; } /* get neighbour struct */ nbr = ospf_nbr_get (oi, ospfh, iph, &p); /* neighbour must be valid, ospf_nbr_get creates if none existed */ assert (nbr); old_state = nbr->state; /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); /* 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_SCHEDULE (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_SCHEDULE (nbr, NSM_TwoWayReceived); nbr->options |= hello->options; } else { OSPF_NSM_EVENT_SCHEDULE (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. */ static 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_getp (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_getp (s, OSPF_LSA_HEADER_SIZE); /* Unknown LS type. */ if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) { zlog_warn ("Packet [DD:RECV]: Unknown LS type %d.", lsah->type); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); return; } 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; } switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_LSA: /* Check for stub area. Reject if AS-External from stub but allow if from NSSA. */ if (oi->area->external_routing == OSPF_AREA_STUB) { 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); /* ospf_lsa_more_recent is fine with NULL pointers */ switch (ospf_lsa_more_recent (find, new)) { case -1: /* Neighbour has a more recent LSA, we must request it */ ospf_ls_request_add (nbr, new); case 0: /* If we have a copy of this LSA, it's either less recent * and we're requesting it from neighbour (the case above), or * it's as recent and we both have same copy (this case). * * In neither of these two cases is there any point in * describing our copy of the LSA to the neighbour in a * DB-Summary packet, if we're still intending to do so. * * See: draft-ogier-ospf-dbex-opt-00.txt, describing the * backward compatible optimisation to OSPF DB Exchange / * DB Description process implemented here. */ if (find) ospf_lsdb_delete (&nbr->db_sum, find); ospf_lsa_discard (new); break; default: /* We have the more recent copy, nothing specific to do: * - no need to request neighbours stale copy * - must leave DB summary list copy alone */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Packet [DD:RECV]: LSA received Type %d, " "ID %s is not recent.", lsah->type, inet_ntoa (lsah->id)); ospf_lsa_discard (new); } } /* Master */ if (IS_SET_DD_MS (nbr->dd_flags)) { nbr->dd_seqnum++; /* Both sides have no More, then we're done with Exchange */ if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags)) OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone); else ospf_db_desc_send (nbr); } /* Slave */ else { nbr->dd_seqnum = ntohl (dd->dd_seqnum); /* Send DD packet in reply. * * Must be done to acknowledge the Master's DD, regardless of * whether we have more LSAs ourselves to describe. * * This function will clear the 'More' bit, if after this DD * we have no more LSAs to describe to the master.. */ ospf_db_desc_send (nbr); /* Slave can raise ExchangeDone now, if master is also done */ if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags)) OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone); } /* Save received neighbor values from DD. */ ospf_db_desc_save_current (nbr, dd); } static 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. */ static 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 (oi, iph, ospfh); if (nbr == NULL) { zlog_warn ("Packet[DD]: Unknown Neighbor %s", inet_ntoa (ospfh->router_id)); return; } /* Check MTU. */ if ((OSPF_IF_PARAM (oi, mtu_ignore) == 0) && (ntohs (dd->mtu) > oi->ifp->mtu)) { zlog_warn ("Packet[DD]: Neighbor %s MTU %u is larger than [%s]'s MTU %u", inet_ntoa (nbr->router_id), ntohs (dd->mtu), IF_NAME (oi), oi->ifp->mtu); return; } /* * XXX HACK by Hasso Tepper. Setting N/P bit in NSSA area DD packets is not * required. In fact at least JunOS sends DD packets with P bit clear. * Until proper solution is developped, this hack should help. * * Update: According to the RFCs, N bit is specified /only/ for Hello * options, unfortunately its use in DD options is not specified. Hence some * implementations follow E-bit semantics and set it in DD options, and some * treat it as unspecified and hence follow the directive "default for * options is clear", ie unset. * * Reset the flag, as ospfd follows E-bit semantics. */ if ( (oi->area->external_routing == OSPF_AREA_NSSA) && (CHECK_FLAG (nbr->options, OSPF_OPTION_NP)) && (!CHECK_FLAG (dd->options, OSPF_OPTION_NP)) ) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Packet[DD]: Neighbour %s: Has NSSA capability, sends with N bit clear in DD options", inet_ntoa (nbr->router_id) ); SET_FLAG (dd->options, OSPF_OPTION_NP); } #ifdef REJECT_IF_TBIT_ON if (CHECK_FLAG (dd->options, OSPF_OPTION_MT)) { /* * 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 */ 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); } /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); /* Process DD packet by neighbor status. */ switch (nbr->state) { case NSM_Down: case NSM_Attempt: case NSM_TwoWay: zlog_warn ("Packet[DD]: Neighbor %s state is %s, packet discarded.", inet_ntoa(nbr->router_id), 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_info ("Packet[DD]: Neighbor %s Negotiation done (Slave).", inet_ntoa(nbr->router_id)); nbr->dd_seqnum = ntohl (dd->dd_seqnum); /* Reset I/MS */ UNSET_FLAG (nbr->dd_flags, (OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I)); } else { /* We're Master, ignore the initial DBD from Slave */ zlog_info ("Packet[DD]: Neighbor %s: Initial DBD from Slave, " "ignoring.", inet_ntoa(nbr->router_id)); 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_info ("Packet[DD]: Neighbor %s Negotiation done (Master).", inet_ntoa(nbr->router_id)); /* Reset I, leaving MS */ UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_I); } else { zlog_warn ("Packet[DD]: Neighbor %s Negotiation fails.", inet_ntoa(nbr->router_id)); break; } /* This is where the real Options are saved */ nbr->options = dd->options; if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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. */ } } 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_info ("Packet[DD] (Master): Neighbor %s packet duplicated.", inet_ntoa (nbr->router_id)); else /* Slave: cause to retransmit the last Database Description. */ { zlog_info ("Packet[DD] [Slave]: Neighbor %s packet duplicated.", inet_ntoa (nbr->router_id)); 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]: Neighbor %s MS-bit mismatch.", inet_ntoa(nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_info ("Packet[DD]: Neighbor %s I-bit set.", inet_ntoa(nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); break; } /* Check DD Options. */ if (dd->options != nbr->options) { #ifdef ORIGINAL_CODING /* Save the new options for debugging */ nbr->options = dd->options; #endif /* ORIGINAL_CODING */ zlog_warn ("Packet[DD]: Neighbor %s options mismatch.", inet_ntoa(nbr->router_id)); 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 ("Packet[DD]: Neighbor %s sequence number mismatch.", inet_ntoa(nbr->router_id)); 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_info ("Packet[DD]: Neighbor %s duplicated, " "packet discarded.", inet_ntoa(nbr->router_id)); break; } else { struct timeval t, now; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); 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]: Neighbor %s NSM illegal status %u.", inet_ntoa(nbr->router_id), nbr->state); break; } } #define OSPF_LSA_KEY_SIZE 12 /* type(4) + id(4) + ar(4) */ /* OSPF Link State Request Read -- RFC2328 Section 10.7. */ static 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; struct list *ls_upd; unsigned int length; /* Increment statistics. */ oi->ls_req_in++; nbr = ospf_nbr_lookup (oi, iph, ospfh); if (nbr == NULL) { zlog_warn ("Link State Request: Unknown Neighbor %s.", inet_ntoa (ospfh->router_id)); return; } /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); /* 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 received from %s: " "Neighbor state is %s, packet discarded.", inet_ntoa (ospfh->router_id), 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 immediately. */ 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 struct 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; struct 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_getp (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 (! ospf_lsa_checksum_valid (lsah)) { /* (bug #685) more details in a one-line message make it possible * to identify problem source on the one hand and to have a better * chance to compress repeated messages in syslog on the other */ zlog_warn ("Link State Update: LSA checksum error %x/%x, ID=%s from: nbr %s, router ID %s, adv router %s", sum, lsah->checksum, inet_ntoa (lsah->id), inet_ntoa (nbr->src), inet_ntoa (nbr->router_id), inet_ntoa (lsah->adv_router)); 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); 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_debug ("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; } /* 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: case OSPF_OPAQUE_AS_LSA: lsa->area = NULL; break; case OSPF_OPAQUE_LINK_LSA: lsa->oi = oi; /* Remember incoming interface for flooding control. */ /* Fallthrough */ default: lsa->area = oi->area; break; } lsa->data = ospf_lsa_data_new (length); memcpy (lsa->data, lsah, length); if (IS_DEBUG_OSPF_EVENT) zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update", lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa); listnode_add (lsas, lsa); } return lsas; } /* Cleanup Update list. */ static void ospf_upd_list_clean (struct list *lsas) { struct listnode *node, *nnode; struct ospf_lsa *lsa; for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa)) ospf_lsa_discard (lsa); list_delete (lsas); } /* OSPF Link State Update message read -- RFC2328 Section 13. */ static void ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh, struct stream *s, struct ospf_interface *oi, u_int16_t size) { struct ospf_neighbor *nbr; struct list *lsas; struct listnode *node, *nnode; 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 (oi, iph, ospfh); if (nbr == NULL) { zlog_warn ("Link State Update: Unknown Neighbor %s on int: %s", inet_ntoa (ospfh->router_id), IF_NAME (oi)); return; } /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); /* Check neighbor state. */ if (nbr->state < NSM_Exchange) { zlog_warn ("Link State Update: " "Neighbor[%s] state %s is less than Exchange", inet_ntoa (ospfh->router_id), LOOKUP(ospf_nsm_state_msg, nbr->state)); 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); #define DISCARD_LSA(L,N) {\ if (IS_DEBUG_OSPF_EVENT) \ zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p" \ " Type-%d", N, (void *)lsa, (int) lsa->data->type); \ ospf_lsa_discard (L); \ continue; } /* Process each LSA received in the one packet. * * Numbers in parentheses, e.g. (1), (2), etc., and the corresponding * text below are from the steps in RFC 2328, Section 13. */ for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa)) { struct ospf_lsa *ls_ret, *current; int ret = 1; if (IS_DEBUG_OSPF_NSSA) { char buf1[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; char buf3[INET_ADDRSTRLEN]; zlog_debug("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)); } listnode_delete (lsas, lsa); /* We don't need it in list anymore */ /* (1) Validate Checksum - Done above by ospf_ls_upd_list_lsa() */ /* (2) LSA Type - Done above by ospf_ls_upd_list_lsa() */ /* (3) 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) { if (IS_DEBUG_OSPF_NSSA) zlog_debug("Incoming External LSA Discarded: We are NSSA/STUB Area"); DISCARD_LSA (lsa, 1); } if (lsa->data->type == OSPF_AS_NSSA_LSA) if (nbr->oi->area->external_routing != OSPF_AREA_NSSA) { if (IS_DEBUG_OSPF_NSSA) zlog_debug("Incoming NSSA LSA Discarded: Not NSSA Area"); DISCARD_LSA (lsa,2); } /* VU229804: Router-LSA Adv-ID must be equal to LS-ID */ if (lsa->data->type == OSPF_ROUTER_LSA) if (!IPV4_ADDR_SAME(&lsa->data->id, &lsa->data->adv_router)) { char buf1[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; char buf3[INET_ADDRSTRLEN]; zlog_err("Incoming Router-LSA from %s with " "Adv-ID[%s] != LS-ID[%s]", 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)); zlog_err("OSPF domain compromised by attack or corruption. " "Verify correct operation of -ALL- OSPF routers."); DISCARD_LSA (lsa, 0); } /* Find the LSA in the current database. */ current = ospf_lsa_lookup_by_header (oi->area, lsa->data); /* (4) 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_check_nbr_status(oi->ospf)) { /* (4a) Response Link State Acknowledgment. */ ospf_ls_ack_send (nbr, lsa); /* (4b) Discard LSA. */ if (IS_DEBUG_OSPF (lsa, LSA)) { zlog_debug ("Link State Update[%s]: LS age is equal to MaxAge.", dump_lsa_key(lsa)); } DISCARD_LSA (lsa, 3); } 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. */ /* XXX: We should deal with this for *ALL* LSAs, not just opaque */ if (current == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[%s]: Previously originated Opaque-LSA," "not found in the LSDB.", dump_lsa_key (lsa)); SET_FLAG (lsa->flags, OSPF_LSA_SELF); ospf_opaque_self_originated_lsa_received (nbr, lsa); ospf_ls_ack_send (nbr, lsa); continue; } } /* It might be happen that received LSA is self-originated network LSA, but * router ID is changed. So, we should check if LSA is a network-LSA whose * Link State ID is one of the router's own IP interface addresses but whose * Advertising Router is not equal to the router's own Router ID * According to RFC 2328 12.4.2 and 13.4 this LSA should be flushed. */ if(lsa->data->type == OSPF_NETWORK_LSA) { struct listnode *oinode, *oinnode; struct ospf_interface *out_if; int Flag = 0; for (ALL_LIST_ELEMENTS (oi->ospf->oiflist, oinode, oinnode, out_if)) { if(out_if == NULL) break; if((IPV4_ADDR_SAME(&out_if->address->u.prefix4, &lsa->data->id)) && (!(IPV4_ADDR_SAME(&oi->ospf->router_id, &lsa->data->adv_router)))) { if(out_if->network_lsa_self) { ospf_lsa_flush_area(lsa,out_if->area); if(IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d", (void *)lsa, (int) lsa->data->type); ospf_lsa_discard (lsa); Flag = 1; } break; } } if(Flag) continue; } /* (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. (The sub steps from RFC 2328 section 13 step (5) will be performed in ospf_flood() ) */ 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[%s] instance exists on Link state request list", dump_lsa_key(lsa)); /* Clean list of LSAs. */ ospf_upd_list_clean (lsas); /* this lsa is not on lsas list already. */ ospf_lsa_discard (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; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); if (tv_cmp (tv_sub (now, current->tv_orig), msec2tv (ospf->min_ls_arrival)) >= 0) /* Trap NSSA type later.*/ ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT); DISCARD_LSA (lsa, 8); } } } #undef DISCARD_LSA assert (listcount (lsas) == 0); list_delete (lsas); } /* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */ static 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; /* increment statistics. */ oi->ls_ack_in++; nbr = ospf_nbr_lookup (oi, iph, ospfh); if (nbr == NULL) { zlog_warn ("Link State Acknowledgment: Unknown Neighbor %s.", inet_ntoa (ospfh->router_id)); return; } /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); if (nbr->state < NSM_Exchange) { zlog_warn ("Link State Acknowledgment: " "Neighbor[%s] state %s is less than Exchange", inet_ntoa (ospfh->router_id), LOOKUP(ospf_nsm_state_msg, nbr->state)); return; } 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_getp (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 && ospf_lsa_more_recent (lsr, lsa) == 0) ospf_ls_retransmit_delete (nbr, lsr); lsa->data = NULL; ospf_lsa_discard (lsa); } return; } static struct stream * ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) { int ret; struct ip *iph; u_int16_t ip_len; ifindex_t ifindex = 0; struct iovec iov; /* Header and data both require alignment. */ char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())]; struct msghdr msgh; memset (&msgh, 0, sizeof (struct msghdr)); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_control = (caddr_t) buff; msgh.msg_controllen = sizeof (buff); ret = stream_recvmsg (ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE+1); if (ret < 0) { zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno)); return NULL; } if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */ { zlog_warn("ospf_recv_packet: discarding runt packet of length %d " "(ip header size is %u)", ret, (u_int)sizeof(iph)); return NULL; } /* Note that there should not be alignment problems with this assignment because this is at the beginning of the stream data buffer. */ iph = (struct ip *) STREAM_DATA(ibuf); sockopt_iphdrincl_swab_systoh (iph); ip_len = iph->ip_len; #if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000) /* * 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 #if defined(__DragonFly__) /* * in DragonFly's raw socket, ip_len/ip_off are read * in network byte order. * As OpenBSD < 200311 adjust ip_len to strip IP header size! */ ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2); #endif ifindex = getsockopt_ifindex (AF_INET, &msgh); *ifp = if_lookup_by_index (ifindex); if (ret != ip_len) { zlog_warn ("ospf_recv_packet read length mismatch: ip_len is %d, " "but recvmsg returned %d", ip_len, ret); return NULL; } return ibuf; } static struct ospf_interface * ospf_associate_packet_vl (struct ospf *ospf, struct interface *ifp, struct ip *iph, struct ospf_header *ospfh) { struct ospf_interface *rcv_oi; struct ospf_vl_data *vl_data; struct ospf_area *vl_area; struct listnode *node; if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) || !OSPF_IS_AREA_BACKBONE (ospfh)) return NULL; /* look for local OSPF interface matching the destination * to determine Area ID. We presume therefore the destination address * is unique, or at least (for "unnumbered" links), not used in other * areas */ if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_dst)) == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) { 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_debug ("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_debug ("This VL is not up yet, sorry"); return NULL; } return vl_data->vl_oi; } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("couldn't find any VL to associate the packet with"); return NULL; } static 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. */ static 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; } /* Return 1, if the packet is properly authenticated and checksummed, 0 otherwise. In particular, check that AuType header field is valid and matches the locally configured AuType, and that D.5 requirements are met. */ static int ospf_check_auth (struct ospf_interface *oi, struct ospf_header *ospfh) { struct crypt_key *ck; u_int16_t iface_auth_type; u_int16_t pkt_auth_type = ntohs (ospfh->auth_type); switch (pkt_auth_type) { case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */ if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type (oi))) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Null", IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); return 0; } if (! ospf_check_sum (ospfh)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: Null auth OK, but checksum error, Router-ID %s", IF_NAME (oi), inet_ntoa (ospfh->router_id)); return 0; } return 1; case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */ if (OSPF_AUTH_SIMPLE != (iface_auth_type = ospf_auth_type (oi))) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Simple", IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); return 0; } if (memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: Simple auth failed", IF_NAME (oi)); return 0; } if (! ospf_check_sum (ospfh)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: Simple auth OK, checksum error, Router-ID %s", IF_NAME (oi), inet_ntoa (ospfh->router_id)); return 0; } return 1; case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */ if (OSPF_AUTH_CRYPTOGRAPHIC != (iface_auth_type = ospf_auth_type (oi))) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Cryptographic", IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); return 0; } if (ospfh->checksum) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: OSPF header checksum is not 0", IF_NAME (oi)); return 0; } /* only MD5 crypto method can pass ospf_packet_examin() */ if ( NULL == (ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) || ospfh->u.crypt.key_id != ck->key_id || /* Condition above uses the last key ID on the list, which is different from what ospf_crypt_key_lookup() does. A bug? */ ! ospf_check_md5_digest (oi, ospfh) ) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: MD5 auth failed", IF_NAME (oi)); return 0; } return 1; default: if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: invalid packet auth-type (%02x)", IF_NAME (oi), pkt_auth_type); return 0; } } static 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; } /* Verify, that given link/TOS records are properly sized/aligned and match Router-LSA "# links" and "# TOS" fields as specified in RFC2328 A.4.2. */ static unsigned ospf_router_lsa_links_examin ( struct router_lsa_link * link, u_int16_t linkbytes, const u_int16_t num_links ) { unsigned counted_links = 0, thislinklen; while (linkbytes) { thislinklen = OSPF_ROUTER_LSA_LINK_SIZE + 4 * link->m[0].tos_count; if (thislinklen > linkbytes) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: length error in link block #%u", __func__, counted_links); return MSG_NG; } link = (struct router_lsa_link *)((caddr_t) link + thislinklen); linkbytes -= thislinklen; counted_links++; } if (counted_links != num_links) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: %u link blocks declared, %u present", __func__, num_links, counted_links); return MSG_NG; } return MSG_OK; } /* Verify, that the given LSA is properly sized/aligned (including type-specific minimum length constraint). */ static unsigned ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char headeronly) { unsigned ret; struct router_lsa * rlsa; if ( lsah->type < OSPF_MAX_LSA && ospf_lsa_minlen[lsah->type] && lsalen < OSPF_LSA_HEADER_SIZE + ospf_lsa_minlen[lsah->type] ) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: undersized (%u B) %s", __func__, lsalen, LOOKUP (ospf_lsa_type_msg, lsah->type)); return MSG_NG; } switch (lsah->type) { case OSPF_ROUTER_LSA: /* RFC2328 A.4.2, LSA header + 4 bytes followed by N>=1 (12+)-byte link blocks */ if (headeronly) { ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE) % 4 ? MSG_NG : MSG_OK; break; } rlsa = (struct router_lsa *) lsah; ret = ospf_router_lsa_links_examin ( (struct router_lsa_link *) rlsa->link, lsalen - OSPF_LSA_HEADER_SIZE - 4, /* skip: basic header, "flags", 0, "# links" */ ntohs (rlsa->links) /* 16 bits */ ); break; case OSPF_AS_EXTERNAL_LSA: /* RFC2328 A.4.5, LSA header + 4 bytes followed by N>=1 12-bytes long blocks */ case OSPF_AS_NSSA_LSA: /* RFC3101 C, idem */ ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_AS_EXTERNAL_LSA_MIN_SIZE) % 12 ? MSG_NG : MSG_OK; break; /* Following LSA types are considered OK length-wise as soon as their minimum * length constraint is met and length of the whole LSA is a multiple of 4 * (basic LSA header size is already a multiple of 4). */ case OSPF_NETWORK_LSA: /* RFC2328 A.4.3, LSA header + 4 bytes followed by N>=1 router-IDs */ case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: /* RFC2328 A.4.4, LSA header + 4 bytes followed by N>=1 4-bytes TOS blocks */ case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* RFC5250 A.2, "some number of octets (of application-specific * data) padded to 32-bit alignment." This is considered equivalent * to 4-byte alignment of all other LSA types, see OSPF-ALIGNMENT.txt * file for the detailed analysis of this passage. */ ret = lsalen % 4 ? MSG_NG : MSG_OK; break; default: if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: unsupported LSA type 0x%02x", __func__, lsah->type); return MSG_NG; } if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: alignment error in %s", __func__, LOOKUP (ospf_lsa_type_msg, lsah->type)); return ret; } /* Verify if the provided input buffer is a valid sequence of LSAs. This includes verification of LSA blocks length/alignment and dispatching of deeper-level checks. */ static unsigned ospf_lsaseq_examin ( struct lsa_header *lsah, /* start of buffered data */ size_t length, const u_char headeronly, /* When declared_num_lsas is not 0, compare it to the real number of LSAs and treat the difference as an error. */ const u_int32_t declared_num_lsas ) { u_int32_t counted_lsas = 0; while (length) { u_int16_t lsalen; if (length < OSPF_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: undersized (%zu B) trailing (#%u) LSA header", __func__, length, counted_lsas); return MSG_NG; } /* save on ntohs() calls here and in the LSA validator */ lsalen = ntohs (lsah->length); if (lsalen < OSPF_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: malformed LSA header #%u, declared length is %u B", __func__, counted_lsas, lsalen); return MSG_NG; } if (headeronly) { /* less checks here and in ospf_lsa_examin() */ if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 1)) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: malformed header-only LSA #%u", __func__, counted_lsas); return MSG_NG; } lsah = (struct lsa_header *) ((caddr_t) lsah + OSPF_LSA_HEADER_SIZE); length -= OSPF_LSA_HEADER_SIZE; } else { /* make sure the input buffer is deep enough before further checks */ if (lsalen > length) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: anomaly in LSA #%u: declared length is %u B, buffered length is %zu B", __func__, counted_lsas, lsalen, length); return MSG_NG; } if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 0)) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: malformed LSA #%u", __func__, counted_lsas); return MSG_NG; } lsah = (struct lsa_header *) ((caddr_t) lsah + lsalen); length -= lsalen; } counted_lsas++; } if (declared_num_lsas && counted_lsas != declared_num_lsas) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: #LSAs declared (%u) does not match actual (%u)", __func__, declared_num_lsas, counted_lsas); return MSG_NG; } return MSG_OK; } /* Verify a complete OSPF packet for proper sizing/alignment. */ static unsigned ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) { u_int16_t bytesdeclared, bytesauth; unsigned ret; struct ospf_ls_update * lsupd; /* Length, 1st approximation. */ if (bytesonwire < OSPF_HEADER_SIZE) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire); return MSG_NG; } /* Now it is safe to access header fields. Performing length check, allow * for possible extra bytes of crypto auth/padding, which are not counted * in the OSPF header "length" field. */ if (oh->version != OSPF_VERSION) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version); return MSG_NG; } bytesdeclared = ntohs (oh->length); if (ntohs (oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) bytesauth = 0; else { if (oh->u.crypt.auth_data_len != OSPF_AUTH_MD5_SIZE) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: unsupported crypto auth length (%u B)", __func__, oh->u.crypt.auth_data_len); return MSG_NG; } bytesauth = OSPF_AUTH_MD5_SIZE; } if (bytesdeclared + bytesauth > bytesonwire) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: packet length error (%u real, %u+%u declared)", __func__, bytesonwire, bytesdeclared, bytesauth); return MSG_NG; } /* Length, 2nd approximation. The type-specific constraint is checked against declared length, not amount of bytes on wire. */ if ( oh->type >= OSPF_MSG_HELLO && oh->type <= OSPF_MSG_LS_ACK && bytesdeclared < OSPF_HEADER_SIZE + ospf_packet_minlen[oh->type] ) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: undersized (%u B) %s packet", __func__, bytesdeclared, LOOKUP (ospf_packet_type_str, oh->type)); return MSG_NG; } switch (oh->type) { case OSPF_MSG_HELLO: /* RFC2328 A.3.2, packet header + OSPF_HELLO_MIN_SIZE bytes followed by N>=0 router-IDs. */ ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE) % 4 ? MSG_NG : MSG_OK; break; case OSPF_MSG_DB_DESC: /* RFC2328 A.3.3, packet header + OSPF_DB_DESC_MIN_SIZE bytes followed by N>=0 header-only LSAs. */ ret = ospf_lsaseq_examin ( (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE), bytesdeclared - OSPF_HEADER_SIZE - OSPF_DB_DESC_MIN_SIZE, 1, /* header-only LSAs */ 0 ); break; case OSPF_MSG_LS_REQ: /* RFC2328 A.3.4, packet header followed by N>=0 12-bytes request blocks. */ ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_REQ_MIN_SIZE) % OSPF_LSA_KEY_SIZE ? MSG_NG : MSG_OK; break; case OSPF_MSG_LS_UPD: /* RFC2328 A.3.5, packet header + OSPF_LS_UPD_MIN_SIZE bytes followed by N>=0 full LSAs (with N declared beforehand). */ lsupd = (struct ospf_ls_update *) ((caddr_t) oh + OSPF_HEADER_SIZE); ret = ospf_lsaseq_examin ( (struct lsa_header *) ((caddr_t) lsupd + OSPF_LS_UPD_MIN_SIZE), bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_UPD_MIN_SIZE, 0, /* full LSAs */ ntohl (lsupd->num_lsas) /* 32 bits */ ); break; case OSPF_MSG_LS_ACK: /* RFC2328 A.3.6, packet header followed by N>=0 header-only LSAs. */ ret = ospf_lsaseq_examin ( (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_LS_ACK_MIN_SIZE), bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_ACK_MIN_SIZE, 1, /* header-only LSAs */ 0 ); break; default: if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: invalid packet type 0x%02x", __func__, oh->type); return MSG_NG; } if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: malformed %s packet", __func__, LOOKUP (ospf_packet_type_str, oh->type)); return ret; } /* OSPF Header verification. */ static int ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh) { /* 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. The function handles logging actions, where required. */ if (! ospf_check_auth (oi, ospfh)) 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); /* prepare for next packet. */ ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd); stream_reset(ospf->ibuf); if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf))) return -1; /* This raw packet is known to be at least as big as its IP header. */ /* Note that there should not be alignment problems with this assignment because this is at the beginning of the stream data buffer. */ iph = (struct ip *) STREAM_DATA (ibuf); /* Note that sockopt_iphdrincl_swab_systoh was called in ospf_recv_packet. */ if (ifp == NULL) /* Handle cases where the platform does not support retrieving the ifindex, and also platforms (such as Solaris 8) that claim to support ifindex retrieval but do not. */ ifp = if_lookup_address (iph->ip_src); if (ifp == NULL) return 0; /* IP Header dump. */ if (IS_DEBUG_OSPF_PACKET(0, RECV)) ospf_ip_header_dump (iph); /* Self-originated packet should be discarded silently. */ if (ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_src)) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) { zlog_debug ("ospf_read[%s]: Dropping self-originated packet", inet_ntoa (iph->ip_src)); } return 0; } /* Advance from IP header to OSPF header (iph->ip_hl has been verified by ospf_recv_packet() to be correct). */ stream_forward_getp (ibuf, iph->ip_hl * 4); ospfh = (struct ospf_header *) STREAM_PNT (ibuf); if (MSG_OK != ospf_packet_examin (ospfh, stream_get_endp (ibuf) - stream_get_getp (ibuf))) return -1; /* Now it is safe to access all fields of OSPF packet header. */ /* associate packet with ospf interface */ oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp); /* ospf_verify_header() relies on a valid "oi" and thus can be called only after the passive/backbone/other checks below are passed. These checks in turn access the fields of unverified "ospfh" structure for their own purposes and must remain very accurate in doing this. */ /* If incoming interface is passive one, ignore it. */ if (oi && OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE) { char buf[3][INET_ADDRSTRLEN]; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ignoring packet from router %s sent to %s, " "received on a passive interface, %s", inet_ntop(AF_INET, &ospfh->router_id, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])), inet_ntop(AF_INET, &oi->address->u.prefix4, buf[2], sizeof(buf[2]))); if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) { /* Try to fix multicast membership. * Some OS:es may have problems in this area, * make sure it is removed. */ OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); ospf_if_set_multicast(oi); } return 0; } /* if no local ospf_interface, * or header area is backbone but ospf_interface is not * check for VLINK interface */ if ( (oi == NULL) || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id) && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id)) ) { if ((oi = ospf_associate_packet_vl (ospf, ifp, iph, ospfh)) == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Packet from [%s] received on link %s" " but no ospf_interface", inet_ntoa (iph->ip_src), ifp->name); return 0; } } /* else it must be a local ospf interface, check it was received on * correct link */ else if (oi->ifp != ifp) { if (IS_DEBUG_OSPF_EVENT) zlog_warn ("Packet from [%s] received on wrong link %s", inet_ntoa (iph->ip_src), ifp->name); return 0; } else if (oi->state == ISM_Down) { char buf[2][INET_ADDRSTRLEN]; zlog_warn ("Ignoring packet from %s to %s received on interface that is " "down [%s]; interface flags are %s", inet_ntop(AF_INET, &iph->ip_src, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])), ifp->name, if_flag_dump(ifp->flags)); /* Fix multicast memberships? */ if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS)) OI_MEMBER_JOINED(oi, MEMBER_DROUTERS); if (oi->multicast_memberships) ospf_if_set_multicast(oi); 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_warn ("Dropping packet for AllDRouters from [%s] via [%s] (ISM: %s)", inet_ntoa (iph->ip_src), IF_NAME (oi), LOOKUP (ospf_ism_state_msg, oi->state)); /* Try to fix multicast membership. */ SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS); ospf_if_set_multicast(oi); return 0; } /* Verify more OSPF header fields. */ ret = ospf_verify_header (ibuf, oi, iph, ospfh); if (ret < 0) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("ospf_read[%s]: Header check failed, " "dropping.", inet_ntoa (iph->ip_src)); return ret; } /* Show debug receiving packet. */ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) { zlog_debug ("-----------------------------------------------------"); ospf_packet_dump (ibuf); } zlog_debug ("%s received from [%s] via [%s]", LOOKUP (ospf_packet_type_str, ospfh->type), inet_ntoa (ospfh->router_id), IF_NAME (oi)); zlog_debug (" src [%s],", inet_ntoa (iph->ip_src)); zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst)); if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) zlog_debug ("-----------------------------------------------------"); } stream_forward_getp (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 (ospf, 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; } return 0; } /* Make OSPF header. */ static 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); stream_forward_endp (s, OSPF_HEADER_SIZE); } /* Make Authentication Data. */ static 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: /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */ 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 = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt))); 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: /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */ break; } return 0; } /* Fill rest of OSPF header. */ static 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); } static 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 (!(CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED) && 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. */ if (OSPF_IF_PARAM (oi, fast_hello) == 0) stream_putw (s, OSPF_IF_PARAM (oi, v_hello)); else stream_putw (s, 0); /* hello-interval of 0 for fast-hellos */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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 = stream_get_endp (s); /* 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_putl_at (s, p, 0); /* ipv4 address, normally */ return length; } static 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); if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) SET_FLAG (options, OSPF_OPTION_O); stream_putc (s, options); /* DD flags */ pp = stream_get_endp (s); stream_putc (s, nbr->dd_flags); /* Set DD Sequence Number. */ stream_putl (s, nbr->dd_seqnum); /* shortcut unneeded walk of (empty) summary LSDBs */ if (ospf_db_summary_isempty (nbr)) goto empty; /* 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) { 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; } 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_endp (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); } } /* Update 'More' bit */ if (ospf_db_summary_isempty (nbr)) { empty: if (nbr->state >= NSM_Exchange) { UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_M); /* Rewrite DD flags */ stream_putc_at (s, pp, nbr->dd_flags); } else { assert (IS_SET_DD_M(nbr->dd_flags)); } } return length; } static 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; } static 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_endp(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; } static 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); } static int ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream *s) { struct ospf_lsa *lsa; struct listnode *node; u_int16_t length = 0; unsigned int size_noauth; unsigned long delta = stream_get_endp (s); unsigned long pp; int count = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_make_ls_upd: Start"); pp = stream_get_endp (s); stream_forward_endp (s, OSPF_LS_UPD_MIN_SIZE); length += OSPF_LS_UPD_MIN_SIZE; /* Calculate amount of packet usable for data. */ size_noauth = stream_get_size(s) - ospf_packet_authspace(oi); while ((node = listhead (update)) != NULL) { struct lsa_header *lsah; u_int16_t ls_age; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_make_ls_upd: List Iteration %d", count); lsa = listgetdata (node); assert (lsa->data); /* Will it fit? */ if (length + delta + ntohs (lsa->data->length) > size_noauth) break; /* Keep pointer to LS age. */ lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_endp (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); /* oi->ls_upd_queue */ } /* Now set #LSAs. */ stream_putl_at (s, pp, count); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_make_ls_upd: Stop"); return length; } static int ospf_make_ls_ack (struct ospf_interface *oi, struct list *ack, struct stream *s) { struct listnode *node, *nnode; u_int16_t length = OSPF_LS_ACK_MIN_SIZE; unsigned long delta = stream_get_endp(s) + 24; struct ospf_lsa *lsa; for (ALL_LIST_ELEMENTS (ack, node, nnode, lsa)) { 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_delete (ack, lsa); ospf_lsa_unlock (&lsa); /* oi->ls_ack_direct.ls_ack */ } return length; } static void ospf_hello_send_sub (struct ospf_interface *oi, in_addr_t 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; /* Add packet to the top of the interface output queue, so that they * can't get delayed by things like long queues of LS Update packets */ ospf_packet_add_top (oi, op); /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON (oi->ospf); } static 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_PASSIVE_STATUS (oi) == 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.s_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_DEBUG, "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_DEBUG, "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.s_addr); return 0; } /* Send OSPF Hello. */ void ospf_hello_send (struct ospf_interface *oi) { /* If this is passive interface, do not send OSPF Hello. */ if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE) return; 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 */ ospf_hello_send_sub (oi, nbr->address.u.prefix4.s_addr); } } else { /* Decide destination address. */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) ospf_hello_send_sub (oi, oi->vl_data->peer_addr.s_addr); else ospf_hello_send_sub (oi, htonl (OSPF_ALLSPFROUTERS)); } } /* 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. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else 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); quagga_gettime (QUAGGA_CLK_MONOTONIC, &nbr->last_send_ts); } /* 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. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else 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) { struct list *update; update = list_new (); listnode_add (update, lsa); ospf_ls_upd_send (nbr, update, flag); list_delete (update); } /* Determine size for packet. Must be at least big enough to accomodate next * LSA on list, which may be bigger than MTU size. * * Return pointer to new ospf_packet * NULL if we can not allocate, eg because LSA is bigger than imposed limit * on packet sizes (in which case offending LSA is deleted from update list) */ static struct ospf_packet * ospf_ls_upd_packet_new (struct list *update, struct ospf_interface *oi) { struct ospf_lsa *lsa; struct listnode *ln; size_t size; static char warned = 0; lsa = listgetdata((ln = listhead (update))); assert (lsa->data); if ((OSPF_LS_UPD_MIN_SIZE + ntohs (lsa->data->length)) > ospf_packet_max (oi)) { if (!warned) { zlog_warn ("ospf_ls_upd_packet_new: oversized LSA encountered!" "will need to fragment. Not optimal. Try divide up" " your network with areas. Use 'debug ospf packet send'" " to see details, or look at 'show ip ospf database ..'"); warned = 1; } if (IS_DEBUG_OSPF_PACKET (0, SEND)) zlog_debug ("ospf_ls_upd_packet_new: oversized LSA id:%s," " %d bytes originated by %s, will be fragmented!", inet_ntoa (lsa->data->id), ntohs (lsa->data->length), inet_ntoa (lsa->data->adv_router)); /* * Allocate just enough to fit this LSA only, to avoid including other * LSAs in fragmented LSA Updates. */ size = ntohs (lsa->data->length) + (oi->ifp->mtu - ospf_packet_max (oi)) + OSPF_LS_UPD_MIN_SIZE; } else size = oi->ifp->mtu; if (size > OSPF_MAX_PACKET_SIZE) { zlog_warn ("ospf_ls_upd_packet_new: oversized LSA id:%s too big," " %d bytes, packet size %ld, dropping it completely." " OSPF routing is broken!", inet_ntoa (lsa->data->id), ntohs (lsa->data->length), (long int) size); list_delete_node (update, ln); return NULL; } /* IP header is built up separately by ospf_write(). This means, that we must * reduce the "affordable" size just calculated by length of an IP header. * This makes sure, that even if we manage to fill the payload with LSA data * completely, the final packet (our data plus IP header) still fits into * outgoing interface MTU. This correction isn't really meaningful for an * oversized LSA, but for consistency the correction is done for both cases. * * P.S. OSPF_MAX_PACKET_SIZE above already includes IP header size */ return ospf_packet_new (size - sizeof (struct ip)); } static void ospf_ls_upd_queue_send (struct ospf_interface *oi, struct list *update, struct in_addr addr) { struct ospf_packet *op; u_int16_t length = OSPF_HEADER_SIZE; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("listcount = %d, [%s]dst %s", listcount (update), IF_NAME(oi), inet_ntoa(addr)); op = ospf_ls_upd_packet_new (update, oi); /* 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. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else 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; struct route_node *rnext; struct list *update; char again = 0; oi->t_ls_upd_event = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ls_upd_send_queue start"); for (rn = route_top (oi->ls_upd_queue); rn; rn = rnext) { rnext = route_next (rn); if (rn->info == NULL) continue; update = (struct list *)rn->info; ospf_ls_upd_queue_send (oi, update, rn->p.u.prefix4); /* list might not be empty. */ if (listcount(update) == 0) { list_delete (rn->info); rn->info = NULL; route_unlock_node (rn); } else again = 1; } if (again != 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ls_upd_send_queue: update lists not cleared," " %d nodes to try again, raising new event", again); oi->t_ls_upd_event = thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ls_upd_send_queue stop"); return 0; } void ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag) { struct ospf_interface *oi; struct ospf_lsa *lsa; struct prefix_ipv4 p; struct route_node *rn; struct listnode *node; 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 (oi->type == OSPF_IFTYPE_POINTOPOINT) p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); 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_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 (); else route_unlock_node (rn); for (ALL_LIST_ELEMENTS_RO (update, node, lsa)) listnode_add (rn->info, ospf_lsa_lock (lsa)); /* oi->ls_upd_queue */ 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, struct 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; /* Decide destination address. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else op->dst.s_addr = dst.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_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 if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) 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); } quagga-1.2.4/ospfd/ospf_packet.h000066400000000000000000000134761325323223500165600ustar00rootroot00000000000000/* * 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 24U #define OSPF_AUTH_SIMPLE_SIZE 8U #define OSPF_AUTH_MD5_SIZE 16U #define OSPF_MAX_PACKET_SIZE 65535U /* includes IP Header size. */ #define OSPF_HELLO_MIN_SIZE 20U /* not including neighbors */ #define OSPF_DB_DESC_MIN_SIZE 8U #define OSPF_LS_REQ_MIN_SIZE 0U #define OSPF_LS_UPD_MIN_SIZE 4U #define OSPF_LS_ACK_MIN_SIZE 0U #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 #define OSPF_SEND_PACKET_LOOP 3 #define OSPF_HELLO_REPLY_DELAY 1 /* Return values of functions involved in packet verification, see ospf6d. */ #define MSG_OK 0 #define MSG_NG 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; }; struct ospf_ls_update { u_int32_t num_lsas; }; /* Macros. */ /* XXX Perhaps obsolete; function in ospf_packet.c */ #define OSPF_PACKET_MAX(oi) ospf_packet_max (oi) #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. */ extern void ospf_output_forward (struct stream *, int); extern struct ospf_packet *ospf_packet_new (size_t); extern void ospf_packet_free (struct ospf_packet *); extern struct ospf_fifo *ospf_fifo_new (void); extern void ospf_fifo_push (struct ospf_fifo *, struct ospf_packet *); extern struct ospf_packet *ospf_fifo_pop (struct ospf_fifo *); extern struct ospf_packet *ospf_fifo_head (struct ospf_fifo *); extern void ospf_fifo_flush (struct ospf_fifo *); extern void ospf_fifo_free (struct ospf_fifo *); extern void ospf_packet_add (struct ospf_interface *, struct ospf_packet *); extern void ospf_packet_delete (struct ospf_interface *); extern struct stream *ospf_stream_dup (struct stream *); extern struct ospf_packet *ospf_packet_dup (struct ospf_packet *); extern int ospf_read (struct thread *); extern void ospf_hello_send (struct ospf_interface *); extern void ospf_db_desc_send (struct ospf_neighbor *); extern void ospf_db_desc_resend (struct ospf_neighbor *); extern void ospf_ls_req_send (struct ospf_neighbor *); extern void ospf_ls_upd_send_lsa (struct ospf_neighbor *, struct ospf_lsa *, int); extern void ospf_ls_upd_send (struct ospf_neighbor *, struct list *, int); extern void ospf_ls_ack_send (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_ack_send_delayed (struct ospf_interface *); extern void ospf_ls_retransmit (struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event (struct ospf_neighbor *); extern int ospf_ls_upd_timer (struct thread *); extern int ospf_ls_ack_timer (struct thread *); extern int ospf_poll_timer (struct thread *); extern int ospf_hello_reply_timer (struct thread *); extern const struct message ospf_packet_type_str[]; extern const size_t ospf_packet_type_str_max; #endif /* _ZEBRA_OSPF_PACKET_H */ quagga-1.2.4/ospfd/ospf_ri.c000066400000000000000000001301211325323223500157010ustar00rootroot00000000000000/* * This is an implementation of RFC4970 Router Information * with support of RFC5088 PCE Capabilites announcement * * Module name: Router Information * Version: 0.99.22 * Created: 2012-02-01 by Olivier Dugeon * Copyright (C) 2012 Orange Labs http://www.orange.com/ * * This file is part of GNU Quagga. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Quagga; 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 "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_ri.h" #include "ospfd/ospf_te.h" struct ospf_pce_info { /* Store Router Information PCE TLV and SubTLV in network byte order. */ struct ri_tlv_pce pce_header; struct ri_pce_subtlv_address pce_address; struct ri_pce_subtlv_path_scope pce_scope; struct list *pce_domain; struct list *pce_neighbor; struct ri_pce_subtlv_cap_flag pce_cap_flag; }; /* Following structure are internal use only. */ struct ospf_router_info { status_t status; u_int8_t registered; u_int8_t scope; /* Flags to manage this router information. */ #define RIFLG_LOOKUP_DONE 0x1 #define RIFLG_LSA_ENGAGED 0x2 #define RIFLG_LSA_FORCED_REFRESH 0x4 u_int32_t flags; /* area pointer if flooding is Type 10 Null if flooding is AS scope */ struct ospf_area *area; struct in_addr area_id; /* Store Router Information Capabilities LSA */ struct ri_tlv_router_cap router_cap; /* Store PCE capability LSA */ struct ospf_pce_info pce_info; }; /* * Global variable to manage Opaque-LSA/Router Information on this node. * Note that all parameter values are stored in network byte order. */ static struct ospf_router_info OspfRI; /*------------------------------------------------------------------------------* * Followings are initialize/terminate functions for Router Information handling. *------------------------------------------------------------------------------*/ static void ospf_router_info_ism_change (struct ospf_interface *oi, int old_status); static void ospf_router_info_nsm_change (struct ospf_neighbor *nbr, int old_status); static void ospf_router_info_config_write_router (struct vty *vty); static void ospf_router_info_show_info (struct vty *vty, struct ospf_lsa *lsa); static int ospf_router_info_lsa_originate (void *arg); static struct ospf_lsa *ospf_router_info_lsa_refresh (struct ospf_lsa *lsa); static void ospf_router_info_lsa_schedule (opcode_t opcode); static void ospf_router_info_register_vty (void); static void del_pce_info (void *val); int ospf_router_info_init (void) { memset (&OspfRI, 0, sizeof (struct ospf_router_info)); OspfRI.status = disabled; OspfRI.registered = 0; OspfRI.scope = OSPF_OPAQUE_AS_LSA; OspfRI.flags = 0; /* Initialize pce domain and neighbor list */ OspfRI.pce_info.pce_domain = list_new (); OspfRI.pce_info.pce_domain->del = del_pce_info; OspfRI.pce_info.pce_neighbor = list_new (); OspfRI.pce_info.pce_neighbor->del = del_pce_info; ospf_router_info_register_vty (); return 0; } static int ospf_router_info_register (u_int8_t scope) { int rc = 0; if (OspfRI.registered) return 0; zlog_info ("Register Router Information with scope %s(%d)", scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope); rc = ospf_register_opaque_functab (scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA, NULL, /* new interface */ NULL, /* del interface */ ospf_router_info_ism_change, ospf_router_info_nsm_change, ospf_router_info_config_write_router, NULL, /* Config. write interface */ NULL, /* Config. write debug */ ospf_router_info_show_info, ospf_router_info_lsa_originate, ospf_router_info_lsa_refresh, NULL, /* new_lsa_hook */ NULL); /* del_lsa_hook */ if (rc != 0) { zlog_warn ("ospf_router_info_init: Failed to register functions"); return rc; } OspfRI.registered = 1; OspfRI.scope = scope; return 0; } static int ospf_router_info_unregister () { if ((OspfRI.scope != OSPF_OPAQUE_AS_LSA) && (OspfRI.scope != OSPF_OPAQUE_AREA_LSA)) { zlog_warn ("Unable to unregister Router Info functions: Wrong scope!"); return -1; } ospf_delete_opaque_functab (OspfRI.scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA); OspfRI.registered = 0; return 0; } void ospf_router_info_term (void) { list_delete (OspfRI.pce_info.pce_domain); list_delete (OspfRI.pce_info.pce_neighbor); OspfRI.pce_info.pce_domain = NULL; OspfRI.pce_info.pce_neighbor = NULL; OspfRI.status = disabled; ospf_router_info_unregister (OspfRI.scope); return; } static void del_pce_info (void *val) { XFREE (MTYPE_OSPF_PCE_PARAMS, val); return; } /*------------------------------------------------------------------------* * Followings are control functions for ROUTER INFORMATION parameters management. *------------------------------------------------------------------------*/ static void set_router_info_capabilities (struct ri_tlv_router_cap *ric, u_int32_t cap) { ric->header.type = htons (RI_TLV_CAPABILITIES); ric->header.length = htons (RI_TLV_LENGTH); ric->value = htonl (cap); return; } static int set_pce_header (struct ospf_pce_info *pce) { u_int16_t length = 0; struct listnode *node; struct ri_pce_subtlv_domain *domain; struct ri_pce_subtlv_neighbor *neighbor; /* PCE Address */ if (ntohs (pce->pce_address.header.type) != 0) length += RI_TLV_SIZE (&pce->pce_address.header); /* PCE Path Scope */ if (ntohs (pce->pce_scope.header.type) != 0) length += RI_TLV_SIZE (&pce->pce_scope.header); /* PCE Domain */ for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) { if (ntohs (domain->header.type) != 0) length += RI_TLV_SIZE (&domain->header); } /* PCE Neighbor */ for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) { if (ntohs (neighbor->header.type) != 0) length += RI_TLV_SIZE (&neighbor->header); } /* PCE Capabilities */ if (ntohs (pce->pce_cap_flag.header.type) != 0) length += RI_TLV_SIZE (&pce->pce_cap_flag.header); if (length != 0) { pce->pce_header.header.type = htons (RI_TLV_PCE); pce->pce_header.header.length = htons (length); } else { pce->pce_header.header.type = 0; pce->pce_header.header.length = 0; } return length; } static void set_pce_address (struct in_addr ipv4, struct ospf_pce_info *pce) { /* Enable PCE Info */ pce->pce_header.header.type = htons (RI_TLV_PCE); /* Set PCE Address */ pce->pce_address.header.type = htons (RI_PCE_SUBTLV_ADDRESS); pce->pce_address.header.length = htons (PCE_ADDRESS_LENGTH_IPV4); pce->pce_address.address.type = htons (PCE_ADDRESS_TYPE_IPV4); pce->pce_address.address.value = ipv4; return; } static void set_pce_path_scope (u_int32_t scope, struct ospf_pce_info *pce) { /* Enable PCE Info */ pce->pce_header.header.type = htons (RI_TLV_PCE); /* Set PCE Scope */ pce->pce_scope.header.type = htons (RI_PCE_SUBTLV_PATH_SCOPE); pce->pce_scope.header.length = htons (RI_TLV_LENGTH); pce->pce_scope.value = htonl (scope); return; } static void set_pce_domain (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) { struct ri_pce_subtlv_domain *new; /* Enable PCE Info */ pce->pce_header.header.type = htons (RI_TLV_PCE); /* Create new domain info */ new = XCALLOC (MTYPE_OSPF_PCE_PARAMS, sizeof (struct ri_pce_subtlv_domain)); new->header.type = htons (RI_PCE_SUBTLV_DOMAIN); new->header.length = htons (PCE_ADDRESS_LENGTH_IPV4); new->type = htons (type); new->value = htonl (domain); /* Add new domain to the list */ listnode_add (pce->pce_domain, new); return; } static void unset_pce_domain (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) { struct listnode *node; struct ri_pce_subtlv_domain *old = NULL; int found = 0; /* Search the corresponding node */ for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, old)) { if ((old->type == htons (type)) && (old->value == htonl (domain))) { found = 1; break; } } /* if found remove it */ if (found) { listnode_delete (pce->pce_domain, old); /* Avoid misjudgement in the next lookup. */ if (listcount (pce->pce_domain) == 0) pce->pce_domain->head = pce->pce_domain->tail = NULL; /* Finally free the old domain */ XFREE (MTYPE_OSPF_PCE_PARAMS, old); } } static void set_pce_neighbor (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) { struct ri_pce_subtlv_neighbor *new; /* Enable PCE Info */ pce->pce_header.header.type = htons (RI_TLV_PCE); /* Create new neighbor info */ new = XCALLOC (MTYPE_OSPF_PCE_PARAMS, sizeof (struct ri_pce_subtlv_neighbor)); new->header.type = htons (RI_PCE_SUBTLV_NEIGHBOR); new->header.length = htons (PCE_ADDRESS_LENGTH_IPV4); new->type = htons (type); new->value = htonl (domain); /* Add new domain to the list */ listnode_add (pce->pce_neighbor, new); return; } static void unset_pce_neighbor (u_int16_t type, u_int32_t domain, struct ospf_pce_info *pce) { struct listnode *node; struct ri_pce_subtlv_neighbor *old = NULL; int found = 0; /* Search the corresponding node */ for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, old)) { if ((old->type == htons (type)) && (old->value == htonl (domain))) { found = 1; break; } } /* if found remove it */ if (found) { listnode_delete (pce->pce_neighbor, old); /* Avoid misjudgement in the next lookup. */ if (listcount (pce->pce_neighbor) == 0) pce->pce_neighbor->head = pce->pce_neighbor->tail = NULL; /* Finally free the old domain */ XFREE (MTYPE_OSPF_PCE_PARAMS, old); } } static void set_pce_cap_flag (u_int32_t cap, struct ospf_pce_info *pce) { /* Enable PCE Info */ pce->pce_header.header.type = htons (RI_TLV_PCE); /* Set PCE Capabilities flag */ pce->pce_cap_flag.header.type = htons (RI_PCE_SUBTLV_CAP_FLAG); pce->pce_cap_flag.header.length = htons (RI_TLV_LENGTH); pce->pce_cap_flag.value = htonl (cap); return; } static void unset_param (struct ri_tlv_header *tlv) { tlv->type = 0; /* Fill the Value to 0 */ memset ((tlv + RI_TLV_HDR_SIZE), 0, RI_TLV_BODY_SIZE (tlv)); tlv->length = 0; return; } static void initialize_params (struct ospf_router_info *ori) { u_int32_t cap; struct ospf *top; /* * Initialize default Router Information Capabilities. */ cap = 0; cap = cap | RI_TE_SUPPORT; set_router_info_capabilities (&ori->router_cap, cap); /* If Area address is not null and exist, retrieve corresponding structure */ top = ospf_lookup (); zlog_info ("RI-> Initialize Router Info for %s scope within area %s", OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", inet_ntoa (OspfRI.area_id)); /* Try to get the Area context at this step. Do it latter if not available */ if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) OspfRI.area = ospf_area_lookup_by_area_id (top, OspfRI.area_id); /* * Initialize default PCE Information values */ /* PCE address == OSPF Router ID */ set_pce_address (top->router_id, &ori->pce_info); /* PCE scope */ cap = 7; /* Set L, R and Rd bits to one = intra & inter-area path computation */ set_pce_path_scope (cap, &ori->pce_info); /* PCE Capabilities */ cap = PCE_CAP_BIDIRECTIONAL | PCE_CAP_DIVERSE_PATH | PCE_CAP_OBJECTIVES | PCE_CAP_ADDITIVE | PCE_CAP_MULTIPLE_REQ; set_pce_cap_flag (cap, &ori->pce_info); /* Finally compute PCE header */ set_pce_header (&ori->pce_info); return; } static int is_mandated_params_set (struct ospf_router_info ori) { int rc = 0; if (ntohs (ori.router_cap.header.type) == 0) goto out; if ((ntohs (ori.pce_info.pce_header.header.type) == RI_TLV_PCE) && (ntohs (ori.pce_info.pce_address.header.type) == 0) && (ntohs (ori.pce_info.pce_cap_flag.header.type) == 0)) goto out; rc = 1; out: return rc; } /*------------------------------------------------------------------------* * Followings are callback functions against generic Opaque-LSAs handling. *------------------------------------------------------------------------*/ static void ospf_router_info_ism_change (struct ospf_interface *oi, int old_state) { /* So far, nothing to do here. */ return; } static void ospf_router_info_nsm_change (struct ospf_neighbor *nbr, int old_state) { /* So far, nothing to do here. */ return; } /*------------------------------------------------------------------------* * Followings are OSPF protocol processing functions for ROUTER INFORMATION *------------------------------------------------------------------------*/ static void build_tlv_header (struct stream *s, struct ri_tlv_header *tlvh) { stream_put (s, tlvh, sizeof (struct ri_tlv_header)); return; } static void build_tlv (struct stream *s, struct ri_tlv_header *tlvh) { if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh + 1, RI_TLV_BODY_SIZE (tlvh)); } return; } static void ospf_router_info_lsa_body_set (struct stream *s) { struct listnode *node; struct ri_pce_subtlv_domain *domain; struct ri_pce_subtlv_neighbor *neighbor; /* Build Router Information TLV */ build_tlv (s, &OspfRI.router_cap.header); /* Add RI PCE TLV if it is set */ /* Compute PCE Info header first */ if ((set_pce_header (&OspfRI.pce_info)) != 0) { /* Build PCE TLV */ build_tlv_header (s, &OspfRI.pce_info.pce_header.header); /* Build PCE address sub-tlv */ build_tlv (s, &OspfRI.pce_info.pce_address.header); /* Build PCE path scope sub-tlv */ build_tlv (s, &OspfRI.pce_info.pce_scope.header); /* Build PCE domain sub-tlv */ for (ALL_LIST_ELEMENTS_RO (OspfRI.pce_info.pce_domain, node, domain)) build_tlv (s, &domain->header); /* Build PCE neighbor sub-tlv */ for (ALL_LIST_ELEMENTS_RO (OspfRI.pce_info.pce_neighbor, node, neighbor)) build_tlv (s, &neighbor->header); /* Build PCE cap flag sub-tlv */ build_tlv (s, &OspfRI.pce_info.pce_cap_flag.header); } return; } /* Create new opaque-LSA. */ static struct ospf_lsa * ospf_router_info_lsa_new () { struct ospf *top; 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_router_info_lsa_new: stream_new() ?"); goto out; } lsah = (struct lsa_header *) STREAM_DATA (s); options = OSPF_OPTION_E; /* Enable AS external as we flood RI with Opaque Type 11 */ options |= OSPF_OPTION_O; /* Don't forget this :-) */ lsa_type = OspfRI.scope; /* LSA ID == 0 for Router Information see RFC 4970 */ tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0); lsa_id.s_addr = htonl (tmp); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Create an Opaque-LSA/ROUTER INFORMATION instance", lsa_type, inet_ntoa (lsa_id)); top = ospf_lookup (); /* Set opaque-LSA header fields. */ lsa_header_set (s, options, lsa_type, lsa_id, top->router_id); /* Set opaque-LSA body fields. */ ospf_router_info_lsa_body_set (s); /* 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_router_info_lsa_new: ospf_lsa_new() ?"); stream_free (s); goto out; } if ((new->data = ospf_lsa_data_new (length)) == NULL) { zlog_warn ("ospf_router_info_lsa_new: ospf_lsa_data_new() ?"); ospf_lsa_unlock (&new); new = NULL; stream_free (s); goto out; } new->area = OspfRI.area; /* Area must be null if the Opaque type is AS scope, fulfill otherwise */ SET_FLAG (new->flags, OSPF_LSA_SELF); memcpy (new->data, lsah, length); stream_free (s); out:return new; } static int ospf_router_info_lsa_originate1 (void *arg) { struct ospf_lsa *new; struct ospf *top; struct ospf_area *area; int rc = -1; /* First check if the area is known if flooding scope is Area */ if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { area = (struct ospf_area *) arg; if (area->area_id.s_addr != OspfRI.area_id.s_addr) { zlog_debug ("RI -> This is not the Router Information Area. Stop processing"); goto out; } OspfRI.area = area; } /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ if ((new = ospf_router_info_lsa_new ()) == NULL) { zlog_warn ("ospf_router_info_lsa_originate1: ospf_router_info_lsa_new() ?"); goto out; } /* Get ospf info */ top = ospf_lookup (); /* Install this LSA into LSDB. */ if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) { zlog_warn ("ospf_router_info_lsa_originate1: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } /* Now this Router Info parameter entry has associated LSA. */ SET_FLAG (OspfRI.flags, RIFLG_LSA_ENGAGED); /* Update new LSA origination count. */ top->lsa_originate_count++; /* Flood new LSA through AS. */ if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) ospf_flood_through_as (top, NULL /*nbr */ , new); else ospf_flood_through_area (OspfRI.area, NULL /*nbr */ , new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } rc = 0; out:return rc; } static int ospf_router_info_lsa_originate (void *arg) { int rc = -1; if (OspfRI.status == disabled) { zlog_info ("ospf_router_info_lsa_originate: ROUTER INFORMATION is disabled now."); rc = 0; /* This is not an error case. */ goto out; } /* Check if Router Information LSA is already engaged */ if (OspfRI.flags & RIFLG_LSA_ENGAGED) { if (OspfRI.flags & RIFLG_LSA_FORCED_REFRESH) { OspfRI.flags &= ~RIFLG_LSA_FORCED_REFRESH; ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); } } else { if (!is_mandated_params_set (OspfRI)) zlog_warn ("ospf_router_info_lsa_originate: lacks mandated ROUTER INFORMATION parameters"); /* Ok, let's try to originate an LSA */ if (ospf_router_info_lsa_originate1 (arg) != 0) goto out; } rc = 0; out:return rc; } static struct ospf_lsa * ospf_router_info_lsa_refresh (struct ospf_lsa *lsa) { struct ospf_lsa *new = NULL; struct ospf *top; if (OspfRI.status == disabled) { /* * This LSA must have flushed before due to ROUTER INFORMATION status change. * It seems a slip among routers in the routing domain. */ zlog_info ("ospf_router_info_lsa_refresh: ROUTER INFORMATION is disabled now."); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } /* Verify that the Router Information ID is supported */ if (GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)) != 0) { zlog_warn ("ospf_router_info_lsa_refresh: Unsupported Router Information ID"); goto out; } /* If the lsa's age reached to MaxAge, start flushing procedure. */ if (IS_LSA_MAXAGE (lsa)) { OspfRI.flags &= ~RIFLG_LSA_ENGAGED; ospf_opaque_lsa_flush_schedule (lsa); goto out; } /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ if ((new = ospf_router_info_lsa_new ()) == NULL) { zlog_warn ("ospf_router_info_lsa_refresh: ospf_router_info_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. */ top = ospf_lookup (); if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) { zlog_warn ("ospf_router_info_lsa_refresh: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } /* Flood updated LSA through AS or AREA depending of OspfRI.scope. */ if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) ospf_flood_through_as (top, NULL /*nbr */ , new); else ospf_flood_through_area (OspfRI.area, NULL /*nbr */ , new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Refresh Opaque-LSA/ROUTER INFORMATION", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } out:return new; } static void ospf_router_info_lsa_schedule (opcode_t opcode) { struct ospf_lsa lsa; struct lsa_header lsah; struct ospf *top; u_int32_t tmp; memset (&lsa, 0, sizeof (lsa)); memset (&lsah, 0, sizeof (lsah)); zlog_debug ("RI-> LSA schedule %s%s%s", opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", opcode == REFRESH_THIS_LSA ? "Refresh" : "", opcode == FLUSH_THIS_LSA ? "Flush" : ""); top = ospf_lookup (); if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) { zlog_warn ("ospf_router_info_lsa_schedule(): Router Info is Area scope flooding but area is not set"); OspfRI.area = ospf_area_lookup_by_area_id (top, OspfRI.area_id); } lsa.area = OspfRI.area; lsa.data = &lsah; lsah.type = OspfRI.scope; /* LSA ID is set to 0 for the Router Information. See RFC 4970 */ tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0); lsah.id.s_addr = htonl (tmp); switch (opcode) { case REORIGINATE_THIS_LSA: if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) ospf_opaque_lsa_reoriginate_schedule ((void *) OspfRI.area, OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_ROUTER_INFORMATION_LSA); else ospf_opaque_lsa_reoriginate_schedule ((void *) top, OSPF_OPAQUE_AS_LSA, OPAQUE_TYPE_ROUTER_INFORMATION_LSA); break; case REFRESH_THIS_LSA: ospf_opaque_lsa_refresh_schedule (&lsa); break; case FLUSH_THIS_LSA: OspfRI.flags &= ~RIFLG_LSA_ENGAGED; ospf_opaque_lsa_flush_schedule (&lsa); break; default: zlog_warn ("ospf_router_info_lsa_schedule: Unknown opcode (%u)", opcode); break; } return; } /*------------------------------------------------------------------------* * Followings are vty session control functions. *------------------------------------------------------------------------*/ static u_int16_t show_vty_router_cap (struct vty *vty, struct ri_tlv_header *tlvh) { struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *) tlvh; if (vty != NULL) vty_out (vty, " Router Capabilities: 0x%x%s", ntohl (top->value), VTY_NEWLINE); else zlog_debug (" Router Capabilities: 0x%x", ntohl (top->value)); return RI_TLV_SIZE (tlvh); } static u_int16_t show_vty_pce_subtlv_address (struct vty *vty, struct ri_tlv_header *tlvh) { struct ri_pce_subtlv_address *top = (struct ri_pce_subtlv_address *) tlvh; if (ntohs (top->address.type) == PCE_ADDRESS_TYPE_IPV4) { if (vty != NULL) vty_out (vty, " PCE Address: %s%s", inet_ntoa (top->address.value), VTY_NEWLINE); else zlog_debug (" PCE Address: %s", inet_ntoa (top->address.value)); } else { /* TODO: Add support to IPv6 with inet_ntop() */ if (vty != NULL) vty_out (vty, " PCE Address: 0x%x%s", ntohl (top->address.value.s_addr), VTY_NEWLINE); else zlog_debug (" PCE Address: 0x%x", ntohl (top->address.value.s_addr)); } return RI_TLV_SIZE (tlvh); } static u_int16_t show_vty_pce_subtlv_path_scope (struct vty *vty, struct ri_tlv_header *tlvh) { struct ri_pce_subtlv_path_scope *top = (struct ri_pce_subtlv_path_scope *) tlvh; if (vty != NULL) vty_out (vty, " PCE Path Scope: 0x%x%s", ntohl (top->value), VTY_NEWLINE); else zlog_debug (" PCE Path Scope: 0x%x", ntohl (top->value)); return RI_TLV_SIZE (tlvh); } static u_int16_t show_vty_pce_subtlv_domain (struct vty *vty, struct ri_tlv_header *tlvh) { struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *) tlvh; struct in_addr tmp; if (ntohs (top->type) == PCE_DOMAIN_TYPE_AREA) { tmp.s_addr = top->value; if (vty != NULL) vty_out (vty, " PCE domain Area: %s%s", inet_ntoa (tmp), VTY_NEWLINE); else zlog_debug (" PCE domain Area: %s", inet_ntoa (tmp)); } else { if (vty != NULL) vty_out (vty, " PCE domain AS: %d%s", ntohl (top->value), VTY_NEWLINE); else zlog_debug (" PCE domain AS: %d", ntohl (top->value)); } return RI_TLV_SIZE (tlvh); } static u_int16_t show_vty_pce_subtlv_neighbor (struct vty *vty, struct ri_tlv_header *tlvh) { struct ri_pce_subtlv_neighbor *top = (struct ri_pce_subtlv_neighbor *) tlvh; struct in_addr tmp; if (ntohs (top->type) == PCE_DOMAIN_TYPE_AREA) { tmp.s_addr = top->value; if (vty != NULL) vty_out (vty, " PCE neighbor Area: %s%s", inet_ntoa (tmp), VTY_NEWLINE); else zlog_debug (" PCE neighbor Area: %s", inet_ntoa (tmp)); } else { if (vty != NULL) vty_out (vty, " PCE neighbor AS: %d%s", ntohl (top->value), VTY_NEWLINE); else zlog_debug (" PCE neighbor AS: %d", ntohl (top->value)); } return RI_TLV_SIZE (tlvh); } static u_int16_t show_vty_pce_subtlv_cap_flag (struct vty *vty, struct ri_tlv_header *tlvh) { struct ri_pce_subtlv_cap_flag *top = (struct ri_pce_subtlv_cap_flag *) tlvh; if (vty != NULL) vty_out (vty, " PCE Capabilities Flag: 0x%x%s", ntohl (top->value), VTY_NEWLINE); else zlog_debug (" PCE Capabilities Flag: 0x%x", ntohl (top->value)); return RI_TLV_SIZE (tlvh); } static u_int16_t show_vty_unknown_tlv (struct vty *vty, struct ri_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_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length)); return RI_TLV_SIZE (tlvh); } static u_int16_t show_vty_pce_info (struct vty *vty, struct ri_tlv_header *ri, uint32_t total) { struct ri_tlv_header *tlvh; u_int16_t sum = 0; for (tlvh = ri; sum < total; tlvh = RI_TLV_HDR_NEXT (tlvh)) { switch (ntohs (tlvh->type)) { case RI_PCE_SUBTLV_ADDRESS: sum += show_vty_pce_subtlv_address (vty, tlvh); break; case RI_PCE_SUBTLV_PATH_SCOPE: sum += show_vty_pce_subtlv_path_scope (vty, tlvh); break; case RI_PCE_SUBTLV_DOMAIN: sum += show_vty_pce_subtlv_domain (vty, tlvh); break; case RI_PCE_SUBTLV_NEIGHBOR: sum += show_vty_pce_subtlv_neighbor (vty, tlvh); break; case RI_PCE_SUBTLV_CAP_FLAG: sum += show_vty_pce_subtlv_cap_flag (vty, tlvh); break; default: sum += show_vty_unknown_tlv (vty, tlvh); break; } } return sum; } static void ospf_router_info_show_info (struct vty *vty, struct ospf_lsa *lsa) { struct lsa_header *lsah = (struct lsa_header *) lsa->data; struct ri_tlv_header *tlvh; u_int16_t length = 0, sum = 0; /* Initialize TLV browsing */ length = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE; for (tlvh = RI_TLV_HDR_TOP (lsah); sum < length; tlvh = RI_TLV_HDR_NEXT (tlvh)) { switch (ntohs (tlvh->type)) { case RI_TLV_CAPABILITIES: sum += show_vty_router_cap (vty, tlvh); break; case RI_TLV_PCE: tlvh++; sum += RI_TLV_HDR_SIZE; sum += show_vty_pce_info (vty, tlvh, length - sum); break; default: sum += show_vty_unknown_tlv (vty, tlvh); break; } } return; } static void ospf_router_info_config_write_router (struct vty *vty) { struct ospf_pce_info *pce = &OspfRI.pce_info; struct listnode *node; struct ri_pce_subtlv_domain *domain; struct ri_pce_subtlv_neighbor *neighbor; struct in_addr tmp; if (OspfRI.status == enabled) { if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) vty_out (vty, " router-info as%s", VTY_NEWLINE); else vty_out (vty, " router-info area %s%s", inet_ntoa (OspfRI.area_id), VTY_NEWLINE); if (pce->pce_address.header.type != 0) vty_out (vty, " pce address %s%s", inet_ntoa (pce->pce_address.address.value), VTY_NEWLINE); if (pce->pce_cap_flag.header.type != 0) vty_out (vty, " pce flag 0x%x%s", ntohl (pce->pce_cap_flag.value), VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) { if (domain->header.type != 0) { if (domain->type == PCE_DOMAIN_TYPE_AREA) { tmp.s_addr = domain->value; vty_out (vty, " pce domain area %s%s", inet_ntoa (tmp), VTY_NEWLINE); } else { vty_out (vty, " pce domain as %d%s", ntohl (domain->value), VTY_NEWLINE); } } } for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) { if (neighbor->header.type != 0) { if (neighbor->type == PCE_DOMAIN_TYPE_AREA) { tmp.s_addr = neighbor->value; vty_out (vty, " pce neighbor area %s%s", inet_ntoa (tmp), VTY_NEWLINE); } else { vty_out (vty, " pce neighbor as %d%s", ntohl (neighbor->value), VTY_NEWLINE); } } } if (pce->pce_scope.header.type != 0) vty_out (vty, " pce scope 0x%x%s", ntohl (OspfRI.pce_info.pce_scope.value), VTY_NEWLINE); } return; } /*------------------------------------------------------------------------* * Followings are vty command functions. *------------------------------------------------------------------------*/ DEFUN (router_info, router_info_area_cmd, "router-info area A.B.C.D", OSPF_RI_STR "Enable the Router Information functionality with Area flooding scope\n" "OSPF area ID in IP format") { u_int8_t scope; if (OspfRI.status == enabled) return CMD_SUCCESS; /* Check and get Area value if present */ if (argc == 1) { if (!inet_aton (argv[0], &OspfRI.area_id)) { vty_out (vty, "Please specify Router Info Area by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } scope = OSPF_OPAQUE_AREA_LSA; } else { OspfRI.area_id.s_addr = 0; scope = OSPF_OPAQUE_AS_LSA; } /* First start to register Router Information callbacks */ if ((ospf_router_info_register (scope)) != 0) { zlog_warn ("Enable to register Router Information callbacks. Abort!"); return CMD_WARNING; } OspfRI.status = enabled; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("RI-> Router Information (%s flooding): OFF -> ON", OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS"); /* * Following code is intended to handle two cases; * * 1) Router Information was disabled at startup time, but now become enabled. * 2) Router Information was once enabled then disabled, and now enabled again. */ initialize_params (&OspfRI); /* Refresh RI LSA if already engaged */ if (OspfRI.flags & RIFLG_LSA_ENGAGED) { zlog_debug ("RI-> Initial origination following configuration"); ospf_router_info_lsa_schedule (REORIGINATE_THIS_LSA); } return CMD_SUCCESS; } ALIAS (router_info, router_info_as_cmd, "router-info as", OSPF_RI_STR "Enable the Router Information functionality with AS flooding scope\n") DEFUN (no_router_info, no_router_info_cmd, "no router-info", NO_STR "Disable the Router Information functionality\n") { if (OspfRI.status == disabled) return CMD_SUCCESS; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("RI-> Router Information: ON -> OFF"); if (OspfRI.flags & RIFLG_LSA_ENGAGED) ospf_router_info_lsa_schedule (FLUSH_THIS_LSA); /* Unregister the callbacks */ ospf_router_info_unregister (); OspfRI.status = disabled; return CMD_SUCCESS; } DEFUN (pce_address, pce_address_cmd, "pce address A.B.C.D", PCE_STR "Stable IP address of the PCE\n" "PCE address in IPv4 address format\n") { struct in_addr value; struct ospf_pce_info *pi = &OspfRI.pce_info; if (!inet_aton (argv[0], &value)) { vty_out (vty, "Please specify PCE Address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } if (ntohs (pi->pce_address.header.type) == 0 || ntohl (pi->pce_address.address.value.s_addr) != ntohl (value.s_addr)) { set_pce_address (value, pi); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); } return CMD_SUCCESS; } DEFUN (no_pce_address, no_pce_address_cmd, "no pce address", NO_STR PCE_STR "Disable PCE address\n") { unset_param (&OspfRI.pce_info.pce_address.header); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); return CMD_SUCCESS; } DEFUN (pce_path_scope, pce_path_scope_cmd, "pce scope BITPATTERN", PCE_STR "Path scope visibilities of the PCE for path computation\n" "32-bit Hexadecimal value\n") { uint32_t scope; struct ospf_pce_info *pi = &OspfRI.pce_info; if (sscanf (argv[0], "0x%x", &scope) != 1) { vty_out (vty, "pce_path_scope: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohl (pi->pce_scope.header.type) == 0 || scope != pi->pce_scope.value) { set_pce_path_scope (scope, pi); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); } return CMD_SUCCESS; } DEFUN (no_pce_path_scope, no_pce_path_scope_cmd, "no pce scope", NO_STR PCE_STR "Disable PCE path scope\n") { unset_param (&OspfRI.pce_info.pce_address.header); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); return CMD_SUCCESS; } DEFUN (pce_domain, pce_domain_cmd, "pce domain as <0-65535>", PCE_STR "Configure PCE domain AS number\n" "AS number where the PCE as visibilities for path computation\n" "AS number in decimal <0-65535>\n") { uint32_t as; struct ospf_pce_info *pce = &OspfRI.pce_info; struct listnode *node; struct ri_pce_subtlv_domain *domain; if (sscanf (argv[0], "%d", &as) != 1) { vty_out (vty, "pce_domain: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Check if the domain is not already in the domain list */ for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) { if (ntohl (domain->header.type) == 0 && as == domain->value) goto out; } /* Create new domain if not found */ set_pce_domain (PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); out:return CMD_SUCCESS; } DEFUN (no_pce_domain, no_pce_domain_cmd, "no pce domain as <0-65535>", NO_STR PCE_STR "Disable PCE domain AS number\n" "AS number where the PCE as visibilities for path computation\n" "AS number in decimal <0-65535>\n") { uint32_t as; struct ospf_pce_info *pce = &OspfRI.pce_info; if (sscanf (argv[0], "%d", &as) != 1) { vty_out (vty, "no_pce_domain: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Unset corresponding PCE domain */ unset_pce_domain (PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); return CMD_SUCCESS; } DEFUN (pce_neigbhor, pce_neighbor_cmd, "pce neighbor as <0-65535>", PCE_STR "Configure PCE neighbor domain AS number\n" "AS number of PCE neighbors\n" "AS number in decimal <0-65535>\n") { uint32_t as; struct ospf_pce_info *pce = &OspfRI.pce_info; struct listnode *node; struct ri_pce_subtlv_neighbor *neighbor; if (sscanf (argv[0], "%d", &as) != 1) { vty_out (vty, "pce_neighbor: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Check if the domain is not already in the domain list */ for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) { if (ntohl (neighbor->header.type) == 0 && as == neighbor->value) goto out; } /* Create new domain if not found */ set_pce_neighbor (PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); out:return CMD_SUCCESS; } DEFUN (no_pce_neighbor, no_pce_neighbor_cmd, "no pce neighbor as <0-65535>", NO_STR PCE_STR "Disable PCE neighbor AS number\n" "AS number of PCE neighbor\n" "AS number in decimal <0-65535>\n") { uint32_t as; struct ospf_pce_info *pce = &OspfRI.pce_info; if (sscanf (argv[0], "%d", &as) != 1) { vty_out (vty, "no_pce_neighbor: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Unset corresponding PCE domain */ unset_pce_neighbor (PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); return CMD_SUCCESS; } DEFUN (pce_cap_flag, pce_cap_flag_cmd, "pce flag BITPATTERN", PCE_STR "Capabilities of the PCE for path computation\n" "32-bit Hexadecimal value\n") { uint32_t cap; struct ospf_pce_info *pce = &OspfRI.pce_info; if (sscanf (argv[0], "0x%x", &cap) != 1) { vty_out (vty, "pce_cap_flag: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohl (pce->pce_cap_flag.header.type) == 0 || cap != pce->pce_cap_flag.value) { set_pce_cap_flag (cap, pce); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); } return CMD_SUCCESS; } DEFUN (no_pce_cap_flag, no_pce_cap_flag_cmd, "no pce flag", NO_STR PCE_STR "Disable PCE capabilities\n") { unset_param (&OspfRI.pce_info.pce_cap_flag.header); /* Refresh RI LSA if already engaged */ if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); return CMD_SUCCESS; } DEFUN (show_ip_ospf_router_info, show_ip_ospf_router_info_cmd, "show ip ospf router-info", SHOW_STR IP_STR OSPF_STR "Router Information\n") { if (OspfRI.status == enabled) { vty_out (vty, "--- Router Information parameters ---%s", VTY_NEWLINE); show_vty_router_cap (vty, &OspfRI.router_cap.header); } else { if (vty != NULL) vty_out (vty, " Router Information is disabled on this router%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (show_ip_opsf_router_info_pce, show_ip_ospf_router_info_pce_cmd, "show ip ospf router-info pce", SHOW_STR IP_STR OSPF_STR "Router Information\n" "PCE information\n") { struct ospf_pce_info *pce = &OspfRI.pce_info; struct listnode *node; struct ri_pce_subtlv_domain *domain; struct ri_pce_subtlv_neighbor *neighbor; if (OspfRI.status == enabled) { vty_out (vty, "--- PCE parameters ---%s", VTY_NEWLINE); if (pce->pce_address.header.type != 0) show_vty_pce_subtlv_address (vty, &pce->pce_address.header); if (pce->pce_scope.header.type != 0) show_vty_pce_subtlv_path_scope (vty, &pce->pce_scope.header); for (ALL_LIST_ELEMENTS_RO (pce->pce_domain, node, domain)) { if (domain->header.type != 0) show_vty_pce_subtlv_domain (vty, &domain->header); } for (ALL_LIST_ELEMENTS_RO (pce->pce_neighbor, node, neighbor)) { if (neighbor->header.type != 0) show_vty_pce_subtlv_neighbor (vty, &neighbor->header); } if (pce->pce_cap_flag.header.type != 0) show_vty_pce_subtlv_cap_flag (vty, &pce->pce_cap_flag.header); } else { vty_out (vty, " Router Information is disabled on this router%s", VTY_NEWLINE); } return CMD_SUCCESS; } /* Install new CLI commands */ static void ospf_router_info_register_vty (void) { install_element (VIEW_NODE, &show_ip_ospf_router_info_cmd); install_element (VIEW_NODE, &show_ip_ospf_router_info_pce_cmd); install_element (OSPF_NODE, &router_info_area_cmd); install_element (OSPF_NODE, &router_info_as_cmd); install_element (OSPF_NODE, &no_router_info_cmd); install_element (OSPF_NODE, &pce_address_cmd); install_element (OSPF_NODE, &pce_path_scope_cmd); install_element (OSPF_NODE, &pce_domain_cmd); install_element (OSPF_NODE, &no_pce_domain_cmd); install_element (OSPF_NODE, &pce_neighbor_cmd); install_element (OSPF_NODE, &no_pce_neighbor_cmd); install_element (OSPF_NODE, &pce_cap_flag_cmd); return; } quagga-1.2.4/ospfd/ospf_ri.h000066400000000000000000000137051325323223500157160ustar00rootroot00000000000000/* * This is an implementation of RFC4970 Router Information * with support of RFC5088 PCE Capabilites announcement * * Module name: Router Information * Version: 0.99.22 * Created: 2012-02-01 by Olivier Dugeon * Copyright (C) 2012 Orange Labs http://www.orange.com/ * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_ROUTER_INFO_H #define _ZEBRA_OSPF_ROUTER_INFO_H /* * Opaque LSA's link state ID for Router Information is * structured as follows. * * 24 16 8 0 * +--------+--------+--------+--------+ * | 1 | MBZ |........|........| * +--------+--------+--------+--------+ * |<-Type->||<-- Instance --->| * * * Type: IANA has assigned '4' for Router Information. * MBZ: Reserved, must be set to zero. * Instance: User may select an arbitrary 16-bit value. * */ /* * 24 16 8 0 * +--------+--------+--------+--------+ --- * | LS age |Options | 9,10,11| A * +--------+--------+--------+--------+ | * | 4 | 0 | Instance | | * +--------+--------+--------+--------+ | * | Advertising router | | Standard (Opaque) LSA header; * +--------+--------+--------+--------+ | Type 9,10 or 11 are used. * | LS sequence number | | * +--------+--------+--------+--------+ | * | LS checksum | Length | V * +--------+--------+--------+--------+ --- * | Type | Length | A * +--------+--------+--------+--------+ | TLV part for Router Information; Values might be * | Values ... | V structured as a set of sub-TLVs. * +--------+--------+--------+--------+ --- */ /* * Following section defines TLV (tag, length, value) structures, * used for Router Information. */ struct ri_tlv_header { u_int16_t type; /* RI_TLV_XXX (see below) */ u_int16_t length; /* Value portion only, in byte */ }; #define RI_TLV_HDR_SIZE (sizeof (struct ri_tlv_header)) #define RI_TLV_BODY_SIZE(tlvh) (ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t))) #define RI_TLV_SIZE(tlvh) (RI_TLV_HDR_SIZE + RI_TLV_BODY_SIZE(tlvh)) #define RI_TLV_HDR_TOP(lsah) (struct ri_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) #define RI_TLV_HDR_NEXT(tlvh) (struct ri_tlv_header *)((char *)(tlvh) + RI_TLV_SIZE(tlvh)) /* * Following section defines TLV body parts. */ /* Up to now, 8 code point have been assigned to Router Information */ /* Only type 1 Router Capabilities and 6 PCE are supported with this code */ #define RI_IANA_MAX_TYPE 8 /* RFC4970: Router Information Capabilities TLV */ /* Mandatory */ #define RI_TLV_CAPABILITIES 1 struct ri_tlv_router_cap { struct ri_tlv_header header; /* Value length is 4 bytes. */ u_int32_t value; }; #define RI_GRACE_RESTART 0x01 #define RI_GRACE_HELPER 0x02 #define RI_STUB_SUPPORT 0x04 #define RI_TE_SUPPORT 0x08 #define RI_P2P_OVER_LAN 0x10 #define RI_TE_EXPERIMENTAL 0x20 #define RI_TLV_LENGTH 4 /* RFC5088: PCE Capabilities TLV */ /* Optional */ /* RI PCE TLV */ #define RI_TLV_PCE 6 struct ri_tlv_pce { struct ri_tlv_header header; /* A set of PCE-sub-TLVs will follow. */ }; /* PCE Address Sub-TLV */ /* Mandatory */ #define RI_PCE_SUBTLV_ADDRESS 1 struct ri_pce_subtlv_address { struct ri_tlv_header header; /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */ #define PCE_ADDRESS_LENGTH_IPV4 8 #define PCE_ADDRESS_LENGTH_IPV6 20 struct { u_int16_t type; /* Address type: 1 = IPv4, 2 = IPv6 */ #define PCE_ADDRESS_TYPE_IPV4 1 #define PCE_ADDRESS_TYPE_IPV6 2 u_int16_t reserved; struct in_addr value; /* PCE address */ } address; }; /* PCE Path-Scope Sub-TLV */ /* Mandatory */ #define RI_PCE_SUBTLV_PATH_SCOPE 2 struct ri_pce_subtlv_path_scope { struct ri_tlv_header header; /* Type = 2; Length = 4 bytes. */ u_int32_t value; /* L, R, Rd, S, Sd, Y, PrefL, PrefR, PrefS and PrefY bits see RFC5088 page 9 */ }; /* PCE Domain Sub-TLV */ /* Optional */ #define RI_PCE_SUBTLV_DOMAIN 3 #define PCE_DOMAIN_TYPE_AREA 1 #define PCE_DOMAIN_TYPE_AS 2 struct ri_pce_subtlv_domain { struct ri_tlv_header header; /* Type = 3; Length = 8 bytes. */ u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ u_int16_t reserved; u_int32_t value; }; /* PCE Neighbor Sub-TLV */ /* Mandatory if R or S bit is set */ #define RI_PCE_SUBTLV_NEIGHBOR 4 struct ri_pce_subtlv_neighbor { struct ri_tlv_header header; /* Type = 4; Length = 8 bytes. */ u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ u_int16_t reserved; u_int32_t value; }; /* PCE Capabilities Flags Sub-TLV */ /* Optional */ #define RI_PCE_SUBTLV_CAP_FLAG 5 #define PCE_CAP_GMPLS_LINK 0x0001 #define PCE_CAP_BIDIRECTIONAL 0x0002 #define PCE_CAP_DIVERSE_PATH 0x0004 #define PCE_CAP_LOAD_BALANCE 0x0008 #define PCE_CAP_SYNCHRONIZED 0x0010 #define PCE_CAP_OBJECTIVES 0x0020 #define PCE_CAP_ADDITIVE 0x0040 #define PCE_CAP_PRIORIZATION 0x0080 #define PCE_CAP_MULTIPLE_REQ 0x0100 struct ri_pce_subtlv_cap_flag { struct ri_tlv_header header; /* Type = 5; Length = n x 4 bytes. */ u_int32_t value; }; /* Prototypes. */ extern int ospf_router_info_init (void); extern void ospf_router_info_term (void); #endif /* _ZEBRA_OSPF_ROUTER_INFO_H */ quagga-1.2.4/ospfd/ospf_route.c000066400000000000000000000657461325323223500164510ustar00rootroot00000000000000/* * 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 = quagga_time (NULL); new->mtime = new->ctime; new->paths = list_new (); new->paths->del = (void (*) (void *))ospf_path_free; return new; } void ospf_route_free (struct ospf_route *or) { if (or->paths) list_delete (or->paths); 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; } static 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 exists in the new routing table, then return 1, otherwise return 0. Since the ZEBRA-RIB does an implicit withdraw, it is not necessary to send a delete, an add later will act like an implicit delete. */ static int ospf_route_exist_new_table (struct route_table *rt, struct prefix_ipv4 *prefix) { struct route_node *rn; assert (rt); assert (prefix); rn = route_node_lookup (rt, (struct prefix *) prefix); if (!rn) { return 0; } route_unlock_node (rn); if (!rn->info) { return 0; } return 1; } /* 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; struct listnode *n1; struct 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->paths->count != newor->paths->count) return 0; /* Check each path. */ for (n1 = listhead (or->paths), n2 = listhead (newor->paths); n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2)) { op = listgetdata (n1); newop = listgetdata (n2); if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) return 0; if (op->ifindex != newop->ifindex) return 0; } return 1; } else if (prefix_same (&rn->p, (struct prefix *) prefix)) return 1; } return 0; } /* delete routes generated from AS-External routes if there is a inter/intra * area route */ static void ospf_route_delete_same_ext(struct route_table *external_routes, struct route_table *routes) { struct route_node *rn, *ext_rn; if ( (external_routes == NULL) || (routes == NULL) ) return; /* Remove deleted routes */ for ( rn = route_top (routes); rn; rn = route_next (rn) ) { if (rn && rn->info) { struct prefix_ipv4 *p = (struct prefix_ipv4 *)(&rn->p); if ( (ext_rn = route_node_lookup (external_routes, (struct prefix *)p)) ) { if (ext_rn->info) { ospf_zebra_delete (p, ext_rn->info); ospf_route_free( ext_rn->info); ext_rn->info = NULL; } route_unlock_node (ext_rn); } } } } /* rt: Old, cmprt: New */ static 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_exist_new_table (cmprt, (struct prefix_ipv4 *) &rn->p)) ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); } else if (or->type == OSPF_DESTINATION_DISCARD) if (! ospf_route_exist_new_table (cmprt, (struct prefix_ipv4 *) &rn->p)) 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); if (ospf->old_external_route) ospf_route_delete_same_ext (ospf->old_external_route, 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); } } /* 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_debug ("ospf_intra_add_router: Start"); lsa = (struct router_lsa *) v->lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_router: LS ID: %s", inet_ntoa (lsa->header.id)); if (!OSPF_IS_AREA_BACKBONE(area)) 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_debug ("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; or->u.std.external_routing = area->external_routing; 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_debug ("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); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_router: Stop"); } /* 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; or->u.std.external_routing = area->external_routing; 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, int parent_is_root, int lsa_pos) { 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_debug ("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_debug ("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_debug ("ospf_intra_add_stub(): calculated cost is %d + %d = %d", v->distance, ntohs(link->m[0].metric), cost); /* PtP links with /32 masks adds host routes to remote, directly * connected hosts, see RFC 2328, 12.4.1.1, Option 1. * Such routes can just be ignored for the sake of tidyness. */ if (parent_is_root && link->link_data.s_addr == 0xffffffff && ospf_if_lookup_by_local_addr (area->ospf, NULL, link->link_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: ignoring host route %s/32 to self.", __func__, inet_ntoa (link->link_id)); return; } 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_debug ("ospf_intra_add_stub(): " "another route to the same prefix found with cost %u", cur_or->cost); /* 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_debug ("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_debug ("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_debug ("ospf_intra_add_stub(): new route is better, set it"); cur_or->cost = cost; list_delete_all_node (cur_or->paths); 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_debug ("ospf_intra_add_stub(): installing new route"); or = ospf_route_new (); or->id = v->id; or->u.std.area_id = area->area_id; or->u.std.external_routing = area->external_routing; or->path_type = OSPF_PATH_INTRA_AREA; or->cost = cost; or->type = OSPF_DESTINATION_NETWORK; or->u.std.origin = (struct lsa_header *) lsa; /* Nexthop is depend on connection type. */ if (v != area->spf) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("ospf_intra_add_stub(): this network is on this router"); if ((oi = ospf_if_lookup_by_lsa_pos (area, lsa_pos))) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): the interface is %s", IF_NAME (oi)); path = ospf_path_new (); path->nexthop.s_addr = 0; path->ifindex = oi->ifp->ifindex; listnode_add (or->paths, path); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): where's the interface ?"); } } rn->info = or; if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_intra_add_stub(): Stop"); } const 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]; struct listnode *pnode; struct ospf_path *path; #if 0 zlog_debug ("Type Dest Area Path Type Cost Next Adv."); zlog_debug (" Hop(s) Router(s)"); #endif /* 0 */ zlog_debug ("========== 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_debug ("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 (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path)) zlog_debug (" -> %s", inet_ntoa (path->nexthop)); } else zlog_debug ("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_debug ("========================================"); } /* 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. */ static 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; /* 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_debug ("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); } static int ospf_path_exist (struct list *plist, struct in_addr nexthop, struct ospf_interface *oi) { struct listnode *node, *nnode; struct ospf_path *path; for (ALL_LIST_ELEMENTS (plist, node, nnode, path)) if (IPV4_ADDR_SAME (&path->nexthop, &nexthop) && path->ifindex == oi->ifp->ifindex) return 1; return 0; } void ospf_route_copy_nexthops_from_vertex (struct ospf_route *to, struct vertex *v) { struct listnode *node; struct ospf_path *path; struct vertex_nexthop *nexthop; struct vertex_parent *vp; assert (to->paths); for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { nexthop = vp->nexthop; if (nexthop->oi != NULL) { if (! ospf_path_exist (to->paths, nexthop->router, nexthop->oi)) { path = ospf_path_new (); path->nexthop = nexthop->router; path->ifindex = nexthop->oi->ifp->ifindex; listnode_add (to->paths, path); } } } } struct ospf_path * ospf_path_lookup (struct list *plist, struct ospf_path *path) { struct listnode *node; struct ospf_path *op; for (ALL_LIST_ELEMENTS_RO (plist, node, op)) { if (!IPV4_ADDR_SAME (&op->nexthop, &path->nexthop)) continue; if (!IPV4_ADDR_SAME (&op->adv_router, &path->adv_router)) continue; if (op->ifindex != path->ifindex) continue; return op; } return NULL; } void ospf_route_copy_nexthops (struct ospf_route *to, struct list *from) { struct listnode *node, *nnode; struct ospf_path *path; assert (to->paths); for (ALL_LIST_ELEMENTS (from, node, nnode, path)) /* The same routes are just discarded. */ if (!ospf_path_lookup (to->paths, path)) listnode_add (to->paths, ospf_path_dup (path)); } void ospf_route_subst_nexthops (struct ospf_route *to, struct list *from) { list_delete_all_node (to->paths); 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->paths); 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->paths); if (rn->info) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("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->paths) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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; struct listnode *node, *nnode; struct list *paths; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Pruning unreachable routers"); for (rn = route_top (rtrs); rn; rn = next) { next = route_next (rn); if ((paths = rn->info) == NULL) continue; for (ALL_LIST_ELEMENTS (paths, node, nnode, or)) { if (listcount (or->paths) == 0) { if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("Pruning route to rtr %s", inet_ntoa (rn->p.u.prefix4)); zlog_debug (" 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_debug ("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_debug ("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_debug ("ospf_add_discard_route(): " "an intra-area route exists"); return 0; } if (or->type == OSPF_DESTINATION_DISCARD) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_add_discard_route(): " "discard entry already installed"); return 0; } ospf_route_free (rn->info); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_add_discard_route(): " "adding %s/%d", inet_ntoa (p->prefix), p->prefixlen); 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; new_or->u.std.external_routing = area->external_routing; 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 route_table *rt, struct prefix_ipv4 *p) { struct route_node *rn; struct ospf_route *or; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_delete_discard_route(): " "deleting %s/%d", inet_ntoa (p->prefix), p->prefixlen); rn = route_node_lookup (rt, (struct prefix*)p); if (rn == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_delete_discard_route(): no route found"); return; } or = rn->info; if (or->path_type == OSPF_PATH_INTRA_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_delete_discard_route(): " "an intra-area route exists"); return; } if (or->type != OSPF_DESTINATION_DISCARD) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_delete_discard_route(): " "not a discard entry"); return; } /* free the route entry and the route node */ ospf_route_free (rn->info); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); /* remove the discard entry from the rib */ ospf_zebra_delete_discard(p); return; } quagga-1.2.4/ospfd/ospf_route.h000066400000000000000000000112241325323223500164340ustar00rootroot00000000000000/* * 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; ifindex_t ifindex; }; /* 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 */ /* Area Type */ int external_routing; /* 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. */ struct list *paths; /* Link State Cost. */ u_int32_t cost; /* i.e. metric. */ /* Route specific info. */ union { struct route_standard std; struct route_external ext; } u; }; extern struct ospf_path *ospf_path_new (void); extern void ospf_path_free (struct ospf_path *); extern struct ospf_path *ospf_path_lookup (struct list *, struct ospf_path *); extern struct ospf_route *ospf_route_new (void); extern void ospf_route_free (struct ospf_route *); extern void ospf_route_delete (struct route_table *); extern void ospf_route_table_free (struct route_table *); extern void ospf_route_install (struct ospf *, struct route_table *); extern void ospf_route_table_dump (struct route_table *); extern void ospf_intra_add_router (struct route_table *, struct vertex *, struct ospf_area *); extern void ospf_intra_add_transit (struct route_table *, struct vertex *, struct ospf_area *); extern void ospf_intra_add_stub (struct route_table *, struct router_lsa_link *, struct vertex *, struct ospf_area *, int parent_is_root, int); extern int ospf_route_cmp (struct ospf *, struct ospf_route *, struct ospf_route *); extern void ospf_route_copy_nexthops (struct ospf_route *, struct list *); extern void ospf_route_copy_nexthops_from_vertex (struct ospf_route *, struct vertex *); extern void ospf_route_subst (struct route_node *, struct ospf_route *, struct ospf_route *); extern void ospf_route_add (struct route_table *, struct prefix_ipv4 *, struct ospf_route *, struct ospf_route *); extern void ospf_route_subst_nexthops (struct ospf_route *, struct list *); extern void ospf_prune_unreachable_networks (struct route_table *); extern void ospf_prune_unreachable_routers (struct route_table *); extern int ospf_add_discard_route (struct route_table *, struct ospf_area *, struct prefix_ipv4 *); extern void ospf_delete_discard_route (struct route_table *, struct prefix_ipv4 *); extern int ospf_route_match_same (struct route_table *, struct prefix_ipv4 *, struct ospf_route *); #endif /* _ZEBRA_OSPF_ROUTE_H */ quagga-1.2.4/ospfd/ospf_routemap.c000066400000000000000000000613121325323223500171300ustar00rootroot00000000000000/* * 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. */ static void ospf_route_map_update (const 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); } } } static void ospf_route_map_event (route_map_event_t event, const 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. */ static int ospf_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ospf_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ospf_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete rip route map rule. */ static int ospf_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% OSPF Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% OSPF Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* `match ip netxthop ' */ /* Match function return 1 if match is success else return zero. */ static 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. */ static void * route_match_ip_nexthop_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static 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' */ static 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; } static void * route_match_ip_next_hop_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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. */ static 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. */ static void * route_match_ip_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static 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' */ static 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; } static void * route_match_ip_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static 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. */ static 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. */ static void * route_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `interface' value. */ static 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 }; /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; struct external_info *ei; if (type == RMAP_OSPF) { tag = rule; ei = object; return ((ei->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH); } return RMAP_NOMATCH; } /* Route map commands for tag matching. */ static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_map_rule_tag_compile, route_map_rule_tag_free, }; /* `set metric METRIC' */ /* Set metric to attribute. */ static 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. */ static void * route_set_metric_compile (const char *arg) { u_int32_t *metric; int32_t ret; /* OSPF doesn't support the +/- in set metric <+/-metric> check Ignore the +/- component */ if (! all_digit (arg)) { if ((strncmp (arg, "+", 1) == 0 || strncmp (arg, "-", 1) == 0) && all_digit (arg+1)) { zlog_warn ("OSPF does not support 'set metric +/-'"); arg++; } else return NULL; } metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); ret = atoi (arg); if (ret >= 0) { *metric = (u_int32_t)ret; return metric; } XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); return NULL; } /* Free route map's compiled `set metric' value. */ static 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. */ static 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. */ static void * route_set_metric_type_compile (const 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. */ static 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, }; static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; struct external_info *ei; if (type == RMAP_OSPF) { tag = rule; ei = object; /* Set tag value */ ei->tag=*tag; } return RMAP_OKAY; } /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, route_map_rule_tag_compile, route_map_rule_tag_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 (match_tag, match_tag_cmd, "match tag <1-4294967295>", MATCH_STR "Match tag of route\n" "Tag value\n") { return ospf_route_match_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_match_tag, no_match_tag_cmd, "no match tag", NO_STR MATCH_STR "Match tag of route\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "tag", NULL); return ospf_route_match_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_match_tag, no_match_tag_val_cmd, "no match tag <1-4294967295>", NO_STR MATCH_STR "Match tag of route\n" "Tag value\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[6] external type 1 metric\n" "OSPF[6] 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[6] external type 1 metric\n" "OSPF[6] external type 2 metric\n") DEFUN (set_tag, set_tag_cmd, "set tag <1-4294967295>", SET_STR "Tag value for routing protocol\n" "Tag value\n") { return ospf_route_set_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_set_tag, no_set_tag_cmd, "no set tag", NO_STR SET_STR "Tag value for routing protocol\n") { if (argc == 0) ospf_route_set_delete(vty, vty->index, "tag", NULL); return ospf_route_set_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_set_tag, no_set_tag_val_cmd, "no set tag <1-4294967295>", NO_STR SET_STR "Tag value for routing protocol\n" "Tag value\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_match (&route_match_tag_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_metric_type_cmd); route_map_install_set (&route_set_tag_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, &match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_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); install_element (RMAP_NODE, &set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_val_cmd); } quagga-1.2.4/ospfd/ospf_snmp.c000066400000000000000000002164711325323223500162610ustar00rootroot00000000000000/* OSPFv2 SNMP support * Copyright (C) 2005 6WIND * 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 #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" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_snmp.h" /* OSPF2-MIB. */ #define OSPF2MIB 1,3,6,1,2,1,14 /* 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 ospf_trap_oid [] = { OSPF2MIB, 16, 2 }; /* Not reverse mappable! */ /* IP address 0.0.0.0. */ static struct in_addr ospf_empty_addr = { .s_addr = 0 }; /* Hook functions. */ static u_char *ospfGeneralGroup (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfAreaEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfStubAreaEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfLsdbEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfAreaRangeEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfHostEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfIfEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfIfMetricEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfVirtIfEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfNbrEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfVirtNbrEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfExtLsdbEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfAreaAggregateEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); 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. */ static int ospf_admin_stat (struct ospf *ospf) { struct listnode *node; struct ospf_interface *oi; if (ospf == NULL) return 0; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) 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; } static struct ospf_area * ospf_area_lookup_next (struct ospf *ospf, struct in_addr *area_id, int first) { struct ospf_area *area; struct listnode *node; if (ospf == NULL) return NULL; if (first) { node = listhead (ospf->areas); if (node) { area = listgetdata (node); *area_id = area->area_id; return area; } return NULL; } for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr)) { *area_id = area->area_id; return area; } } return NULL; } static 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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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; } static struct ospf_area * ospf_stub_area_lookup_next (struct in_addr *area_id, int first) { struct ospf_area *area; struct listnode *node; struct ospf *ospf; ospf = ospf_lookup (); if (ospf == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { 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; } static 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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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; } static 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; /* Sanity check, if LSA type unknwon merley skip any LSA */ if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) { zlog_debug("Strange request with LSA type %d\n", i); return NULL; } 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; } static 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 > (int)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, 1); if (area == NULL) return NULL; do { /* Next we lookup type. */ offset += len; offsetlen -= len; 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 > (int)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 > (int)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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* 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; } static 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 > (int)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 > (int)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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* 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; } static 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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* 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; ifindex_t ifindex; struct interface *ifp; }; static struct ospf_snmp_if * ospf_snmp_if_new (void) { return XCALLOC (MTYPE_TMP, sizeof (struct ospf_snmp_if)); } static void ospf_snmp_if_free (struct ospf_snmp_if *osif) { XFREE (MTYPE_TMP, osif); } void ospf_snmp_if_delete (struct interface *ifp) { struct listnode *node, *nnode; struct ospf_snmp_if *osif; for (ALL_LIST_ELEMENTS (ospf_snmp_iflist, node, nnode, osif)) { if (osif->ifp == ifp) { list_delete_node (ospf_snmp_iflist, node); ospf_snmp_if_free (osif); return; } } } void ospf_snmp_if_update (struct interface *ifp) { struct listnode *node; struct listnode *pn; struct connected *ifc; struct prefix *p; struct ospf_snmp_if *osif; struct in_addr *addr; ifindex_t ifindex; ospf_snmp_if_delete (ifp); p = NULL; addr = NULL; ifindex = 0; /* Lookup first IPv4 address entry. */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) { p = CONNECTED_ID(ifc); if (p->family == AF_INET) { addr = &p->u.prefix4; break; } } if (! addr) ifindex = ifp->ifindex; /* Add interface to the list. */ pn = NULL; for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, node, osif)) { if (addr) { /* Usual interfaces --> Sort them based on interface IPv4 addresses */ if (ntohl (osif->addr.s_addr) > ntohl (addr->s_addr)) break; } else { /* Unnumbered interfaces --> Sort them based on interface indexes */ if (osif->addr.s_addr != 0 || osif->ifindex > ifindex) break; } pn = node; } osif = ospf_snmp_if_new (); if (addr) /* Usual interface */ { osif->addr = *addr; /* This field is used for storing ospfAddressLessIf OID value, * conform to RFC1850 OSPF-MIB specification, it must be 0 for * usual interface */ osif->ifindex = 0; } else /* Unnumbered interface */ osif->ifindex = ifindex; osif->ifp = ifp; listnode_add_after (ospf_snmp_iflist, pn, osif); } static int ospf_snmp_is_if_have_addr (struct interface *ifp) { struct listnode *nn; struct connected *ifc; /* Is this interface having any connected IPv4 address ? */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, ifc)) { if (CONNECTED_PREFIX(ifc)->family == AF_INET) return 1; } return 0; } static struct ospf_interface * ospf_snmp_if_lookup (struct in_addr *ifaddr, ifindex_t *ifindex) { struct listnode *node; struct ospf_snmp_if *osif; struct ospf_interface *oi = NULL; struct ospf *ospf = ospf_lookup (); for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, node, osif)) { if (ifaddr->s_addr) { if (IPV4_ADDR_SAME (&osif->addr, ifaddr)) oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); } else { if (osif->ifindex == *ifindex) oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); } } return oi; } static struct ospf_interface * ospf_snmp_if_lookup_next (struct in_addr *ifaddr, ifindex_t *ifindex, int ifaddr_next, ifindex_t ifindex_next) { struct ospf_snmp_if *osif; struct listnode *nn; struct ospf *ospf = ospf_lookup (); struct ospf_interface *oi = NULL; if (ospf == NULL) return NULL; /* No instance is specified --> Return the first OSPF interface */ if (ifaddr_next) { for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, nn, osif)) { osif = listgetdata (nn); *ifaddr = osif->addr; *ifindex = osif->ifindex; /* Because no instance is specified, we don't care about the kind of * interface (usual or unnumbered), just returning the first valid * OSPF interface */ oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); if (oi) return (oi); } return NULL; } /* An instance is specified --> Return the next OSPF interface */ for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, nn, osif)) { /* Usual interface */ if (ifaddr->s_addr) { /* The interface must have valid AF_INET connected address */ /* it must have lager IPv4 address value than the lookup entry */ if ((ospf_snmp_is_if_have_addr(osif->ifp)) && (ntohl (osif->addr.s_addr) > ntohl (ifaddr->s_addr))) { *ifaddr = osif->addr; *ifindex = osif->ifindex; /* and it must be an OSPF interface */ oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); if (oi) return oi; } } /* Unnumbered interface */ else /* The interface must NOT have valid AF_INET connected address */ /* it must have lager interface index than the lookup entry */ if ((!ospf_snmp_is_if_have_addr(osif->ifp)) && (osif->ifindex > *ifindex)) { *ifaddr = osif->addr; *ifindex = osif->ifindex; /* and it must be an OSPF interface */ oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); if (oi) return oi; } } return NULL; } static 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; } static struct ospf_interface * ospfIfLookup (struct variable *v, oid *name, size_t *length, struct in_addr *ifaddr, ifindex_t *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; ifindex_t ifindex_next = 0; struct ospf_interface *oi; 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]; oi = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next, ifindex_next); if (oi) { *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 oi; } } return NULL; } static u_char * ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { ifindex_t ifindex; struct in_addr ifaddr; struct ospf_interface *oi; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; ifindex = 0; memset (&ifaddr, 0, sizeof (struct in_addr)); /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; oi = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact); 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 (oi->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 (ISM_SNMP(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 static struct ospf_interface * ospfIfMetricLookup (struct variable *v, oid *name, size_t *length, struct in_addr *ifaddr, ifindex_t *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; ifindex_t ifindex_next = 0; struct ospf_interface *oi; 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]; oi = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next, ifindex_next); if (oi) { *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 oi; } } 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. */ ifindex_t ifindex; struct in_addr ifaddr; struct ospf_interface *oi; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; ifindex = 0; memset (&ifaddr, 0, sizeof (struct in_addr)); /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; oi = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact); 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); if (rn->info) route_unlock_node (rn); 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); } static 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; } static 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; } static 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; unsigned 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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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; } static struct ospf_neighbor * ospf_snmp_nbr_lookup (struct ospf *ospf, struct in_addr *nbr_addr, ifindex_t *ifindex) { struct listnode *node, *nnode; struct ospf_interface *oi; struct ospf_neighbor *nbr; struct route_node *rn; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL && nbr != oi->nbr_self /* If EXACT match is needed, provide ALL entry found && 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; } static struct ospf_neighbor * ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, ifindex_t *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 (); for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, nn, oi)) { 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; } static struct ospf_neighbor * ospfNbrLookup (struct variable *v, oid *name, size_t *length, struct in_addr *nbr_addr, ifindex_t *ifindex, int exact) { unsigned int len; int first; struct ospf_neighbor *nbr; struct ospf *ospf; ospf = ospf_lookup (); if (! ospf) return NULL; 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; } /* map internal quagga neighbor states to official MIB values: ospfNbrState OBJECT-TYPE SYNTAX INTEGER { down (1), attempt (2), init (3), twoWay (4), exchangeStart (5), exchange (6), loading (7), full (8) } */ static int32_t ospf_snmp_neighbor_state(u_char nst) { switch (nst) { case NSM_Attempt: return 2; case NSM_Init: return 3; case NSM_TwoWay: return 4; case NSM_ExStart: return 5; case NSM_Exchange: return 6; case NSM_Loading: return 7; case NSM_Full: return 8; default: return 1; /* down */ } } 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; ifindex_t ifindex; struct ospf_neighbor *nbr; struct ospf_interface *oi; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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 (ospf_snmp_neighbor_state(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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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; } static 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; unsigned 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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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) { if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* 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; } /* OSPF Traps. */ #define IFSTATECHANGE 16 #define VIRTIFSTATECHANGE 1 #define NBRSTATECHANGE 2 #define VIRTNBRSTATECHANGE 3 struct trap_object ospfNbrTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {10, 1, OSPFNBRIPADDR}}, {3, {10, 1, OSPFNBRRTRID}}, {3, {10, 1, OSPFNBRSTATE}} }; struct trap_object ospfVirtNbrTrapList[] = { {-2, {1, 1}}, {3, {11, 1, OSPFVIRTNBRAREA}}, {3, {11, 1, OSPFVIRTNBRRTRID}}, {3, {11, 1, OSPFVIRTNBRSTATE}} }; struct trap_object ospfIfTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {7, 1, OSPFIFIPADDRESS}}, {3, {7, 1, OSPFADDRESSLESSIF}}, {3, {7, 1, OSPFIFSTATE}} }; struct trap_object ospfVirtIfTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {9, 1, OSPFVIRTIFAREAID}}, {3, {9, 1, OSPFVIRTIFNEIGHBOR}}, {3, {9, 1, OSPFVIRTIFSTATE}} }; void ospfTrapNbrStateChange (struct ospf_neighbor *on) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; char msgbuf[16]; ospf_nbr_state_message(on, msgbuf, sizeof(msgbuf)); zlog (NULL, LOG_INFO, "ospfTrapNbrStateChange trap sent: %s now %s", inet_ntoa(on->address.u.prefix4), msgbuf); oid_copy_addr (index, &(on->address.u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfNbrTrapList, sizeof ospfNbrTrapList / sizeof (struct trap_object), NBRSTATECHANGE); } void ospfTrapVirtNbrStateChange (struct ospf_neighbor *on) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; zlog (NULL, LOG_INFO, "ospfTrapVirtNbrStateChange trap sent"); oid_copy_addr (index, &(on->address.u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfVirtNbrTrapList, sizeof ospfVirtNbrTrapList / sizeof (struct trap_object), VIRTNBRSTATECHANGE); } void ospfTrapIfStateChange (struct ospf_interface *oi) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; zlog (NULL, LOG_INFO, "ospfTrapIfStateChange trap sent: %s now %s", inet_ntoa(oi->address->u.prefix4), LOOKUP(ospf_ism_state_msg, oi->state)); oid_copy_addr (index, &(oi->address->u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfIfTrapList, sizeof ospfIfTrapList / sizeof (struct trap_object), IFSTATECHANGE); } void ospfTrapVirtIfStateChange (struct ospf_interface *oi) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; zlog (NULL, LOG_INFO, "ospfTrapVirtIfStateChange trap sent"); oid_copy_addr (index, &(oi->address->u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfVirtIfTrapList, sizeof ospfVirtIfTrapList / sizeof (struct trap_object), VIRTIFSTATECHANGE); } /* Register OSPF2-MIB. */ void ospf_snmp_init () { ospf_snmp_iflist = list_new (); ospf_snmp_vl_table = route_table_init (); smux_init (om->master); REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid); } #endif /* HAVE_SNMP */ quagga-1.2.4/ospfd/ospf_snmp.h000066400000000000000000000026431325323223500162600ustar00rootroot00000000000000/* 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 extern void ospf_snmp_if_update (struct interface *); extern void ospf_snmp_if_delete (struct interface *); extern void ospf_snmp_vl_add (struct ospf_vl_data *); extern void ospf_snmp_vl_delete (struct ospf_vl_data *); extern void ospfTrapIfStateChange (struct ospf_interface *); extern void ospfTrapVirtIfStateChange (struct ospf_interface *); extern void ospfTrapNbrStateChange (struct ospf_neighbor *); extern void ospfTrapVirtNbrStateChange (struct ospf_neighbor *); #endif /* _ZEBRA_OSPF_SNMP_H */ quagga-1.2.4/ospfd/ospf_spf.c000066400000000000000000001315621325323223500160710ustar00rootroot00000000000000/* 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 "pqueue.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_ase.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_dump.h" /* Variables to ensure a SPF scheduled log message is printed only once */ static unsigned int spf_reason_flags = 0; static void ospf_clear_spf_reason_flags () { spf_reason_flags = 0; } static void ospf_spf_set_reason (ospf_spf_reason_t reason) { spf_reason_flags |= 1 << reason; } static void ospf_get_spf_reason_str (char *buf) { if (!buf) return; buf[0] = '\0'; if (spf_reason_flags) { if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) strcat (buf, "R, "); if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) strcat (buf, "N, "); if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) strcat (buf, "S, "); if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) strcat (buf, "AS, "); if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) strcat (buf, "ABR, "); if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) strcat (buf, "ASBR, "); if (spf_reason_flags & SPF_FLAG_MAXAGE) strcat (buf, "M, "); buf[strlen(buf)-2] = '\0'; /* skip the last ", " */ } } static void ospf_vertex_free (void *); /* List of allocated vertices, to simplify cleanup of SPF. * Not thread-safe obviously. If it ever needs to be, it'd have to be * dynamically allocated at begin of ospf_spf_calculate */ static struct list vertex_list = { .del = ospf_vertex_free }; /* Heap related functions, for the managment of the candidates, to * be used with pqueue. */ static int cmp (void * node1 , void * node2) { struct vertex * v1 = (struct vertex *) node1; struct vertex * v2 = (struct vertex *) node2; if (v1 != NULL && v2 != NULL ) { /* network vertices must be chosen before router vertices of same * cost in order to find all shortest paths */ if ( ((v1->distance - v2->distance) == 0) && (v1->type != v2->type)) { switch (v1->type) { case OSPF_VERTEX_NETWORK: return -1; case OSPF_VERTEX_ROUTER: return 1; } } else return (v1->distance - v2->distance); } return 0; } static void update_stat (void *node , int position) { struct vertex *v = node; /* Set the status of the vertex, when its position changes. */ *(v->stat) = position; } static struct vertex_nexthop * vertex_nexthop_new (void) { return XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop)); } static void vertex_nexthop_free (struct vertex_nexthop *nh) { XFREE (MTYPE_OSPF_NEXTHOP, nh); } /* Free the canonical nexthop objects for an area, ie the nexthop objects * attached to the first-hop router vertices, and any intervening network * vertices. */ static void ospf_canonical_nexthops_free (struct vertex *root) { struct listnode *node, *nnode; struct vertex *child; for (ALL_LIST_ELEMENTS (root->children, node, nnode, child)) { struct listnode *n2, *nn2; struct vertex_parent *vp; /* router vertices through an attached network each * have a distinct (canonical / not inherited) nexthop * which must be freed. * * A network vertex can only have router vertices as its * children, so only one level of recursion is possible. */ if (child->type == OSPF_VERTEX_NETWORK) ospf_canonical_nexthops_free (child); /* Free child nexthops pointing back to this root vertex */ for (ALL_LIST_ELEMENTS (child->parents, n2, nn2, vp)) if (vp->parent == root && vp->nexthop) vertex_nexthop_free (vp->nexthop); } } /* TODO: Parent list should be excised, in favour of maintaining only * vertex_nexthop, with refcounts. */ static struct vertex_parent * vertex_parent_new (struct vertex *v, int backlink, struct vertex_nexthop *hop) { struct vertex_parent *new; new = XMALLOC (MTYPE_OSPF_VERTEX_PARENT, sizeof (struct vertex_parent)); if (new == NULL) return NULL; new->parent = v; new->backlink = backlink; new->nexthop = hop; return new; } static void vertex_parent_free (void *p) { XFREE (MTYPE_OSPF_VERTEX_PARENT, p); } static struct vertex * ospf_vertex_new (struct ospf_lsa *lsa) { struct vertex *new; new = XCALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex)); new->flags = 0; new->stat = &(lsa->stat); new->type = lsa->data->type; new->id = lsa->data->id; new->lsa = lsa->data; new->children = list_new (); new->parents = list_new (); new->parents->del = vertex_parent_free; listnode_add (&vertex_list, new); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: Created %s vertex %s", __func__, new->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", inet_ntoa (new->lsa->id)); return new; } static void ospf_vertex_free (void *data) { struct vertex *v = data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: Free %s vertex %s", __func__, v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", inet_ntoa (v->lsa->id)); /* There should be no parents potentially holding references to this vertex * Children however may still be there, but presumably referenced by other * vertices */ //assert (listcount (v->parents) == 0); if (v->children) list_delete (v->children); v->children = NULL; if (v->parents) list_delete (v->parents); v->parents = NULL; v->lsa = NULL; XFREE (MTYPE_OSPF_VERTEX, v); } static void ospf_vertex_dump(const char *msg, struct vertex *v, int print_parents, int print_children) { if ( ! IS_DEBUG_OSPF_EVENT) return; zlog_debug("%s %s vertex %s distance %u flags %u", msg, v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", inet_ntoa(v->lsa->id), v->distance, (unsigned int)v->flags); if (print_parents) { struct listnode *node; struct vertex_parent *vp; for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { char buf1[BUFSIZ]; if (vp) { zlog_debug ("parent %s backlink %d nexthop %s interface %s", inet_ntoa(vp->parent->lsa->id), vp->backlink, inet_ntop(AF_INET, &vp->nexthop->router, buf1, BUFSIZ), vp->nexthop->oi ? IF_NAME(vp->nexthop->oi) : "NULL"); } } } if (print_children) { struct listnode *cnode; struct vertex *cv; for (ALL_LIST_ELEMENTS_RO (v->children, cnode, cv)) ospf_vertex_dump(" child:", cv, 0, 0); } } /* Add a vertex to the list of children in each of its parents. */ static void ospf_vertex_add_parent (struct vertex *v) { struct vertex_parent *vp; struct listnode *node; assert (v && v->parents); for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { assert (vp->parent && vp->parent->children); /* No need to add two links from the same parent. */ if (listnode_lookup (vp->parent->children, v) == NULL) listnode_add (vp->parent->children, v); } } static 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; } /* return index of link back to V from W, or -1 if no link found */ static int ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) { unsigned int i, 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 -1; 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 i; return -1; } /* 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 i; } 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 i; } break; case LSA_LINK_TYPE_STUB: /* Stub can't lead anywhere, carry on */ continue; default: break; } } } return -1; } /* Find the next link after prev_link from v to w. If prev_link is * NULL, return the first link from v to w. Ignore stub and virtual links; * these link types will never be returned. */ static 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; u_char lsa_type = LSA_LINK_TYPE_TRANSIT; struct router_lsa_link *l; if (w->type == OSPF_VERTEX_ROUTER) lsa_type = LSA_LINK_TYPE_POINTOPOINT; if (prev_link == NULL) p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; else { p = (u_char *) prev_link; p += (OSPF_ROUTER_LSA_LINK_SIZE + (prev_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); } lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); while (p < lim) { l = (struct router_lsa_link *) p; p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); if (l->m[0].type != lsa_type) continue; if (IPV4_ADDR_SAME (&l->link_id, &w->id)) return l; } return NULL; } static void ospf_spf_flush_parents (struct vertex *w) { struct vertex_parent *vp; struct listnode *ln, *nn; /* delete the existing nexthops */ for (ALL_LIST_ELEMENTS (w->parents, ln, nn, vp)) { list_delete_node (w->parents, ln); vertex_parent_free (vp); } } /* * Consider supplied next-hop for inclusion to the supplied list of * equal-cost next-hops, adjust list as neccessary. */ static void ospf_spf_add_parent (struct vertex *v, struct vertex *w, struct vertex_nexthop *newhop, unsigned int distance) { struct vertex_parent *vp, *wp; struct listnode *node; /* we must have a newhop, and a distance */ assert (v && w && newhop); assert (distance); /* IFF w has already been assigned a distance, then we shouldn't get here * unless callers have determined V(l)->W is shortest / equal-shortest * path (0 is a special case distance (no distance yet assigned)). */ if (w->distance) assert (distance <= w->distance); else w->distance = distance; if (IS_DEBUG_OSPF_EVENT) { char buf[2][INET_ADDRSTRLEN]; zlog_debug ("%s: Adding %s as parent of %s", __func__, inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &w->lsa->id, buf[1], sizeof(buf[1]))); } /* Adding parent for a new, better path: flush existing parents from W. */ if (distance < w->distance) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: distance %d better than %d, flushing existing parents", __func__, distance, w->distance); ospf_spf_flush_parents (w); w->distance = distance; } /* new parent is <= existing parents, add it to parent list (if nexthop * not on parent list) */ for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) { if (memcmp(newhop, wp->nexthop, sizeof(*newhop)) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: ... nexthop already on parent list, skipping add", __func__); return; } } vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop); listnode_add (w->parents, vp); return; } /* 16.1.1. Calculate nexthop from root through V (parent) to * vertex W (destination), with given distance from root->W. * * The link must be supplied if V is the root vertex. In all other cases * it may be NULL. * * Note that this function may fail, hence the state of the destination * vertex, W, should /not/ be modified in a dependent manner until * this function returns. This function will update the W vertex with the * provided distance as appropriate. */ static unsigned int ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, struct vertex *w, struct router_lsa_link *l, unsigned int distance, int lsa_pos) { struct listnode *node, *nnode; struct vertex_nexthop *nh; struct vertex_parent *vp; struct ospf_interface *oi = NULL; unsigned int added = 0; char buf1[BUFSIZ]; char buf2[BUFSIZ]; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_nexthop_calculation(): Start"); ospf_vertex_dump("V (parent):", v, 1, 1); ospf_vertex_dump("W (dest) :", w, 1, 1); zlog_debug ("V->W distance: %d", distance); } if (v == area->spf) { /* 16.1.1 para 4. In the first case, the parent vertex (V) is the root (the calculating router itself). This means that the destination is either a directly connected network or directly connected router. The outgoing interface in this case is simply the OSPF interface connecting to the destination network/router. */ /* we *must* be supplied with the link data */ assert (l != NULL); oi = ospf_if_lookup_by_lsa_pos (area, lsa_pos); if (!oi) { zlog_debug("%s: OI not found in LSA: lsa_pos:%d link_id:%s link_data:%s", __func__, lsa_pos, inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); return 0; } if (IS_DEBUG_OSPF_EVENT) { zlog_debug("%s: considering link:%s " "type:%d link_id:%s link_data:%s", __func__, oi->ifp->name, l->m[0].type, inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); } if (w->type == OSPF_VERTEX_ROUTER) { /* l is a link from v to w * l2 will be link from w to v */ struct router_lsa_link *l2 = NULL; if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) { struct in_addr nexthop = { .s_addr = 0 }; /* If the destination is a router which connects to the calculating router via a Point-to-MultiPoint network, the destination's next hop IP address(es) can be determined by examining the destination's router-LSA: each link pointing back to the calculating router and having a Link Data field belonging to the Point-to-MultiPoint network provides an IP address of the next hop router. At this point l is a link from V to W, and V is the root ("us"). If it is a point-to-multipoint interface, then look through the links in the opposite direction (W to V). If any of them have an address that lands within the subnet declared by the PtMP link, then that link is a constituent of the PtMP link, and its address is a nexthop address for V. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) { /* Having nexthop = 0 is tempting, but NOT acceptable. It breaks AS-External routes with a forwarding address, since ospf_ase_complete_direct_routes() will mistakenly assume we've reached the last hop and should place the forwarding address as nexthop. Also, users may configure multi-access links in p2p mode, so we need the IP to ARP the nexthop. */ struct ospf_neighbor *nbr_w; nbr_w = ospf_nbr_lookup_by_routerid (oi->nbrs, &l->link_id); if (nbr_w != NULL) { added = 1; nexthop = nbr_w->src; } } else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { struct prefix_ipv4 la; la.family = AF_INET; la.prefixlen = oi->address->prefixlen; /* V links to W on PtMP interface - find the interface address 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) continue; /* link_data is on our PtMP network */ added = 1; nexthop = l2->link_data; break; } } if (added) { /* found all necessary info to build nexthop */ nh = vertex_nexthop_new (); nh->oi = oi; nh->router = nexthop; ospf_spf_add_parent (v, w, nh, distance); return 1; } else zlog_info("%s: could not determine nexthop for link %s", __func__, oi->ifp->name); } /* end point-to-point link from V to W */ else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) { struct ospf_vl_data *vl_data; /* VLink implementation limitations: * a) vl_data can only reference one nexthop, so no ECMP * to backbone through VLinks. Though transit-area * summaries may be considered, and those can be ECMP. * b) We can only use /one/ VLink, even if multiple ones * exist this router through multiple transit-areas. */ vl_data = ospf_vl_lookup (area->ospf, NULL, l->link_id); if (vl_data && CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED)) { nh = vertex_nexthop_new (); nh->oi = vl_data->nexthop.oi; nh->router = vl_data->nexthop.router; ospf_spf_add_parent (v, w, nh, distance); return 1; } else zlog_info("ospf_nexthop_calculation(): " "vl_data for VL link not found"); } /* end virtual-link from V to W */ return 0; } /* end W is a Router vertex */ else { assert(w->type == OSPF_VERTEX_NETWORK); nh = vertex_nexthop_new (); nh->oi = oi; nh->router.s_addr = 0; /* Nexthop not required */ ospf_spf_add_parent (v, w, nh, distance); return 1; } } /* end V is the root */ /* Check if W's parent is a network connected to root. */ else if (v->type == OSPF_VERTEX_NETWORK) { /* See if any of V's parents are the root. */ for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp)) { if (vp->parent == area->spf) /* connects to root? */ { /* 16.1.1 para 5. ...the parent vertex is a network that * directly connects the calculating router to the destination * router. The list of next hops is then determined by * examining the destination's router-LSA... */ assert(w->type == OSPF_VERTEX_ROUTER); while ((l = ospf_get_next_link (w, v, l))) { /* ...For each link in the router-LSA that points back to the * parent network, the link's Link Data field provides the IP * address of a next hop router. The outgoing interface to * use can then be derived from the next hop IP address (or * it can be inherited from the parent network). */ nh = vertex_nexthop_new (); nh->oi = vp->nexthop->oi; nh->router = l->link_data; added = 1; ospf_spf_add_parent (v, w, nh, distance); } /* Note lack of return is deliberate. See next comment. */ } } /* NB: This code is non-trivial. * * E.g. it is not enough to know that V connects to the root. It is * also important that the while above, looping through all links from * W->V found at least one link, so that we know there is * bi-directional connectivity between V and W (which need not be the * case, e.g. when OSPF has not yet converged fully). Otherwise, if * we /always/ return here, without having checked that root->V->-W * actually resulted in a valid nexthop being created, then we we will * prevent SPF from finding/using higher cost paths. * * It is important, if root->V->W has not been added, that we continue * through to the intervening-router nexthop code below. So as to * ensure other paths to V may be used. This avoids unnecessary * blackholes while OSPF is convergening. * * I.e. we may have arrived at this function, examining V -> W, via * workable paths other than root -> V, and it's important to avoid * getting "confused" by non-working root->V->W path - it's important * to *not* lose the working non-root paths, just because of a * non-viable root->V->W. * * See also bug #330 (required reading!), and: * * http://blogs.oracle.com/paulj/entry/the_difference_a_line_makes */ if (added) return added; } /* 16.1.1 para 4. If there is at least one intervening router in the * current shortest path between the destination and the root, the * destination simply inherits the set of next hops from the * parent. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: Intervening routers, adding parent(s)", __func__); for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp)) { added = 1; ospf_spf_add_parent (v, w, vp->nexthop, distance); } return added; } /* RFC2328 Section 16.1 (2). * v is on the SPF tree. Examine the links in v's LSA. Update the list * of candidates with any vertices not already on the list. If a lower-cost * path is found to a vertex already on the candidate list, store the new cost. */ static void ospf_spf_next (struct vertex *v, struct ospf_area *area, struct pqueue * candidate) { struct ospf_lsa *w_lsa = NULL; u_char *p; u_char *lim; struct router_lsa_link *l = NULL; struct in_addr *r; int type = 0, lsa_pos=-1, lsa_pos_next=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; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: Next vertex of %s vertex %s", __func__, v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", inet_ntoa(v->lsa->id)); p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); while (p < lim) { struct vertex *w; unsigned int distance; /* In case of V is Router-LSA. */ if (v->lsa->type == OSPF_ROUTER_LSA) { l = (struct router_lsa_link *) p; lsa_pos = lsa_pos_next; /* LSA link position */ lsa_pos_next++; p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_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; /* Infinite distance links shouldn't be followed, except * for local links (a stub-routed router still wants to * calculate tree, so must follow its own links). */ if ((v != area->spf) && l->m[0].metric >= OSPF_OUTPUT_COST_INFINITE) 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_debug ("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_debug ("found Router LSA %s", inet_ntoa (l->link_id)); } break; case LSA_LINK_TYPE_TRANSIT: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("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); if (w_lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("found Router LSA %s", inet_ntoa (w_lsa->data->id)); } } /* (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) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("No LSA found"); continue; } if (IS_LSA_MAXAGE (w_lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA is MaxAge"); continue; } if (ospf_lsa_has_link (w_lsa->data, v->lsa) < 0 ) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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 (w_lsa->stat == LSA_SPF_IN_SPFTREE) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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: */ /* calculate link cost D. */ if (v->lsa->type == OSPF_ROUTER_LSA) distance = v->distance + ntohs (l->m[0].metric); else /* v is not a Router-LSA */ distance = v->distance; /* Is there already vertex W in candidate list? */ if (w_lsa->stat == LSA_SPF_NOT_EXPLORED) { /* prepare vertex W. */ w = ospf_vertex_new (w_lsa); /* Calculate nexthop to W. */ if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) pqueue_enqueue (w, candidate); else if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Nexthop Calc failed"); } else if (w_lsa->stat >= 0) { /* Get the vertex from candidates. */ w = candidate->array[w_lsa->stat]; /* if D is greater than. */ if (w->distance < distance) { continue; } /* equal to. */ else if (w->distance == distance) { /* Found an equal-cost path to W. * Calculate nexthop of to W from V. */ ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos); } /* less than. */ else { /* Found a lower-cost path to W. * nexthop_calculation is conditional, if it finds * valid nexthop it will call spf_add_parents, which * will flush the old parents */ if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) /* Decrease the key of the node in the heap. * trickle-sort it up towards root, just in case this * node should now be the new root due the cost change. * (next pqueu_{de,en}queue will fully re-heap the queue). */ trickle_up (w_lsa->stat, candidate); } } /* end W is already on the candidate list */ } /* end loop over the links in V's LSA */ } static void ospf_spf_dump (struct vertex *v, int i) { struct listnode *cnode; struct listnode *nnode; struct vertex_parent *parent; if (v->type == OSPF_VERTEX_ROUTER) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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_debug ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id), ip_masklen (lsa->mask)); } if (IS_DEBUG_OSPF_EVENT) for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent)) { zlog_debug (" nexthop %p %s %s", (void *)parent->nexthop, inet_ntoa (parent->nexthop->router), parent->nexthop->oi ? IF_NAME(parent->nexthop->oi) : "NULL"); } i++; for (ALL_LIST_ELEMENTS_RO (v->children, cnode, v)) ospf_spf_dump (v, i); } /* Second stage of SPF calculation. */ static void ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v, struct route_table *rt, int parent_is_root) { struct listnode *cnode, *cnnode; struct vertex *child; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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; int lsa_pos = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_process_stubs():processing router LSA, id: %s", inet_ntoa (v->lsa->id)); rlsa = (struct router_lsa *) v->lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_process_stubs(): we have %d links to process", ntohs (rlsa->links)); p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); while (p < lim) { l = (struct router_lsa_link *) p; p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); if (l->m[0].type == LSA_LINK_TYPE_STUB) ospf_intra_add_stub (rt, l, v, area, parent_is_root, lsa_pos); lsa_pos++; } } ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1, 1); for (ALL_LIST_ELEMENTS (v->children, cnode, cnnode, child)) { if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED)) continue; /* the first level of routers connected to the root * should have 'parent_is_root' set, including those * connected via a network vertex. */ if (area->spf == v) parent_is_root = 1; else if (v->type == OSPF_VERTEX_ROUTER) parent_is_root = 0; ospf_spf_process_stubs (area, child, rt, parent_is_root); SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED); } } void ospf_rtrs_free (struct route_table *rtrs) { struct route_node *rn; struct list *or_list; struct ospf_route *or; struct listnode *node, *nnode; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Route: Router Routing Table free"); for (rn = route_top (rtrs); rn; rn = route_next (rn)) if ((or_list = rn->info) != NULL) { for (ALL_LIST_ELEMENTS (or_list, node, nnode, or)) ospf_route_free (or); list_delete (or_list); /* Unlock the node. */ rn->info = NULL; route_unlock_node (rn); } route_table_finish (rtrs); } #if 0 static void ospf_rtrs_print (struct route_table *rtrs) { struct route_node *rn; struct list *or_list; struct listnode *ln; struct listnode *pnode; struct ospf_route *or; struct ospf_path *path; char buf1[BUFSIZ]; char buf2[BUFSIZ]; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_rtrs_print() start"); for (rn = route_top (rtrs); rn; rn = route_next (rn)) if ((or_list = rn->info) != NULL) for (ALL_LIST_ELEMENTS_RO (or_list, ln, or)) { switch (or->path_type) { case OSPF_PATH_INTRA_AREA: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%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_debug ("%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 (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path)) { if (path->nexthop.s_addr == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug (" directly attached to %s\r\n", ifindex2ifname (path->ifindex)); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug (" via %s, %s\r\n", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex)); } } } zlog_debug ("ospf_rtrs_print() end"); } #endif /* Calculating the shortest-path tree for an area. */ static void ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, struct route_table *new_rtrs) { struct pqueue *candidate; struct vertex *v; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_spf_calculate: Start"); zlog_debug ("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_debug ("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. */ /* This function scans all the LSA database and set the stat field to * LSA_SPF_NOT_EXPLORED. */ ospf_lsdb_clean_stat (area->lsdb); /* Create a new heap for the candidates. */ candidate = pqueue_create(); candidate->cmp = cmp; candidate->update = update_stat; /* Initialize the shortest-path tree to only the root (which is the router doing the calculation). */ ospf_spf_init (area); v = area->spf; /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the * spanning tree. */ *(v->stat) = LSA_SPF_IN_SPFTREE; /* 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); /* 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 (candidate->size == 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). */ /* Extract from the candidates the node with the lower key. */ v = (struct vertex *) pqueue_dequeue (candidate); /* Update stat field in vertex. */ *(v->stat) = LSA_SPF_IN_SPFTREE; ospf_vertex_add_parent (v); /* 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. */ } /* end loop until no more candidate vertices */ 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, 0); /* Free candidate queue. */ pqueue_delete (candidate); ospf_vertex_dump (__func__, area->spf, 0, 1); /* Free nexthop information, canonical versions of which are attached * the first level of router vertices attached to the root vertex, see * ospf_nexthop_calculation. */ ospf_canonical_nexthops_free (area->spf); /* Increment SPF Calculation Counter. */ area->spf_calculation++; quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); area->ts_spf = area->ospf->ts_spf; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_spf_calculate: Stop. %zd vertices", mtype_stats_alloc(MTYPE_OSPF_VERTEX)); /* Free SPF vertices, but not the list. List has ospf_vertex_free * as deconstructor. */ list_delete_all_node (&vertex_list); } /* Timer for SPF calculation. */ static int ospf_spf_calculate_timer (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct route_table *new_table, *new_rtrs; struct ospf_area *area; struct listnode *node, *nnode; struct timeval start_time, stop_time, spf_start_time; int areas_processed = 0; unsigned long ia_time, prune_time, rt_time; unsigned long abr_time, total_spf_time, spf_time; char rbuf[32]; /* reason_buf */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: Timer (SPF calculation expire)"); ospf->t_spf_calc = NULL; quagga_gettime (QUAGGA_CLK_MONOTONIC, &spf_start_time); /* Allocate new table tree. */ new_table = route_table_init (); new_rtrs = route_table_init (); ospf_vl_unapprove (ospf); /* Calculate SPF for each area. */ for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { /* Do backbone last, so as to first discover intra-area paths * for any back-bone virtual-links */ if (ospf->backbone && ospf->backbone == area) continue; ospf_spf_calculate (area, new_table, new_rtrs); areas_processed++; } /* SPF for backbone, if required */ if (ospf->backbone) { ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); areas_processed++; } quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); spf_time = timeval_elapsed (stop_time, spf_start_time); ospf_vl_shut_unapproved (ospf); start_time = stop_time; /* saving a call */ ospf_ia_routing (ospf, new_table, new_rtrs); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); ia_time = timeval_elapsed (stop_time, start_time); quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); ospf_prune_unreachable_networks (new_table); ospf_prune_unreachable_routers (new_rtrs); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); prune_time = timeval_elapsed (stop_time, start_time); /* 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); quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); /* Update routing table. */ ospf_route_install (ospf, new_table); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); rt_time = timeval_elapsed (stop_time, start_time); /* 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; quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); if (IS_OSPF_ABR (ospf)) ospf_abr_task (ospf); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); abr_time = timeval_elapsed (stop_time, start_time); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); total_spf_time = timeval_elapsed (stop_time, spf_start_time); ospf->ts_spf_duration.tv_sec = total_spf_time/1000000; ospf->ts_spf_duration.tv_usec = total_spf_time % 1000000; ospf_get_spf_reason_str (rbuf); if (IS_DEBUG_OSPF_EVENT) { zlog_info ("SPF Processing Time(usecs): %ld", total_spf_time); zlog_info ("\t SPF Time: %ld", spf_time); zlog_info ("\t InterArea: %ld", ia_time); zlog_info ("\t Prune: %ld", prune_time); zlog_info ("\tRouteInstall: %ld", rt_time); if (IS_OSPF_ABR (ospf)) zlog_info ("\t ABR: %ld (%d areas)", abr_time, areas_processed); zlog_info ("Reason(s) for SPF: %s", rbuf); } ospf_clear_spf_reason_flags (); 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, ospf_spf_reason_t reason) { unsigned long delay, elapsed, ht; struct timeval result; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation timer scheduled"); /* OSPF instance does not exist. */ if (ospf == NULL) return; ospf_spf_set_reason (reason); /* SPF calculation timer is already scheduled. */ if (ospf->t_spf_calc) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation timer is already scheduled: %p", (void *)ospf->t_spf_calc); return; } /* XXX Monotic timers: we only care about relative time here. */ result = tv_sub (recent_relative_time (), ospf->ts_spf); elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000); ht = ospf->spf_holdtime * ospf->spf_hold_multiplier; if (ht > ospf->spf_max_holdtime) ht = ospf->spf_max_holdtime; /* Get SPF calculation delay time. */ if (elapsed < ht) { /* Got an event within the hold time of last SPF. We need to * increase the hold_multiplier, if it's not already at/past * maximum value, and wasn't already increased.. */ if (ht < ospf->spf_max_holdtime) ospf->spf_hold_multiplier++; /* always honour the SPF initial delay */ if ( (ht - elapsed) < ospf->spf_delay) delay = ospf->spf_delay; else delay = ht - elapsed; } else { /* Event is past required hold-time of last SPF */ delay = ospf->spf_delay; ospf->spf_hold_multiplier = 1; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation timer delay = %ld", delay); zlog_info ("SPF: Scheduled in %ld msec", delay); ospf->t_spf_calc = thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay); } quagga-1.2.4/ospfd/ospf_spf.h000066400000000000000000000047361325323223500161000ustar00rootroot00000000000000/* * 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. */ #ifndef _QUAGGA_OSPF_SPF_H #define _QUAGGA_OSPF_SPF_H /* values for vertex->type */ #define OSPF_VERTEX_ROUTER 1 /* for a Router-LSA */ #define OSPF_VERTEX_NETWORK 2 /* for a Network-LSA */ /* values for vertex->flags */ #define OSPF_VERTEX_PROCESSED 0x01 /* The "root" is the node running the SPF calculation */ /* A router or network in an area */ struct vertex { u_char flags; u_char type; /* copied from LSA header */ struct in_addr id; /* copied from LSA header */ struct lsa_header *lsa; /* Router or Network LSA */ int *stat; /* Link to LSA status. */ u_int32_t distance; /* from root to this vertex */ struct list *parents; /* list of parents in SPF tree */ struct list *children; /* list of children in SPF tree*/ }; /* A nexthop taken on the root node to get to this (parent) vertex */ struct vertex_nexthop { struct ospf_interface *oi; /* output intf on root node */ struct in_addr router; /* router address to send to */ }; struct vertex_parent { struct vertex_nexthop *nexthop; /* link to nexthop info for this parent */ struct vertex *parent; /* parent vertex */ int backlink; /* index back to parent for router-lsa's */ }; /* What triggered the SPF ? */ typedef enum { SPF_FLAG_ROUTER_LSA_INSTALL = 1, SPF_FLAG_NETWORK_LSA_INSTALL, SPF_FLAG_SUMMARY_LSA_INSTALL, SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL, SPF_FLAG_MAXAGE, SPF_FLAG_ABR_STATUS_CHANGE, SPF_FLAG_ASBR_STATUS_CHANGE, SPF_FLAG_CONFIG_CHANGE, } ospf_spf_reason_t; extern void ospf_spf_calculate_schedule (struct ospf *, ospf_spf_reason_t); extern void ospf_rtrs_free (struct route_table *); /* void ospf_spf_calculate_timer_add (); */ #endif /* _QUAGGA_OSPF_SPF_H */ quagga-1.2.4/ospfd/ospf_te.c000066400000000000000000002251151325323223500157070ustar00rootroot00000000000000/* * This is an implementation of RFC3630 * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * Copyright (C) 2012 Orange Labs * http://www.orange.com * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* Add support of RFC7471 */ /* Add support of RFC5392, RFC6827 */ #include #include #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 "network.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_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" #include "ospfd/ospf_vty.h" /* * Global variable to manage Opaque-LSA/MPLS-TE on this node. * Note that all parameter values are stored in network byte order. */ struct ospf_mpls_te OspfMplsTE; const char *mode2text[] = { "Disable", "AS", "Area", "Emulate" }; enum oifstate { OI_ANY, OI_DOWN, OI_UP }; /*------------------------------------------------------------------------* * 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_show_info (struct vty *vty, struct ospf_lsa *lsa); static int ospf_mpls_te_lsa_originate_area (void *arg); static int ospf_mpls_te_lsa_originate_as (void *arg); static struct ospf_lsa *ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); 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, NULL,/*ospf_mpls_te_config_write_if */ NULL,/* ospf_mpls_te_config_write_debug */ ospf_mpls_te_show_info, ospf_mpls_te_lsa_originate_area, 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 Traffic Engineering functions"); goto out; } memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); OspfMplsTE.status = disabled; OspfMplsTE.inter_as = Disable; OspfMplsTE.iflist = list_new (); OspfMplsTE.iflist->del = del_mpls_te_link; ospf_mpls_te_register_vty (); out: return rc; } /* Additional register for RFC5392 support */ static int ospf_mpls_te_register (enum inter_as_mode mode) { int rc; u_int8_t scope; if (OspfMplsTE.inter_as != Disable) return 0; if (mode == AS) scope = OSPF_OPAQUE_AS_LSA; else scope = OSPF_OPAQUE_AREA_LSA; rc = ospf_register_opaque_functab (scope, OPAQUE_TYPE_INTER_AS_LSA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ospf_mpls_te_show_info, ospf_mpls_te_lsa_originate_as, ospf_mpls_te_lsa_refresh, NULL, NULL); if (rc != 0) { zlog_warn ("ospf_router_info_init: Failed to register Inter-AS functions"); return rc; } return 0; } static int ospf_mpls_te_unregister () { u_int8_t scope; if (OspfMplsTE.inter_as == Disable) return 0; if (OspfMplsTE.inter_as == AS) scope = OSPF_OPAQUE_AS_LSA; else scope = OSPF_OPAQUE_AREA_LSA; ospf_delete_opaque_functab (scope, OPAQUE_TYPE_INTER_AS_LSA); return 0; } void ospf_mpls_te_term (void) { list_delete (OspfMplsTE.iflist); OspfMplsTE.iflist = NULL; ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); OspfMplsTE.status = disabled; ospf_mpls_te_unregister (); OspfMplsTE.inter_as = Disable; return; } /*------------------------------------------------------------------------* * Followings are control functions for MPLS-TE parameters management. *------------------------------------------------------------------------*/ static void del_mpls_te_link (void *val) { XFREE (MTYPE_OSPF_MPLS_TE, val); return; } u_int32_t get_mpls_te_instance_value (void) { static u_int32_t seqno = 0; if (seqno < MAX_LEGAL_TE_INSTANCE_NUM ) 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) { struct listnode *node, *nnode; struct mpls_te_link *lp; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) if (lp->ifp == ifp) return lp; return NULL; } static struct mpls_te_link * lookup_linkparams_by_instance (struct ospf_lsa *lsa) { struct listnode *node; struct mpls_te_link *lp; unsigned int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) 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, opcode_t sched_opcode), opcode_t sched_opcode) { struct listnode *node, *nnode; struct listnode *node2; struct mpls_te_link *lp; struct ospf_area *area; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { /* Skip Inter-AS TEv2 Links */ if (IS_INTER_AS (lp->type)) continue; if ((area = lp->area) == NULL) continue; if CHECK_FLAG (lp->flags, LPFLG_LOOKUP_DONE) continue; if (func != NULL) (* func)(lp, sched_opcode); for (node2 = listnextnode (node); node2; node2 = listnextnode (node2)) if ((lp = listgetdata (node2)) != NULL) if (lp->area != NULL) if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) SET_FLAG (lp->flags, LPFLG_LOOKUP_DONE); } for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) if (lp->area != NULL) UNSET_FLAG (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 (TE_LINK_SUBTLV_DEF_SIZE); OspfMplsTE.router_addr.value = ipv4; return; } static void set_linkparams_link_header (struct mpls_te_link *lp) { 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 (lp->lclif_ipaddr.header.type != 0) length += TLV_SIZE (&lp->lclif_ipaddr.header); /* TE_LINK_SUBTLV_RMTIF_IPADDR */ if (lp->rmtif_ipaddr.header.type != 0) length += TLV_SIZE (&lp->rmtif_ipaddr.header); /* 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); /* TE_LINK_SUBTLV_LLRI */ if (ntohs (lp->llri.header.type) != 0) length += TLV_SIZE (&lp->llri.header); /* TE_LINK_SUBTLV_RIP */ if (ntohs (lp->rip.header.type) != 0) length += TLV_SIZE (&lp->rip.header); /* TE_LINK_SUBTLV_RAS */ if (ntohs (lp->ras.header.type) != 0) length += TLV_SIZE (&lp->ras.header); /* TE_LINK_SUBTLV_LRRID */ if (ntohs (lp->lrrid.header.type) != 0) length += TLV_SIZE (&lp->lrrid.header); /* TE_LINK_SUBTLV_AV_DELAY */ if (ntohs (lp->av_delay.header.type) != 0) length += TLV_SIZE (&lp->av_delay.header); /* TE_LINK_SUBTLV_MM_DELAY */ if (ntohs (lp->mm_delay.header.type) != 0) length += TLV_SIZE (&lp->mm_delay.header); /* TE_LINK_SUBTLV_DELAY_VAR */ if (ntohs (lp->delay_var.header.type) != 0) length += TLV_SIZE (&lp->delay_var.header); /* TE_LINK_SUBTLV_PKT_LOSS */ if (ntohs (lp->pkt_loss.header.type) != 0) length += TLV_SIZE (&lp->pkt_loss.header); /* TE_LINK_SUBTLV_RES_BW */ if (ntohs (lp->res_bw.header.type) != 0) length += TLV_SIZE (&lp->res_bw.header); /* TE_LINK_SUBTLV_AVA_BW */ if (ntohs (lp->ava_bw.header.type) != 0) length += TLV_SIZE (&lp->ava_bw.header); /* TE_LINK_SUBTLV_USE_BW */ if (ntohs (lp->use_bw.header.type) != 0) length += TLV_SIZE (&lp->use_bw.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 (TE_LINK_SUBTLV_TYPE_SIZE); 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 (TE_LINK_SUBTLV_DEF_SIZE); /* * 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_lclif_ipaddr (struct mpls_te_link *lp, struct in_addr lclif) { lp->lclif_ipaddr.header.type = htons (TE_LINK_SUBTLV_LCLIF_IPADDR); lp->lclif_ipaddr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->lclif_ipaddr.value[0] = lclif; return; } static void set_linkparams_rmtif_ipaddr (struct mpls_te_link *lp, struct in_addr rmtif) { lp->rmtif_ipaddr.header.type = htons (TE_LINK_SUBTLV_RMTIF_IPADDR); lp->rmtif_ipaddr.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->rmtif_ipaddr.value[0] = rmtif; 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 (TE_LINK_SUBTLV_DEF_SIZE); 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 (TE_LINK_SUBTLV_DEF_SIZE); lp->max_bw.value = htonf (fp); 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 (TE_LINK_SUBTLV_DEF_SIZE); lp->max_rsv_bw.value = htonf (fp); 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 (TE_LINK_SUBTLV_UNRSV_SIZE); lp->unrsv_bw.value [priority] = htonf (fp); 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 (TE_LINK_SUBTLV_DEF_SIZE); lp->rsc_clsclr.value = htonl (classcolor); return; } static void set_linkparams_inter_as (struct mpls_te_link *lp, struct in_addr addr, u_int32_t as) { /* Set the Remote ASBR IP address and then the associated AS number */ lp->rip.header.type = htons (TE_LINK_SUBTLV_RIP); lp->rip.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->rip.value = addr; lp->ras.header.type = htons (TE_LINK_SUBTLV_RAS); lp->ras.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->ras.value = htonl (as); } static void unset_linkparams_inter_as (struct mpls_te_link *lp) { /* Reset the Remote ASBR IP address and then the associated AS number */ lp->rip.header.type = htons (0); lp->rip.header.length = htons (0); lp->rip.value.s_addr = htonl (0); lp->ras.header.type = htons (0); lp->ras.header.length = htons (0); lp->ras.value = htonl (0); } void set_linkparams_llri (struct mpls_te_link *lp, u_int32_t local, u_int32_t remote) { lp->llri.header.type = htons (TE_LINK_SUBTLV_LLRI); lp->llri.header.length = htons (TE_LINK_SUBTLV_LLRI_SIZE); lp->llri.local = htonl (local); lp->llri.remote = htonl (remote); } void set_linkparams_lrrid (struct mpls_te_link *lp, struct in_addr local, struct in_addr remote) { lp->lrrid.header.type = htons (TE_LINK_SUBTLV_LRRID); lp->lrrid.header.length = htons (TE_LINK_SUBTLV_LRRID_SIZE); lp->lrrid.local.s_addr = local.s_addr; lp->lrrid.remote.s_addr = remote.s_addr; } static void set_linkparams_av_delay (struct mpls_te_link *lp, u_int32_t delay, u_char anormal) { u_int32_t tmp; /* Note that TLV-length field is the size of array. */ lp->av_delay.header.type = htons (TE_LINK_SUBTLV_AV_DELAY); lp->av_delay.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); tmp = delay & TE_EXT_MASK; if (anormal) tmp |= TE_EXT_ANORMAL; lp->av_delay.value = htonl (tmp); return; } static void set_linkparams_mm_delay (struct mpls_te_link *lp, u_int32_t low, u_int32_t high, u_char anormal) { u_int32_t tmp; /* Note that TLV-length field is the size of array. */ lp->mm_delay.header.type = htons (TE_LINK_SUBTLV_MM_DELAY); lp->mm_delay.header.length = htons (TE_LINK_SUBTLV_MM_DELAY_SIZE); tmp = low & TE_EXT_MASK; if (anormal) tmp |= TE_EXT_ANORMAL; lp->mm_delay.low = htonl (tmp); lp->mm_delay.high = htonl (high); return; } static void set_linkparams_delay_var (struct mpls_te_link *lp, u_int32_t jitter) { /* Note that TLV-length field is the size of array. */ lp->delay_var.header.type = htons (TE_LINK_SUBTLV_DELAY_VAR); lp->delay_var.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->delay_var.value = htonl (jitter & TE_EXT_MASK); return; } static void set_linkparams_pkt_loss (struct mpls_te_link *lp, u_int32_t loss, u_char anormal) { u_int32_t tmp; /* Note that TLV-length field is the size of array. */ lp->pkt_loss.header.type = htons (TE_LINK_SUBTLV_PKT_LOSS); lp->pkt_loss.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); tmp = loss & TE_EXT_MASK; if (anormal) tmp |= TE_EXT_ANORMAL; lp->pkt_loss.value = htonl (tmp); return; } static void set_linkparams_res_bw (struct mpls_te_link *lp, float fp) { /* Note that TLV-length field is the size of array. */ lp->res_bw.header.type = htons (TE_LINK_SUBTLV_RES_BW); lp->res_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->res_bw.value = htonf (fp); return; } static void set_linkparams_ava_bw (struct mpls_te_link *lp, float fp) { /* Note that TLV-length field is the size of array. */ lp->ava_bw.header.type = htons (TE_LINK_SUBTLV_AVA_BW); lp->ava_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->ava_bw.value = htonf (fp); return; } static void set_linkparams_use_bw (struct mpls_te_link *lp, float fp) { /* Note that TLV-length field is the size of array. */ lp->use_bw.header.type = htons (TE_LINK_SUBTLV_USE_BW); lp->use_bw.header.length = htons (TE_LINK_SUBTLV_DEF_SIZE); lp->use_bw.value = htonf (fp); return; } /* Update TE parameters from Interface */ static void update_linkparams(struct mpls_te_link *lp) { int i; struct interface *ifp; /* Get the Interface structure */ if ((ifp = lp->ifp) == NULL) { zlog_warn("OSPF MPLS-TE: Abort update TE parameters: no interface associated to Link Parameters"); return; } if (!HAS_LINK_PARAMS(ifp)) { zlog_warn("OSPF MPLS-TE: Abort update TE parameters: no Link Parameters for interface"); return; } /* RFC3630 metrics */ if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) set_linkparams_rsc_clsclr (lp, ifp->link_params->admin_grp); else TLV_TYPE(lp->rsc_clsclr) = 0; if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) set_linkparams_max_bw (lp, ifp->link_params->max_bw); else TLV_TYPE(lp->max_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) set_linkparams_max_rsv_bw (lp, ifp->link_params->max_rsv_bw); else TLV_TYPE(lp->max_rsv_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) for (i = 0; i < MAX_CLASS_TYPE; i++) set_linkparams_unrsv_bw (lp, i, ifp->link_params->unrsv_bw[i]); else TLV_TYPE(lp->unrsv_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_TE)) set_linkparams_te_metric(lp, ifp->link_params->te_metric); else TLV_TYPE(lp->te_metric) = 0; /* TE metric Extensions */ if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) set_linkparams_av_delay(lp, ifp->link_params->av_delay, 0); else TLV_TYPE(lp->av_delay) = 0; if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) set_linkparams_mm_delay(lp, ifp->link_params->min_delay, ifp->link_params->max_delay, 0); else TLV_TYPE(lp->mm_delay) = 0; if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) set_linkparams_delay_var(lp, ifp->link_params->delay_var); else TLV_TYPE(lp->delay_var) = 0; if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) set_linkparams_pkt_loss(lp, ifp->link_params->pkt_loss, 0); else TLV_TYPE(lp->pkt_loss) = 0; if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) set_linkparams_res_bw(lp, ifp->link_params->res_bw); else TLV_TYPE(lp->res_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) set_linkparams_ava_bw(lp, ifp->link_params->ava_bw); else TLV_TYPE(lp->ava_bw) = 0; if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) set_linkparams_use_bw(lp, ifp->link_params->use_bw); else TLV_TYPE(lp->use_bw) = 0; /* RFC5392 */ if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) { /* Flush LSA if it engaged and was previously a STD_TE one */ if (IS_STD_TE(lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) { if (IS_DEBUG_OSPF_TE) zlog_debug("OSPF MPLS-TE Update IF: Switch from Standard LSA to INTER-AS for %s[%d/%d]", ifp->name, lp->flags, lp->type); ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); /* Then, switch it to INTER-AS */ if (OspfMplsTE.inter_as == AS) lp->flags = INTER_AS | FLOOD_AS; else { lp->flags = INTER_AS | FLOOD_AREA; lp->area = ospf_area_lookup_by_area_id (ospf_lookup(), OspfMplsTE.interas_areaid); } } set_linkparams_inter_as(lp, ifp->link_params->rmt_ip, ifp->link_params->rmt_as); } else { if (IS_DEBUG_OSPF_TE) zlog_debug("OSPF MPLS-TE Update IF: Switch from INTER-AS LSA to Standard for %s[%d/%d]", ifp->name, lp->flags, lp->type); /* reset inter-as TE params */ /* Flush LSA if it engaged and was previously an INTER_AS one */ if (IS_INTER_AS(lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) { ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); /* Then, switch it to Standard TE */ lp->flags = STD_TE | FLOOD_AREA; } unset_linkparams_inter_as (lp); } } static void initialize_linkparams (struct mpls_te_link *lp) { struct interface *ifp = lp->ifp; struct ospf_interface *oi; if (IS_DEBUG_OSPF_TE) zlog_debug("MPLS-TE(initialize_linkparams) Initialize Link Parameters for interface %s", ifp->name); if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL) { zlog_warn("MPLS-TE(initialize_linkparams) Could not find corresponding OSPF Interface for %s", ifp->name); return; } /* * Try to set initial values those can be derived from * zebra-interface information. */ set_linkparams_link_type (oi, lp); /* Set local IP addr */ set_linkparams_lclif_ipaddr (lp, oi->address->u.prefix4); /* Set Remote IP addr if Point to Point Interface */ if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) { struct prefix *pref = CONNECTED_PREFIX(oi->connected); if (pref != NULL) set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); } /* Keep Area information in combination with link parameters. */ lp->area = oi->area; return; } static int is_mandated_params_set (struct mpls_te_link *lp) { int rc = 0; if (ntohs (OspfMplsTE.router_addr.header.type) == 0) { zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Router Address"); goto out; } if (ntohs (lp->link_type.header.type) == 0) { zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Link Type"); goto out; } if (!IS_INTER_AS (lp->type) && (ntohs (lp->link_id.header.type) == 0)) { zlog_warn ("MPLS-TE(is_mandated_params_set) Missing Link ID"); 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 (IS_DEBUG_OSPF_TE) zlog_debug ("MPLS-TE(ospf_mpls_te_new_if) Add new %s interface %s to MPLS-TE list", ifp->link_params ? "Active" : "Inactive", ifp->name); if (lookup_linkparams_by_ifp (ifp) != NULL) { zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", (void *)ifp); rc = 0; /* Do nothing here. */ goto out; } new = XCALLOC (MTYPE_OSPF_MPLS_TE, sizeof (struct mpls_te_link)); if (new == NULL) { zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", safe_strerror (errno)); goto out; } new->instance = get_mpls_te_instance_value (); new->ifp = ifp; /* By default TE-Link is RFC3630 compatible flooding in Area and not active */ /* This default behavior will be adapted with call to ospf_mpls_te_update_if() */ new->type = STD_TE | FLOOD_AREA; new->flags = LPFLG_LSA_INACTIVE; /* Initialize Link Parameters from Interface */ initialize_linkparams(new); /* Set TE Parameters from Interface */ update_linkparams(new); /* Add Link Parameters structure to the list */ listnode_add (OspfMplsTE.iflist, new); if (IS_DEBUG_OSPF_TE) zlog_debug("OSPF MPLS-TE New IF: Add new LP context for %s[%d/%d]", ifp->name, new->flags, new->type); /* 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) { struct 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, lp); } /* Schedule Opaque-LSA refresh. *//* XXX */ rc = 0; /*out:*/ return rc; } /* Main initialization / update function of the MPLS TE Link context */ /* Call when interface TE Link parameters are modified */ void ospf_mpls_te_update_if (struct interface *ifp) { struct mpls_te_link *lp; if (IS_DEBUG_OSPF_TE) zlog_debug ("OSPF MPLS-TE: Update LSA parameters for interface %s [%s]", ifp->name, HAS_LINK_PARAMS(ifp) ? "ON" : "OFF"); /* Get Link context from interface */ if ((lp = lookup_linkparams_by_ifp(ifp)) == NULL) { zlog_warn ("OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s", ifp->name); return; } /* Fulfill MPLS-TE Link TLV from Interface TE Link parameters */ if (HAS_LINK_PARAMS(ifp)) { SET_FLAG (lp->flags, LPFLG_LSA_ACTIVE); /* Update TE parameters */ update_linkparams(lp); /* Finally Re-Originate or Refresh Opaque LSA if MPLS_TE is enabled */ if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); } } else { /* If MPLS TE is disable on this interface, flush LSA if it is already engaged */ if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); else /* Reset Activity flag */ lp->flags = LPFLG_LSA_INACTIVE; } return; } 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 combination with linkparams. */ lp->area = oi->area; /* Keep interface MPLS-TE status */ lp->flags = HAS_LINK_PARAMS(oi->ifp); 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 Link type, Link ID, Local and Remote IP addr */ set_linkparams_link_type (oi, lp); set_linkparams_link_id (oi, lp); set_linkparams_lclif_ipaddr (lp, oi->address->u.prefix4); if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) { struct prefix *pref = CONNECTED_PREFIX(oi->connected); if (pref != NULL) set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); } /* Update TE parameters */ update_linkparams(lp); /* Try to Schedule LSA */ 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 CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); } break; default: lp->link_type.header.type = htons (0); lp->link_id.header.type = htons (0); if CHECK_FLAG (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) { /* 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 (struct stream *s, struct te_tlv_header *tlvh) { 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_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 (s, &lp->link_type.header); build_link_subtlv (s, &lp->link_id.header); build_link_subtlv (s, &lp->lclif_ipaddr.header); build_link_subtlv (s, &lp->rmtif_ipaddr.header); build_link_subtlv (s, &lp->te_metric.header); build_link_subtlv (s, &lp->max_bw.header); build_link_subtlv (s, &lp->max_rsv_bw.header); build_link_subtlv (s, &lp->unrsv_bw.header); build_link_subtlv (s, &lp->rsc_clsclr.header); build_link_subtlv (s, &lp->lrrid.header); build_link_subtlv (s, &lp->llri.header); build_link_subtlv (s, &lp->rip.header); build_link_subtlv (s, &lp->ras.header); build_link_subtlv (s, &lp->av_delay.header); build_link_subtlv (s, &lp->mm_delay.header); build_link_subtlv (s, &lp->delay_var.header); build_link_subtlv (s, &lp->pkt_loss.header); build_link_subtlv (s, &lp->res_bw.header); build_link_subtlv (s, &lp->ava_bw.header); build_link_subtlv (s, &lp->res_bw.header); 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 = 0; 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 = OSPF_OPTION_O; /* Don't forget this :-) */ /* Set opaque-LSA header fields depending of the type of RFC */ if (IS_INTER_AS (lp->type)) { if IS_FLOOD_AS (lp->type) { options |= OSPF_OPTION_E; /* Enable AS external as we flood Inter-AS with Opaque Type 11 */ lsa_type = OSPF_OPAQUE_AS_LSA; } else { options |= LSA_OPTIONS_GET (area); /* Get area default option */ options |= LSA_OPTIONS_NSSA_GET (area); lsa_type = OSPF_OPAQUE_AREA_LSA; } tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); lsa_id.s_addr = htonl (tmp); struct ospf *top = ospf_lookup (); lsa_header_set (s, options, lsa_type, lsa_id, top->router_id); } else { options |= LSA_OPTIONS_GET (area); /* Get area default option */ options |= LSA_OPTIONS_NSSA_GET (area); lsa_type = OSPF_OPAQUE_AREA_LSA; tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); lsa_id.s_addr = htonl (tmp); lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id); } if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_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_unlock (&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_unlock (&new); goto out; } /* Now this link-parameter entry has associated LSA. */ SET_FLAG (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_debug ("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_area (void *arg) { struct ospf_area *area = (struct ospf_area *) arg; struct listnode *node, *nnode; struct mpls_te_link *lp; int rc = -1; if (OspfMplsTE.status == disabled) { zlog_info ("ospf_mpls_te_lsa_originate_area: MPLS-TE is disabled now."); rc = 0; /* This is not an error case. */ goto out; } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { /* Process only enabled LSA with area scope flooding */ if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE) || IS_FLOOD_AS (lp->type)) continue; if (lp->area == NULL) continue; if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) continue; if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) { if CHECK_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH) { UNSET_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH); zlog_warn ("OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate"); ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } continue; } if (! is_mandated_params_set (lp)) { zlog_warn ("ospf_mpls_te_lsa_originate_area: 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 (IS_DEBUG_OSPF_TE) zlog_debug ("MPLS-TE(ospf_mpls_te_lsa_originate_area) Let's finally reoriginate the LSA %d through the Area %s for Link %s", lp->instance, inet_ntoa (area->area_id), lp->ifp ? lp->ifp->name : "?"); if (ospf_mpls_te_lsa_originate1 (area, lp) != 0) goto out; } rc = 0; out: return rc; } static int ospf_mpls_te_lsa_originate2 (struct ospf *top, struct mpls_te_link *lp) { struct ospf_lsa *new; int rc = -1; /* Create new Opaque-LSA/Inter-AS instance. */ if ((new = ospf_mpls_te_lsa_new (NULL, lp)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_originate2: ospf_router_info_lsa_new() ?"); goto out; } /* Install this LSA into LSDB. */ if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) { zlog_warn ("ospf_mpls_te_lsa_originate2: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } /* Now this Router Info parameter entry has associated LSA. */ SET_FLAG (lp->flags, LPFLG_LSA_ENGAGED); /* Update new LSA origination count. */ top->lsa_originate_count++; /* Flood new LSA through AS. */ ospf_flood_through_as (top, NULL /*nbr */ , new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE Inter-AS", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } rc = 0; out:return rc; } static int ospf_mpls_te_lsa_originate_as (void *arg) { struct ospf *top; struct ospf_area *area; struct listnode *node, *nnode; struct mpls_te_link *lp; int rc = -1; if ((OspfMplsTE.status == disabled) || (OspfMplsTE.inter_as == Disable)) { zlog_info ("ospf_mpls_te_lsa_originate_as: MPLS-TE Inter-AS is disabled for now."); rc = 0; /* This is not an error case. */ goto out; } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { /* Process only enabled INTER_AS Links or Pseudo-Links */ if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE) || !IS_INTER_AS (lp->type)) continue; if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) { if CHECK_FLAG (lp->flags, LPFLG_LSA_FORCED_REFRESH) { UNSET_FLAG (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_as: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?"); continue; } /* Ok, let's try to originate an LSA for this AS and Link. */ if (IS_DEBUG_OSPF_TE) zlog_debug ("MPLS-TE(ospf_mpls_te_lsa_originate_as) Let's finally re-originate the Inter-AS LSA %d through the %s for Link %s", lp->instance, IS_FLOOD_AS (lp->type) ? "AS" : "Area", lp->ifp ? lp->ifp->name : "Unknown"); if (IS_FLOOD_AS (lp->type)) { top = (struct ospf *) arg; rc = ospf_mpls_te_lsa_originate2 (top, lp); } else { area = (struct ospf_area *) arg; rc = ospf_mpls_te_lsa_originate1 (area, lp); } } rc = 0; out:return rc; } static struct ospf_lsa * ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) { struct mpls_te_link *lp; struct ospf_area *area = lsa->area; struct ospf *top; 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. */ } /* Check if lp was not disable in the interval */ if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE)) { zlog_warn ("ospf_mpls_te_lsa_refresh: lp was disabled: Flush it!"); 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)) { if (lp) UNSET_FLAG (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. */ /* As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use ospf_lookup() to get ospf instance */ if (area) top = area->ospf; else top = ospf_lookup (); if (ospf_lsa_install (top, NULL /*oi */ , new) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } /* Flood updated LSA through AS or Area depending of the RFC of the link */ if (IS_FLOOD_AS (lp->type)) ospf_flood_through_as (top, NULL, new); else ospf_flood_through_area (area, NULL/*nbr*/, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("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 new; } void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, opcode_t opcode) { struct ospf_lsa lsa; struct lsa_header lsah; struct ospf *top; u_int32_t tmp; memset (&lsa, 0, sizeof (lsa)); memset (&lsah, 0, sizeof (lsah)); top = ospf_lookup (); /* Check if the pseudo link is ready to flood */ if (!(CHECK_FLAG (lp->flags, LPFLG_LSA_ACTIVE)) || !(IS_FLOOD_AREA (lp->type) || IS_FLOOD_AS (lp->type))) { return; } lsa.area = lp->area; lsa.data = &lsah; if (IS_FLOOD_AS (lp->type)) { lsah.type = OSPF_OPAQUE_AS_LSA; tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); lsah.id.s_addr = htonl (tmp); } else { lsah.type = OSPF_OPAQUE_AREA_LSA; if (IS_INTER_AS (lp->type)) { /* Set the area context if not know */ if (lp->area == NULL) lp->area = ospf_area_lookup_by_area_id (top, OspfMplsTE.interas_areaid); /* Unable to set the area context. Abort! */ if (lp->area == NULL) { zlog_warn ("MPLS-TE(ospf_mpls_te_lsa_schedule) Area context is null. Abort !"); return; } tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_INTER_AS_LSA, lp->instance); } else tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); lsah.id.s_addr = htonl (tmp); } switch (opcode) { case REORIGINATE_THIS_LSA: if (IS_FLOOD_AS (lp->type)) { ospf_opaque_lsa_reoriginate_schedule ((void *) top, OSPF_OPAQUE_AS_LSA, OPAQUE_TYPE_INTER_AS_LSA); break; } if (IS_FLOOD_AREA (lp->type)) { if (IS_INTER_AS (lp->type)) ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_INTER_AS_LSA); else ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); break; } break; case REFRESH_THIS_LSA: ospf_opaque_lsa_refresh_schedule (&lsa); break; case FLUSH_THIS_LSA: /* Reset Activity flag */ lp->flags = LPFLG_LSA_INACTIVE; 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_debug (" 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_debug (" 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_debug (" 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_debug (" 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_debug (" 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_debug (" #%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_debug (" 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_debug (" #%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_debug (" 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; fval = ntohf (top->value); if (vty != NULL) vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" 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; fval = ntohf (top->value); if (vty != NULL) vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" 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 fval1, fval2; int i; top = (struct te_link_subtlv_unrsv_bw *) tlvh; if (vty != NULL) vty_out (vty, " Unreserved Bandwidth per Class Type in Byte/s:%s", VTY_NEWLINE); else zlog_debug (" Unreserved Bandwidth per Class Type in Byte/s:"); for (i = 0; i < MAX_CLASS_TYPE; i+=2) { fval1 = ntohf (top->value[i]); fval2 = ntohf (top->value[i+1]); if (vty != NULL) vty_out(vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", i, fval1, i+1, fval2, VTY_NEWLINE); else zlog_debug (" [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", i, fval1, i+1, fval2); } 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_debug (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value)); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_lrrid (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_lrrid *top; top = (struct te_link_subtlv_lrrid *) tlvh; if (vty != NULL) { vty_out (vty, " Local TE Router ID: %s%s", inet_ntoa (top->local), VTY_NEWLINE); vty_out (vty, " Remote TE Router ID: %s%s", inet_ntoa (top->remote), VTY_NEWLINE); } else { zlog_debug (" Local TE Router ID: %s", inet_ntoa (top->local)); zlog_debug (" Remote TE Router ID: %s", inet_ntoa (top->remote)); } return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_llri (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_llri *top; top = (struct te_link_subtlv_llri *) tlvh; if (vty != NULL) { vty_out (vty, " Link Local ID: %d%s", (u_int32_t) ntohl (top->local), VTY_NEWLINE); vty_out (vty, " Link Remote ID: %d%s", (u_int32_t) ntohl (top->remote), VTY_NEWLINE); } else { zlog_debug (" Link Local ID: %d", (u_int32_t) ntohl (top->local)); zlog_debug (" Link Remote ID: %d", (u_int32_t) ntohl (top->remote)); } return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_rip (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_rip *top; top = (struct te_link_subtlv_rip *) tlvh; if (vty != NULL) vty_out (vty, " Inter-AS TE Remote ASBR IP address: %s%s", inet_ntoa (top->value), VTY_NEWLINE); else zlog_debug (" Inter-AS TE Remote ASBR IP address: %s", inet_ntoa (top->value)); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_ras (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_ras *top; top = (struct te_link_subtlv_ras *) tlvh; if (vty != NULL) vty_out (vty, " Inter-AS TE Remote AS number: %u%s", ntohl (top->value), VTY_NEWLINE); else zlog_debug (" Inter-AS TE Remote AS number: %u", ntohl (top->value)); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_av_delay (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_av_delay *top; u_int32_t delay; u_int32_t anomalous; top = (struct te_link_subtlv_av_delay *) tlvh; delay = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; anomalous = (u_int32_t) ntohl (top->value) & TE_EXT_ANORMAL; if (vty != NULL) vty_out (vty, " %s Average Link Delay: %d (micro-sec)%s", anomalous ? "Anomalous" : "Normal", delay, VTY_NEWLINE); else zlog_debug (" %s Average Link Delay: %d (micro-sec)", anomalous ? "Anomalous" : "Normal", delay); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_mm_delay (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_mm_delay *top; u_int32_t low, high; u_int32_t anomalous; top = (struct te_link_subtlv_mm_delay *) tlvh; low = (u_int32_t) ntohl (top->low) & TE_EXT_MASK; anomalous = (u_int32_t) ntohl (top->low) & TE_EXT_ANORMAL; high = (u_int32_t) ntohl (top->high); if (vty != NULL) vty_out (vty, " %s Min/Max Link Delay: %d/%d (micro-sec)%s", anomalous ? "Anomalous" : "Normal", low, high, VTY_NEWLINE); else zlog_debug (" %s Min/Max Link Delay: %d/%d (micro-sec)", anomalous ? "Anomalous" : "Normal", low, high); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_delay_var (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_delay_var *top; u_int32_t jitter; top = (struct te_link_subtlv_delay_var *) tlvh; jitter = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; if (vty != NULL) vty_out (vty, " Delay Variation: %d (micro-sec)%s", jitter, VTY_NEWLINE); else zlog_debug (" Delay Variation: %d (micro-sec)", jitter); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_pkt_loss (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_pkt_loss *top; u_int32_t loss; u_int32_t anomalous; float fval; top = (struct te_link_subtlv_pkt_loss *) tlvh; loss = (u_int32_t) ntohl (top->value) & TE_EXT_MASK; fval = (float) (loss * LOSS_PRECISION); anomalous = (u_int32_t) ntohl (top->value) & TE_EXT_ANORMAL; if (vty != NULL) vty_out (vty, " %s Link Loss: %g (%%)%s", anomalous ? "Anomalous" : "Normal", fval, VTY_NEWLINE); else zlog_debug (" %s Link Loss: %g (%%)", anomalous ? "Anomalous" : "Normal", fval); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_res_bw (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_res_bw *top; float fval; top = (struct te_link_subtlv_res_bw *) tlvh; fval = ntohf (top->value); if (vty != NULL) vty_out (vty, " Unidirectional Residual Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Unidirectional Residual Bandwidth: %g (Bytes/sec)", fval); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_ava_bw (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_ava_bw *top; float fval; top = (struct te_link_subtlv_ava_bw *) tlvh; fval = ntohf (top->value); if (vty != NULL) vty_out (vty, " Unidirectional Available Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Unidirectional Available Bandwidth: %g (Bytes/sec)", fval); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_use_bw (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_use_bw *top; float fval; top = (struct te_link_subtlv_use_bw *) tlvh; fval = ntohf (top->value); if (vty != NULL) vty_out (vty, " Unidirectional Utilized Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Unidirectional Utilized Bandwidth: %g (Bytes/sec)", fval); 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_debug (" 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; case TE_LINK_SUBTLV_LRRID: sum += show_vty_link_subtlv_lrrid (vty, tlvh); break; case TE_LINK_SUBTLV_LLRI: sum += show_vty_link_subtlv_llri (vty, tlvh); break; case TE_LINK_SUBTLV_RIP: sum += show_vty_link_subtlv_rip (vty, tlvh); break; case TE_LINK_SUBTLV_RAS: sum += show_vty_link_subtlv_ras (vty, tlvh); break; case TE_LINK_SUBTLV_AV_DELAY: sum += show_vty_link_subtlv_av_delay (vty, tlvh); break; case TE_LINK_SUBTLV_MM_DELAY: sum += show_vty_link_subtlv_mm_delay (vty, tlvh); break; case TE_LINK_SUBTLV_DELAY_VAR: sum += show_vty_link_subtlv_delay_var (vty, tlvh); break; case TE_LINK_SUBTLV_PKT_LOSS: sum += show_vty_link_subtlv_pkt_loss (vty, tlvh); break; case TE_LINK_SUBTLV_RES_BW: sum += show_vty_link_subtlv_res_bw (vty, tlvh); break; case TE_LINK_SUBTLV_AVA_BW: sum += show_vty_link_subtlv_ava_bw (vty, tlvh); break; case TE_LINK_SUBTLV_USE_BW: sum += show_vty_link_subtlv_use_bw (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 on%s", VTY_NEWLINE); vty_out (vty, " mpls-te router-address %s%s", inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE); } if (OspfMplsTE.inter_as == AS) vty_out (vty, " mpls-te inter-as as%s", VTY_NEWLINE); if (OspfMplsTE.inter_as == Area) vty_out (vty, " mpls-te inter-as area %s %s", inet_ntoa (OspfMplsTE.interas_areaid), VTY_NEWLINE); return; } /*------------------------------------------------------------------------* * Followings are vty command functions. *------------------------------------------------------------------------*/ DEFUN (ospf_mpls_te_on, ospf_mpls_te_on_cmd, "mpls-te on", MPLS_TE_STR "Enable the MPLS-TE functionality\n") { struct listnode *node; struct mpls_te_link *lp; if (OspfMplsTE.status == enabled) return CMD_SUCCESS; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("MPLS-TE: OFF -> ON"); OspfMplsTE.status = enabled; /* Reoriginate RFC3630 & RFC6827 Links */ ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_THIS_LSA); /* Reoriginate LSA if INTER-AS is always on */ if (OspfMplsTE.inter_as != Disable) { for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) { if (IS_INTER_AS (lp->type)) { ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); } } } return CMD_SUCCESS; } DEFUN (no_ospf_mpls_te, no_ospf_mpls_te_cmd, "no mpls-te", NO_STR "Disable the MPLS-TE functionality\n") { struct listnode *node, *nnode; struct mpls_te_link *lp; if (OspfMplsTE.status == disabled) return CMD_SUCCESS; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("MPLS-TE: ON -> OFF"); OspfMplsTE.status = disabled; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) if CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); return CMD_SUCCESS; } DEFUN (ospf_mpls_te_router_addr, ospf_mpls_te_router_addr_cmd, "mpls-te router-address A.B.C.D", MPLS_TE_STR "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)) { struct listnode *node, *nnode; struct mpls_te_link *lp; int need_to_reoriginate = 0; set_mpls_te_router_addr (value); if (OspfMplsTE.status == disabled) goto out; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { if ((lp->area == NULL) || IS_FLOOD_AS (lp->type)) continue; if (!CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) { need_to_reoriginate = 1; break; } } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { if ((lp->area == NULL) || IS_FLOOD_AS (lp->type)) continue; if (need_to_reoriginate) SET_FLAG (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_THIS_LSA); } out: return CMD_SUCCESS; } static int set_inter_as_mode (struct vty *vty, const char *mode_name, const char *area_id) { enum inter_as_mode mode; struct listnode *node; struct mpls_te_link *lp; int format; if (OspfMplsTE.status == enabled) { /* Read and Check inter_as mode */ if (strcmp (mode_name, "as") == 0) mode = AS; else if (strcmp (mode_name, "area") == 0) { mode = Area; VTY_GET_OSPF_AREA_ID (OspfMplsTE.interas_areaid, format, area_id); } else { vty_out (vty, "Unknown mode. Please choose between as or area%s", VTY_NEWLINE); return CMD_WARNING; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("MPLS-TE: Inter-AS enable with %s flooding support", mode2text[mode]); /* Register new callbacks regarding the flooding scope (AS or Area) */ if (ospf_mpls_te_register (mode) < 0) { vty_out (vty, "Internal error: Unable to register Inter-AS functions%s", VTY_NEWLINE); return CMD_WARNING; } /* Enable mode and re-originate LSA if needed */ if ((OspfMplsTE.inter_as == Disable) && (mode != OspfMplsTE.inter_as)) { OspfMplsTE.inter_as = mode; /* Re-originate all InterAS-TEv2 LSA */ for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) { if (IS_INTER_AS (lp->type)) { if (mode == AS) lp->type |= FLOOD_AS; else lp->type |= FLOOD_AREA; ospf_mpls_te_lsa_schedule (lp, REORIGINATE_THIS_LSA); } } } else { vty_out (vty, "Please change Inter-AS support to disable first before going to mode %s%s", mode2text[mode], VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } DEFUN (ospf_mpls_te_inter_as_as, ospf_mpls_te_inter_as_cmd, "mpls-te inter-as as", MPLS_TE_STR "Configure MPLS-TE Inter-AS support\n" "AS native mode self originate INTER_AS LSA with Type 11 (as flooding scope)\n") { return set_inter_as_mode (vty, "as", ""); } DEFUN (ospf_mpls_te_inter_as_area, ospf_mpls_te_inter_as_area_cmd, "mpls-te inter-as area (A.B.C.D|<0-4294967295>)", MPLS_TE_STR "Configure MPLS-TE Inter-AS support\n" "AREA native mode self originate INTER_AS LSA with Type 10 (area flooding scope)\n" "OSPF area ID in IP format\n" "OSPF area ID as decimal value\n") { return set_inter_as_mode (vty, "area", argv[0]); } DEFUN (no_ospf_mpls_te_inter_as, no_ospf_mpls_te_inter_as_cmd, "no mpls-te inter-as", NO_STR MPLS_TE_STR "Disable MPLS-TE Inter-AS support\n") { struct listnode *node, *nnode; struct mpls_te_link *lp; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("MPLS-TE: Inter-AS support OFF"); if ((OspfMplsTE.status == enabled) && (OspfMplsTE.inter_as != Disable)) { OspfMplsTE.inter_as = Disable; /* Flush all Inter-AS LSA */ for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) if (IS_INTER_AS (lp->type) && CHECK_FLAG (lp->flags, LPFLG_LSA_ENGAGED)) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); } /* Deregister the Callbacks for Inter-AS suport */ ospf_mpls_te_unregister (); return CMD_SUCCESS; } DEFUN (show_ip_ospf_mpls_te_router, show_ip_ospf_mpls_te_router_cmd, "show ip ospf mpls-te router", SHOW_STR IP_STR OSPF_STR "MPLS-TE information\n" "MPLS-TE Router parameters\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; if ((OspfMplsTE.status == enabled) && HAS_LINK_PARAMS(ifp) && !if_is_loopback (ifp) && if_is_up (ifp) && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) { /* Continue only if interface is not passive or support Inter-AS TEv2 */ if (!(ospf_oi_count (ifp) > 0)) { if (IS_INTER_AS (lp->type)) { vty_out (vty, "-- Inter-AS TEv2 link parameters for %s --%s", ifp->name, VTY_NEWLINE); } else { /* MPLS-TE is not activate on this interface */ /* or this interface is passive and Inter-AS TEv2 is not activate */ vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", ifp->name, VTY_NEWLINE); return; } } else { vty_out (vty, "-- MPLS-TE link parameters for %s --%s", ifp->name, VTY_NEWLINE); } if (TLV_TYPE(lp->link_type) != 0) show_vty_link_subtlv_link_type (vty, &lp->link_type.header); if (TLV_TYPE(lp->link_id) != 0) show_vty_link_subtlv_link_id (vty, &lp->link_id.header); if (TLV_TYPE(lp->lclif_ipaddr) != 0) show_vty_link_subtlv_lclif_ipaddr (vty, &lp->lclif_ipaddr.header); if (TLV_TYPE(lp->rmtif_ipaddr) != 0) show_vty_link_subtlv_rmtif_ipaddr (vty, &lp->rmtif_ipaddr.header); if (TLV_TYPE(lp->rip) != 0) show_vty_link_subtlv_rip (vty, &lp->rip.header); if (TLV_TYPE(lp->ras) != 0) show_vty_link_subtlv_ras (vty, &lp->ras.header); if (TLV_TYPE(lp->te_metric) != 0) show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); if (TLV_TYPE(lp->max_bw) != 0) show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); if (TLV_TYPE(lp->max_rsv_bw) != 0) show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); if (TLV_TYPE(lp->unrsv_bw) != 0) show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); if (TLV_TYPE(lp->rsc_clsclr) != 0) show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); if (TLV_TYPE(lp->av_delay) != 0) show_vty_link_subtlv_av_delay (vty, &lp->av_delay.header); if (TLV_TYPE(lp->mm_delay) != 0) show_vty_link_subtlv_mm_delay (vty, &lp->mm_delay.header); if (TLV_TYPE(lp->delay_var) != 0) show_vty_link_subtlv_delay_var (vty, &lp->delay_var.header); if (TLV_TYPE(lp->pkt_loss) != 0) show_vty_link_subtlv_pkt_loss (vty, &lp->pkt_loss.header); if (TLV_TYPE(lp->res_bw) != 0) show_vty_link_subtlv_res_bw (vty, &lp->res_bw.header); if (TLV_TYPE(lp->ava_bw) != 0) show_vty_link_subtlv_ava_bw (vty, &lp->ava_bw.header); if (TLV_TYPE(lp->use_bw) != 0) show_vty_link_subtlv_use_bw (vty, &lp->use_bw.header); vty_out (vty, "---------------%s%s", VTY_NEWLINE, VTY_NEWLINE); } else { vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", ifp->name, VTY_NEWLINE); } return; } DEFUN (show_ip_ospf_mpls_te_link, show_ip_ospf_mpls_te_link_cmd, "show ip ospf mpls-te interface [INTERFACE]", SHOW_STR IP_STR OSPF_STR "MPLS-TE information\n" "Interface information\n" "Interface name\n") { struct interface *ifp; struct listnode *node, *nnode; /* Show All Interfaces. */ if (argc == 0) { for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) show_mpls_te_link_sub (vty, ifp); } /* 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_ip_ospf_mpls_te_router_cmd); install_element (VIEW_NODE, &show_ip_ospf_mpls_te_link_cmd); install_element (OSPF_NODE, &ospf_mpls_te_on_cmd); install_element (OSPF_NODE, &no_ospf_mpls_te_cmd); install_element (OSPF_NODE, &ospf_mpls_te_router_addr_cmd); install_element (OSPF_NODE, &ospf_mpls_te_inter_as_cmd); install_element (OSPF_NODE, &ospf_mpls_te_inter_as_area_cmd); install_element (OSPF_NODE, &no_ospf_mpls_te_inter_as_cmd); return; } quagga-1.2.4/ospfd/ospf_te.h000066400000000000000000000344701325323223500157160ustar00rootroot00000000000000/* * This is an implementation of RFC3630, RFC5392 & RFC6827 * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * Copyright (C) 2012 Orange Labs * http://www.orange.com * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* Add support of RFC7471 */ /* Add support of RFC5392 */ /* Add support of RFC6827 (partial) */ #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 MAX_LEGAL_TE_INSTANCE_NUM (0xffff) #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 define the type of TE link regarding the various RFC */ #define STD_TE 0x01 #define GMPLS 0x02 #define INTER_AS 0x04 #define PSEUDO_TE 0x08 #define FLOOD_AREA 0x10 #define FLOOD_AS 0x20 #define EMULATED 0x80 #define IS_STD_TE(x) (x & STD_TE) #define IS_PSEUDO_TE(x) (x & PSEUDO_TE) #define IS_INTER_AS(x) (x & INTER_AS) #define IS_EMULATED(x) (x & EMULATED) #define IS_FLOOD_AREA(x) (x & FLOOD_AREA) #define IS_FLOOD_AS(x) (x & FLOOD_AS) #define IS_INTER_AS_EMU(x) (x & INTER_AS & EMULATED) #define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) /* Flags to manage TE Link LSA */ #define LPFLG_LSA_INACTIVE 0x0 #define LPFLG_LSA_ACTIVE 0x1 #define LPFLG_LSA_ENGAGED 0x2 #define LPFLG_LOOKUP_DONE 0x4 #define LPFLG_LSA_FORCED_REFRESH 0x8 /* * 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)) #define TLV_HDR_SUBTLV(tlvh) \ (struct te_tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE) #define TLV_TYPE(tlvh) tlvh.header.type #define TLV_LEN(tlvh) tlvh.header.length #define TLV_HDR(tlvh) tlvh.header /* * 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. */ }; #define TE_LINK_SUBTLV_DEF_SIZE 4 /* Link Type Sub-TLV */ /* Mandatory */ #define TE_LINK_SUBTLV_LINK_TYPE 1 #define TE_LINK_SUBTLV_TYPE_SIZE 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 #define TE_LINK_SUBTLV_UNRSV_SIZE 32 struct te_link_subtlv_unrsv_bw { struct te_tlv_header header; /* Value length is 32 octets. */ float value[MAX_CLASS_TYPE]; /* 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. */ }; /* For RFC6827 */ /* Local and Remote TE Router ID */ #define TE_LINK_SUBTLV_LRRID 10 #define TE_LINK_SUBTLV_LRRID_SIZE 8 struct te_link_subtlv_lrrid { struct te_tlv_header header; /* Value length is 8 octets. */ struct in_addr local; /* Local TE Router Identifier */ struct in_addr remote; /* Remote TE Router Identifier */ }; /* RFC4203: Link Local/Remote Identifiers */ #define TE_LINK_SUBTLV_LLRI 11 #define TE_LINK_SUBTLV_LLRI_SIZE 8 struct te_link_subtlv_llri { struct te_tlv_header header; /* Value length is 8 octets. */ u_int32_t local; /* Link Local Identifier */ u_int32_t remote; /* Link Remote Identifier */ }; /* Inter-RA Export Upward sub-TLV (12) and Inter-RA Export Downward sub-TLV (13) (RFC6827bis) are not yet supported */ /* SUBTLV 14-16 (RFC4203) are not yet supported */ /* Bandwidth Constraints sub-TLV (17) (RFC4124) is not yet supported */ /* SUBLV 18-20 are for OSPFv6 TE (RFC5329). see ospf6d */ /* For RFC 5392 */ /* Remote AS Number sub-TLV */ #define TE_LINK_SUBTLV_RAS 21 struct te_link_subtlv_ras { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Remote AS number */ }; /* IPv4 Remote ASBR ID Sub-TLV */ #define TE_LINK_SUBTLV_RIP 22 struct te_link_subtlv_rip { struct te_tlv_header header; /* Value length is 4 octets. */ struct in_addr value; /* Remote ASBR IP address */ }; /* SUBTLV 24 is IPv6 Remote ASBR ID (RFC5392). see ospf6d */ /* SUBTLV 23 (RFC5330) and 25 (RFC6001) are not yet supported */ /* SUBTLV 26 (RFC7308) is not yet supported */ /* RFC7471 */ /* Link Sub-TLV: Average Link Delay */ /* Optional */ #define TE_LINK_SUBTLV_AV_DELAY 27 struct te_link_subtlv_av_delay { struct te_tlv_header header; /* Value length is 4 bytes. */ u_int32_t value; /* delay in micro-seconds only 24 bits => 0 ... 16777215 with Anomalous Bit as Upper most bit */ }; /* Link Sub-TLV: Low/High Link Delay */ #define TE_LINK_SUBTLV_MM_DELAY 28 #define TE_LINK_SUBTLV_MM_DELAY_SIZE 8 struct te_link_subtlv_mm_delay { struct te_tlv_header header; /* Value length is 8 bytes. */ u_int32_t low; /* low delay in micro-seconds only 24 bits => 0 ... 16777215 with Anomalous Bit (A) as Upper most bit */ u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */ }; /* Link Sub-TLV: Link Delay Variation i.e. Jitter */ #define TE_LINK_SUBTLV_DELAY_VAR 29 struct te_link_subtlv_delay_var { struct te_tlv_header header; /* Value length is 4 bytes. */ u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ... 16777215 */ }; /* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ #define TE_LINK_SUBTLV_PKT_LOSS 30 struct te_link_subtlv_pkt_loss { struct te_tlv_header header; /* Value length is 4 bytes. */ u_int32_t value; /* in percentage of total traffic only 24 bits (2^24 - 2) with Anomalous Bit as Upper most bit */ }; /* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ #define TE_LINK_SUBTLV_RES_BW 31 struct te_link_subtlv_res_bw { struct te_tlv_header header; /* Value length is 4 bytes. */ float value; /* bandwidth in IEEE floating point format with units in bytes per second */ }; /* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ #define TE_LINK_SUBTLV_AVA_BW 32 struct te_link_subtlv_ava_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bandwidth in IEEE floating point format with units in bytes per second */ }; /* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ #define TE_LINK_SUBTLV_USE_BW 33 struct te_link_subtlv_use_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bandwidth in IEEE floating point format with units in bytes per second */ }; #define TE_LINK_SUBTLV_MAX 34 /* Last SUBTLV + 1 */ /* Here are "non-official" architectural constants. */ #define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ /* Following declaration concerns the MPLS-TE and LINk-TE management */ typedef enum _opcode_t { REORIGINATE_THIS_LSA, REFRESH_THIS_LSA, FLUSH_THIS_LSA } opcode_t; typedef enum _status_t { disabled, enabled } status_t; /* Mode for Inter-AS Opaque-LSA */ enum inter_as_mode { Disable, AS, Area }; struct te_link_subtlv { struct te_tlv_header header; union { u_int32_t link_type; struct in_addr link_id; struct in_addr lclif; struct in_addr rmtif; u_int32_t te_metric; float max_bw; float max_rsv_bw; float unrsv[8]; u_int32_t rsc_clsclr; u_int32_t llri[2]; u_int32_t ras; struct in_addr rip; struct in_addr lrrid[2]; u_int32_t av_delay; u_int32_t mm_delay; u_int32_t delay_var; u_int32_t pkt_loss; float res_bw; float ava_bw; float use_bw; } value; }; /* Following structure are internal use only. */ struct ospf_mpls_te { /* Status of MPLS-TE: enable or disable */ status_t status; /* RFC5392 */ enum inter_as_mode inter_as; struct in_addr interas_areaid; /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ struct 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; /* Type of MPLS-TE link: RFC3630, RFC5392, RFC5392 emulated, RFC6827 */ u_int8_t type; /* Store Link-TLV in network byte order. */ /* RFC3630 & RFC6827 / RFC 6827 */ 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; /* RFC4203 */ struct te_link_subtlv_llri llri; /* RFC5392 */ struct te_link_subtlv_ras ras; struct te_link_subtlv_rip rip; /* RFC6827 */ struct te_link_subtlv_lrrid lrrid; /* RFC7471 */ struct te_link_subtlv_av_delay av_delay; struct te_link_subtlv_mm_delay mm_delay; struct te_link_subtlv_delay_var delay_var; struct te_link_subtlv_pkt_loss pkt_loss; struct te_link_subtlv_res_bw res_bw; struct te_link_subtlv_ava_bw ava_bw; struct te_link_subtlv_use_bw use_bw; struct in_addr adv_router; struct in_addr id; }; /* Prototypes. */ extern int ospf_mpls_te_init (void); extern void ospf_mpls_te_term (void); extern struct ospf_mpls_te *get_ospf_mpls_te (void); extern void ospf_mpls_te_update_if (struct interface *); extern void ospf_mpls_te_lsa_schedule (struct mpls_te_link *, opcode_t); extern u_int32_t get_mpls_te_instance_value (void); extern void set_linkparams_llri (struct mpls_te_link *, u_int32_t, u_int32_t); extern void set_linkparams_lrrid (struct mpls_te_link *, struct in_addr, struct in_addr); #endif /* _ZEBRA_OSPF_MPLS_TE_H */ quagga-1.2.4/ospfd/ospf_vty.c000066400000000000000000007020421325323223500161200ustar00rootroot00000000000000/* OSPF VTY interface. * Copyright (C) 2005 6WIND * 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 const char *ospf_network_type_str[] = { "Null", "POINTOPOINT", "BROADCAST", "NBMA", "POINTOMULTIPOINT", "VIRTUALLINK", "LOOPBACK" }; /* Utility functions. */ int ospf_str2area_id (const 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 { if (*str == '-') return -1; errno = 0; ret = strtoul (str, &endptr, 10); if (*endptr != '\0' || errno || ret > UINT32_MAX) return -1; area_id->s_addr = htonl (ret); *format = OSPF_AREA_ID_FORMAT_DECIMAL; } return 0; } static int str2metric (const 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; } static int str2metric_type (const 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; ospf_router_id_update (ospf); 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") static void ospf_passive_interface_default (struct ospf *ospf, u_char newval) { struct listnode *ln; struct interface *ifp; struct ospf_interface *oi; ospf->passive_interface_default = newval; for (ALL_LIST_ELEMENTS_RO (om->iflist, ln, ifp)) { if (ifp && OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), passive_interface)) UNSET_IF_PARAM (IF_DEF_PARAMS (ifp), passive_interface); } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, ln, oi)) { if (OSPF_IF_PARAM_CONFIGURED (oi->params, passive_interface)) UNSET_IF_PARAM (oi->params, passive_interface); /* update multicast memberships */ ospf_if_set_multicast(oi); } } static void ospf_passive_interface_update_addr (struct ospf *ospf, struct interface *ifp, struct ospf_if_params *params, u_char value, struct in_addr addr) { u_char dflt; params->passive_interface = value; if (params != IF_DEF_PARAMS (ifp)) { if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), passive_interface)) dflt = IF_DEF_PARAMS (ifp)->passive_interface; else dflt = ospf->passive_interface_default; if (value != dflt) SET_IF_PARAM (params, passive_interface); else UNSET_IF_PARAM (params, passive_interface); ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } } static void ospf_passive_interface_update (struct ospf *ospf, struct interface *ifp, struct ospf_if_params *params, u_char value) { params->passive_interface = value; if (params == IF_DEF_PARAMS (ifp)) { if (value != ospf->passive_interface_default) SET_IF_PARAM (params, passive_interface); else UNSET_IF_PARAM (params, passive_interface); } } /* get the appropriate ospf parameters structure, checking if * there's a valid interface address at the argi'th argv index */ enum { VTY_SET = 0, VTY_UNSET, }; #define OSPF_VTY_GET_IF_PARAMS(ifp,params,argi,addr,set) \ (params) = IF_DEF_PARAMS ((ifp)); \ \ if (argc == (argi) + 1) \ { \ int ret = inet_aton(argv[(argi)], &(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)); \ \ if (set) \ ospf_if_update_params ((ifp), (addr)); \ else if ((params) == NULL) \ return CMD_SUCCESS; \ } #define OSPF_VTY_PARAM_UNSET(params,var,ifp,addr) \ UNSET_IF_PARAM ((params), var); \ if ((params) != IF_DEF_PARAMS ((ifp))) \ { \ ospf_free_if_params ((ifp), (addr)); \ ospf_if_update_params ((ifp), (addr)); \ } 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; struct route_node *rn; struct ospf *ospf = vty->index; if (argc == 0) { ospf_passive_interface_default (ospf, OSPF_IF_PASSIVE); return CMD_SUCCESS; } ifp = if_get_by_name (argv[0]); 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); ospf_passive_interface_update_addr (ospf, ifp, params, OSPF_IF_PASSIVE, addr); } ospf_passive_interface_update (ospf, ifp, params, OSPF_IF_PASSIVE); /* XXX We should call ospf_if_set_multicast on exactly those * interfaces for which the passive property changed. It is too much * work to determine this set, so we do this for every interface. * This is safe and reasonable because ospf_if_set_multicast uses a * record of joined groups to avoid systems calls if the desired * memberships match the current memership. */ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (oi && (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_PASSIVE)) ospf_if_set_multicast(oi); } /* * XXX It is not clear what state transitions the interface needs to * undergo when going from active to passive. Fixing this will * require precise identification of interfaces having such a * transition. */ 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") ALIAS (ospf_passive_interface, ospf_passive_interface_default_cmd, "passive-interface default", "Suppress routing updates on an interface\n" "Suppress routing updates on interfaces by default\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; struct route_node *rn; struct ospf *ospf = vty->index; if (argc == 0) { ospf_passive_interface_default (ospf, OSPF_IF_ACTIVE); return CMD_SUCCESS; } ifp = if_get_by_name (argv[0]); 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; ospf_passive_interface_update_addr (ospf, ifp, params, OSPF_IF_ACTIVE, addr); } ospf_passive_interface_update (ospf, ifp, params, OSPF_IF_ACTIVE); /* XXX We should call ospf_if_set_multicast on exactly those * interfaces for which the passive property changed. It is too much * work to determine this set, so we do this for every interface. * This is safe and reasonable because ospf_if_set_multicast uses a * record of joined groups to avoid systems calls if the desired * memberships match the current memership. */ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (oi && (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE)) ospf_if_set_multicast(oi); } 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") ALIAS (no_ospf_passive_interface, no_ospf_passive_interface_default_cmd, "no passive-interface default", NO_STR "Allow routing updates on an interface\n" "Allow routing updates on interfaces by default\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_INTEGER ("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; }; static 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; } static 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), area->external_routing == OSPF_AREA_NSSA?"nssa":"stub", VTY_NEWLINE); else vty_out (vty, "Area %ld is %s%s", (u_long)ntohl (area_id.s_addr), area->external_routing == OSPF_AREA_NSSA?"nssa":"stub", VTY_NEWLINE); return NULL; } if ((vl_data = ospf_vl_lookup (ospf, 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, SPF_FLAG_CONFIG_CHANGE); } } return vl_data; } static 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 ((char *) 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 ((char *) 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; } static int ospf_vl_set_timers (struct ospf_vl_data *vl_data, struct ospf_vl_config_data *vl_config) { struct interface *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 */ static 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 (ospf, 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 stub 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; } static int ospf_area_nssa_cmd_handler (struct vty *vty, int argc, const char *argv[], int nosum) { 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); } else { ospf_area_nssa_translator_role_set (ospf, area_id, OSPF_NSSA_ROLE_CANDIDATE); } if (nosum) ospf_area_no_summary_set (ospf, area_id); else ospf_area_no_summary_unset (ospf, area_id); ospf_schedule_abr_task (ospf); return CMD_SUCCESS; } DEFUN (ospf_area_nssa_translate_no_summary, 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") { return ospf_area_nssa_cmd_handler (vty, argc, argv, 1); } DEFUN (ospf_area_nssa_translate, 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") { return ospf_area_nssa_cmd_handler (vty, argc, argv, 0); } 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") { return ospf_area_nssa_cmd_handler (vty, argc, argv, 0); } 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") { return ospf_area_nssa_cmd_handler (vty, argc, argv, 1); } 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); ospf_schedule_abr_task (ospf); 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; } 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; struct prefix_ipv4 p; 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; p.family = AF_INET; p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; p.prefixlen = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): " "announcing 0.0.0.0/0 to area %s", inet_ntoa (area->area_id)); ospf_abr_announce_network_to_area (&p, area->default_cost, area); 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; int format; struct prefix_ipv4 p; VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]); VTY_CHECK_INTEGER_RANGE ("stub default cost", argv[1], 0, OSPF_LS_INFINITY); 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; p.family = AF_INET; p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; p.prefixlen = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): " "announcing 0.0.0.0/0 to area %s", inet_ntoa (area->area_id)); ospf_abr_announce_network_to_area (&p, area->default_cost, area); 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 (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 (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 (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 (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; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); if ((area = ospf_area_lookup_by_area_id (ospf, area_id)) == NULL) return CMD_SUCCESS; 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" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\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|standard)", 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], "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 = OSPF_ABR_DEFAULT; ospf_schedule_abr_task (ospf); } return CMD_SUCCESS; } DEFUN (ospf_log_adjacency_changes, ospf_log_adjacency_changes_cmd, "log-adjacency-changes", "Log changes in adjacency state\n") { struct ospf *ospf = vty->index; SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); return CMD_SUCCESS; } DEFUN (ospf_log_adjacency_changes_detail, ospf_log_adjacency_changes_detail_cmd, "log-adjacency-changes detail", "Log changes in adjacency state\n" "Log all state changes\n") { struct ospf *ospf = vty->index; SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); return CMD_SUCCESS; } DEFUN (no_ospf_log_adjacency_changes, no_ospf_log_adjacency_changes_cmd, "no log-adjacency-changes", NO_STR "Log changes in adjacency state\n") { struct ospf *ospf = vty->index; UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); return CMD_SUCCESS; } DEFUN (no_ospf_log_adjacency_changes_detail, no_ospf_log_adjacency_changes_detail_cmd, "no log-adjacency-changes detail", NO_STR "Log changes in adjacency state\n" "Log all state changes\n") { struct ospf *ospf = vty->index; UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); 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, SPF_FLAG_CONFIG_CHANGE); } 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, SPF_FLAG_CONFIG_CHANGE); } 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") static int ospf_timers_spf_set (struct vty *vty, unsigned int delay, unsigned int hold, unsigned int max) { struct ospf *ospf = vty->index; ospf->spf_delay = delay; ospf->spf_holdtime = hold; ospf->spf_max_holdtime = max; return CMD_SUCCESS; } DEFUN (ospf_timers_min_ls_interval, ospf_timers_min_ls_interval_cmd, "timers throttle lsa all <0-5000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "LSA delay between transmissions\n" NO_STR "Delay (msec) between sending LSAs\n") { struct ospf *ospf = vty->index; unsigned int interval; if (argc != 1) { vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("LSA interval", interval, argv[0]); ospf->min_ls_interval = interval; return CMD_SUCCESS; } DEFUN (no_ospf_timers_min_ls_interval, no_ospf_timers_min_ls_interval_cmd, "no timers throttle lsa all", NO_STR "Adjust routing timers\n" "Throttling adaptive timer\n" "LSA delay between transmissions\n") { struct ospf *ospf = vty->index; ospf->min_ls_interval = OSPF_MIN_LS_INTERVAL; return CMD_SUCCESS; } DEFUN (ospf_timers_min_ls_arrival, ospf_timers_min_ls_arrival_cmd, "timers lsa arrival <0-1000>", "Adjust routing timers\n" "Throttling link state advertisement delays\n" "OSPF minimum arrival interval delay\n" "Delay (msec) between accepted LSAs\n") { struct ospf *ospf = vty->index; unsigned int arrival; if (argc != 1) { vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER_RANGE ("minimum LSA inter-arrival time", arrival, argv[0], 0, 1000); ospf->min_ls_arrival = arrival; return CMD_SUCCESS; } DEFUN (no_ospf_timers_min_ls_arrival, no_ospf_timers_min_ls_arrival_cmd, "no timers lsa arrival", NO_STR "Adjust routing timers\n" "Throttling link state advertisement delays\n" "OSPF minimum arrival interval delay\n") { struct ospf *ospf = vty->index; ospf->min_ls_arrival = OSPF_MIN_LS_ARRIVAL; return CMD_SUCCESS; } DEFUN (ospf_timers_throttle_spf, ospf_timers_throttle_spf_cmd, "timers throttle spf <0-600000> <0-600000> <0-600000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF SPF timers\n" "Delay (msec) from first change received till SPF calculation\n" "Initial hold time (msec) between consecutive SPF calculations\n" "Maximum hold time (msec)\n") { unsigned int delay, hold, max; if (argc != 3) { vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000); VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000); VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000); return ospf_timers_spf_set (vty, delay, hold, max); } DEFUN_DEPRECATED (ospf_timers_spf, ospf_timers_spf_cmd, "timers spf <0-4294967295> <0-4294967295>", "Adjust routing timers\n" "OSPF SPF timers\n" "Delay (s) between receiving a change to SPF calculation\n" "Hold time (s) between consecutive SPF calculations\n") { unsigned int delay, hold; if (argc != 2) { vty_out (vty, "Insufficient number of arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("SPF delay timer", delay, argv[0]); VTY_GET_INTEGER ("SPF hold timer", hold, argv[1]); /* truncate down the second values if they're greater than 600000ms */ if (delay > (600000 / 1000)) delay = 600000; else if (delay == 0) /* 0s delay was probably specified because of lack of ms resolution */ delay = OSPF_SPF_DELAY_DEFAULT; if (hold > (600000 / 1000)) hold = 600000; return ospf_timers_spf_set (vty, delay * 1000, hold * 1000, hold * 1000); } DEFUN (no_ospf_timers_throttle_spf, no_ospf_timers_throttle_spf_cmd, "no timers throttle spf", NO_STR "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF SPF timers\n") { return ospf_timers_spf_set (vty, OSPF_SPF_DELAY_DEFAULT, OSPF_SPF_HOLDTIME_DEFAULT, OSPF_SPF_MAX_HOLDTIME_DEFAULT); } ALIAS_DEPRECATED (no_ospf_timers_throttle_spf, no_ospf_timers_spf_cmd, "no timers spf", NO_STR "Adjust routing timers\n" "OSPF SPF timers\n") 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; unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; unsigned 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, interval); 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; unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; unsigned 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; VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); (void)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; unsigned 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; unsigned 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; struct listnode *node; struct interface *ifp; 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; for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) ospf_if_recalculate_output_cost (ifp); 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; struct listnode *node, *nnode; struct interface *ifp; 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 (ALL_LIST_ELEMENTS (om->iflist, node, nnode, ifp)) ospf_if_recalculate_output_cost (ifp); return CMD_SUCCESS; } const char *ospf_abr_type_descr_str[] = { "Unknown", "Standard (RFC2328)", "Alternative IBM", "Alternative Cisco", "Alternative Shortcut" }; const char *ospf_shortcut_mode_descr_str[] = { "Default", "Enabled", "Disabled" }; static 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 ? "; " : ""); else if (area->external_routing == OSPF_AREA_NSSA) vty_out (vty, " (NSSA%s%s)", area->no_summary ? ", no summary" : "", area->shortcut_configured ? "; " : ""); 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); 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->NSSATranslatorState) { vty_out (vty, " We are an ABR and "); if (area->NSSATranslatorRole == OSPF_NSSA_ROLE_CANDIDATE) vty_out (vty, "the NSSA Elected Translator. %s", VTY_NEWLINE); else if (area->NSSATranslatorRole == OSPF_NSSA_ROLE_ALWAYS) vty_out (vty, "always an NSSA Translator. %s", VTY_NEWLINE); } else { vty_out (vty, " We are an ABR, but "); if (area->NSSATranslatorRole == OSPF_NSSA_ROLE_CANDIDATE) vty_out (vty, "not the NSSA Elected Translator. %s", VTY_NEWLINE); else vty_out (vty, "never an NSSA Translator. %s", VTY_NEWLINE); } } /* Stub-router state for this area */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) { char timebuf[OSPF_TIME_DUMP_SIZE]; vty_out (vty, " Originating stub / maximum-distance Router-LSA%s", VTY_NEWLINE); if (CHECK_FLAG(area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) vty_out (vty, " Administratively activated (indefinitely)%s", VTY_NEWLINE); if (area->t_stub_router) vty_out (vty, " Active from startup, %s remaining%s", ospf_timer_dump (area->t_stub_router, timebuf, sizeof(timebuf)), VTY_NEWLINE); } /* 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, " Number of router LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_ROUTER_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_ROUTER_LSA), VTY_NEWLINE); vty_out (vty, " Number of network LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_NETWORK_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_NETWORK_LSA), VTY_NEWLINE); vty_out (vty, " Number of summary LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_SUMMARY_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_SUMMARY_LSA), VTY_NEWLINE); vty_out (vty, " Number of ASBR summary LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_ASBR_SUMMARY_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_ASBR_SUMMARY_LSA), VTY_NEWLINE); vty_out (vty, " Number of NSSA LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_AS_NSSA_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_AS_NSSA_LSA), VTY_NEWLINE); vty_out (vty, " Number of opaque link LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_OPAQUE_LINK_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_OPAQUE_LINK_LSA), VTY_NEWLINE); vty_out (vty, " Number of opaque area LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_OPAQUE_AREA_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_OPAQUE_AREA_LSA), 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") { struct listnode *node, *nnode; struct ospf_area * area; struct ospf *ospf; struct timeval result; char timebuf[OSPF_TIME_DUMP_SIZE]; /* 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); /* Graceful shutdown */ if (ospf->t_deferred_shutdown) vty_out (vty, " Deferred shutdown in progress, %s remaining%s", ospf_timer_dump (ospf->t_deferred_shutdown, timebuf, sizeof (timebuf)), 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); vty_out (vty, " OpaqueCapability flag is %s%s", CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE) ? "enabled" : "disabled", VTY_NEWLINE); /* Show stub-router configuration */ if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED || ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) { vty_out (vty, " Stub router advertisement is configured%s", VTY_NEWLINE); if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) vty_out (vty, " Enabled for %us after start-up%s", ospf->stub_router_startup_time, VTY_NEWLINE); if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) vty_out (vty, " Enabled for %us prior to full shutdown%s", ospf->stub_router_shutdown_time, VTY_NEWLINE); } /* Show SPF timers. */ vty_out (vty, " Initial SPF scheduling delay %d millisec(s)%s" " Minimum hold time between consecutive SPFs %d millisec(s)%s" " Maximum hold time between consecutive SPFs %d millisec(s)%s" " Hold time multiplier is currently %d%s", ospf->spf_delay, VTY_NEWLINE, ospf->spf_holdtime, VTY_NEWLINE, ospf->spf_max_holdtime, VTY_NEWLINE, ospf->spf_hold_multiplier, VTY_NEWLINE); vty_out (vty, " SPF algorithm "); if (ospf->ts_spf.tv_sec || ospf->ts_spf.tv_usec) { result = tv_sub (recent_relative_time (), ospf->ts_spf); vty_out (vty, "last executed %s ago%s", ospf_timeval_dump (&result, timebuf, sizeof (timebuf)), VTY_NEWLINE); vty_out (vty, " Last SPF duration %s%s", ospf_timeval_dump (&ospf->ts_spf_duration, timebuf, sizeof (timebuf)), VTY_NEWLINE); } else vty_out (vty, "has not been run%s", VTY_NEWLINE); vty_out (vty, " SPF timer %s%s%s", (ospf->t_spf_calc ? "due in " : "is "), ospf_timer_dump (ospf->t_spf_calc, timebuf, sizeof (timebuf)), 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. Checksum Sum 0x%08x%s", ospf_lsdb_count (ospf->lsdb, OSPF_AS_EXTERNAL_LSA), ospf_lsdb_checksum (ospf->lsdb, OSPF_AS_EXTERNAL_LSA), VTY_NEWLINE); vty_out (vty, " Number of opaque AS LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (ospf->lsdb, OSPF_OPAQUE_AS_LSA), ospf_lsdb_checksum (ospf->lsdb, OSPF_OPAQUE_AS_LSA), VTY_NEWLINE); /* Show number of areas attached. */ vty_out (vty, " Number of areas attached to this router: %d%s", listcount (ospf->areas), VTY_NEWLINE); if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) vty_out(vty, " All adjacency changes are logged%s",VTY_NEWLINE); else vty_out(vty, " Adjacency changes are logged%s",VTY_NEWLINE); } vty_out (vty, "%s",VTY_NEWLINE); /* Show each area status. */ for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) show_ip_ospf_area (vty, area); return CMD_SUCCESS; } static void show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf, struct interface *ifp) { int is_up; struct ospf_neighbor *nbr; struct route_node *rn; /* Is interface up? */ vty_out (vty, "%s is %s%s", ifp->name, ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE); vty_out (vty, " ifindex %u, MTU %u bytes, BW %u Kbit %s%s", ifp->ifindex, ifp->mtu, ifp->bandwidth, if_flag_dump(ifp->flags), VTY_NEWLINE); /* Is interface OSPF enabled? */ if (ospf_oi_count(ifp) == 0) { vty_out (vty, " OSPF not enabled on this interface%s", VTY_NEWLINE); return; } else if (!is_up) { vty_out (vty, " OSPF is enabled, but not running 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); if (oi->connected->destination || oi->type == OSPF_IFTYPE_VIRTUALLINK) { struct in_addr *dest; const char *dstr; if (CONNECTED_PEER(oi->connected) || oi->type == OSPF_IFTYPE_VIRTUALLINK) dstr = "Peer"; else dstr = "Broadcast"; /* For Vlinks, showing the peer address is probably more * informative than the local interface that is being used */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) dest = &oi->vl_data->peer_addr; else dest = &oi->connected->destination->u.prefix4; vty_out (vty, " %s %s,", dstr, inet_ntoa (*dest)); } vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area), VTY_NEWLINE); vty_out (vty, " MTU mismatch detection:%s%s", OSPF_IF_PARAM(oi, mtu_ignore) ? "disabled" : "enabled", 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); } } /* Next network-LSA sequence number we'll use, if we're elected DR */ if (oi->params && ntohl (oi->params->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER) vty_out (vty, " Saved Network-LSA sequence number 0x%x%s", ntohl (oi->params->network_lsa_seqnum), VTY_NEWLINE); vty_out (vty, " Multicast group memberships:"); if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) || OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) vty_out (vty, " OSPFAllRouters"); if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) vty_out (vty, " OSPFDesignatedRouters"); } else vty_out (vty, " "); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Timer intervals configured,"); vty_out (vty, " Hello "); if (OSPF_IF_PARAM (oi, fast_hello) == 0) vty_out (vty, "%ds,", OSPF_IF_PARAM (oi, v_hello)); else vty_out (vty, "%dms,", 1000 / OSPF_IF_PARAM (oi, fast_hello)); vty_out (vty, " Dead %ds, Wait %ds, Retransmit %d%s", OSPF_IF_PARAM (oi, v_wait), OSPF_IF_PARAM (oi, v_wait), OSPF_IF_PARAM (oi, retransmit_interval), VTY_NEWLINE); if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_ACTIVE) { char timebuf[OSPF_TIME_DUMP_SIZE]; vty_out (vty, " Hello due in %s%s", ospf_timer_dump (oi->t_hello, timebuf, sizeof(timebuf)), VTY_NEWLINE); } else /* passive-interface 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; struct listnode *node; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, "OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } /* Show All Interfaces. */ if (argc == 0) for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) show_ip_ospf_interface_sub (vty, ospf, ifp); /* 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; } static void show_ip_ospf_neighbour_header (struct vty *vty) { vty_out (vty, "%s%-15s %3s %-15s %9s %-15s %-20s %5s %5s %5s%s", VTY_NEWLINE, "Neighbor ID", "Pri", "State", "Dead Time", "Address", "Interface", "RXmtL", "RqstL", "DBsmL", VTY_NEWLINE); } static 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[OSPF_TIME_DUMP_SIZE]; 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 ", "-", nbr->priority, msgbuf); else vty_out (vty, "%-15s %3d %-15s ", inet_ntoa (nbr->router_id), nbr->priority, msgbuf); vty_out (vty, "%9s ", ospf_timer_dump (nbr->t_inactivity, timebuf, sizeof(timebuf))); vty_out (vty, "%-15s ", inet_ntoa (nbr->src)); vty_out (vty, "%-20s %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; struct ospf_interface *oi; struct listnode *node; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } show_ip_ospf_neighbour_header (vty); for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) show_ip_ospf_neighbor_sub (vty, oi); 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 = ospf_lookup (); struct listnode *node; struct ospf_interface *oi; if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } show_ip_ospf_neighbour_header (vty); for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { struct listnode *nbr_node; struct ospf_nbr_nbma *nbr_nbma; show_ip_ospf_neighbor_sub (vty, oi); /* print Down neighbor status */ for (ALL_LIST_ELEMENTS_RO (oi->nbr_nbma, nbr_node, nbr_nbma)) { if (nbr_nbma->nbr == NULL || nbr_nbma->nbr->state == NSM_Down) { vty_out (vty, "%-15s %3d %-15s %9s ", "-", nbr_nbma->priority, "Down", "-"); vty_out (vty, "%-15s %-20s %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 IFNAME", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n" "Interface name\n") { struct ospf *ospf; struct interface *ifp; struct route_node *rn; ifp = if_lookup_by_name (argv[0]); if (!ifp) { vty_out (vty, "No such interface.%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; } show_ip_ospf_neighbour_header (vty); for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (oi == NULL) continue; show_ip_ospf_neighbor_sub (vty, oi); } return CMD_SUCCESS; } static void show_ip_ospf_nbr_nbma_detail_sub (struct vty *vty, struct ospf_interface *oi, struct ospf_nbr_nbma *nbr_nbma) { char timebuf[OSPF_TIME_DUMP_SIZE]; /* 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, sizeof(timebuf)), VTY_NEWLINE); /* Show poll-interval timer thread. */ vty_out (vty, " Thread Poll Timer %s%s", nbr_nbma->t_poll != NULL ? "on" : "off", VTY_NEWLINE); } static void show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi, struct ospf_neighbor *nbr) { char timebuf[OSPF_TIME_DUMP_SIZE]; /* 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); if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) { struct timeval res = tv_sub (recent_relative_time (), nbr->ts_last_progress); vty_out (vty, " Most recent state change statistics:%s", VTY_NEWLINE); vty_out (vty, " Progressive change %s ago%s", ospf_timeval_dump (&res, timebuf, sizeof(timebuf)), VTY_NEWLINE); } if (nbr->ts_last_regress.tv_sec || nbr->ts_last_regress.tv_usec) { struct timeval res = tv_sub (recent_relative_time (), nbr->ts_last_regress); vty_out (vty, " Regressive change %s ago, due to %s%s", ospf_timeval_dump (&res, timebuf, sizeof(timebuf)), (nbr->last_regress_str ? nbr->last_regress_str : "??"), 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, sizeof (timebuf)), 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; struct listnode *node; struct ospf_neighbor *nbr; struct ospf_interface *oi; 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 (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if ((nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &router_id))) show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); 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; struct ospf_interface *oi; struct listnode *node; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { 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; struct listnode *node; struct ospf_interface *oi; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { struct route_node *rn; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; 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) { struct listnode *nd; for (ALL_LIST_ELEMENTS_RO (oi->nbr_nbma, nd, nbr_nbma)) 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 IFNAME detail", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n" "Interface name\n" "detail of all neighbors") { struct ospf *ospf; struct ospf_interface *oi; struct interface *ifp; struct route_node *rn, *nrn; struct ospf_neighbor *nbr; ifp = if_lookup_by_name (argv[0]); if (!ifp) { vty_out (vty, "No such interface.%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 (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) if ((oi = rn->info)) for (nrn = route_top (oi->nbrs); nrn; nrn = route_next (nrn)) if ((nbr = nrn->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 */ static 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: case OSPF_AS_NSSA_LSA: 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: case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: default: break; } vty_out (vty, VTY_NEWLINE); } return 0; } static const char *show_database_desc[] = { "unknown", "Router Link States", "Net Link States", "Summary Link States", "ASBR-Summary Link States", "AS External Link States", "Group Membership LSA", "NSSA-external Link States", "Type-8 LSA", "Link-Local Opaque-LSA", "Area-Local Opaque-LSA", "AS-external Opaque-LSA", }; static const 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", " --- header for Group Member ----", "Link ID ADV Router Age Seq# CkSum Route", " --- 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", }; static 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: 0x%-2x : %s%s", lsa->data->options, ospf_options_dump(lsa->data->options), VTY_NEWLINE); vty_out (vty, " LS Flags: 0x%-2x %s%s", lsa->flags, ((lsa->flags & OSPF_LSA_LOCAL_XLT) ? "(Translated from Type-7)" : ""), 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); } const char *link_type_desc[] = { "(null)", "another Router (point-to-point)", "a Transit Network", "Stub Network", "a Virtual Link", }; const char *link_id_desc[] = { "(null)", "Neighboring Router ID", "Designated Router address", "Net", "Neighboring Router ID", }; const char *link_data_desc[] = { "(null)", "Router Interface address", "Router Interface address", "Network Mask", "Router Interface address", }; /* Show router-LSA each Link information. */ static void show_ip_ospf_database_router_links (struct vty *vty, struct router_lsa *rl) { int len, type; unsigned int i; 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. */ static 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); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } /* Show network-LSA detail information. */ static 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. */ static 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); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } /* Show summary-ASBR-LSA detail information. */ static 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); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } /* Show AS-external-LSA detail information. */ static 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; } #if 0 static 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_debug( " Network Mask: /%d%s", ip_masklen (al->mask), "\n"); zlog_debug( " Metric Type: %s%s", IS_EXTERNAL_METRIC (al->e[0].tos) ? "2 (Larger than any link state path)" : "1", "\n"); zlog_debug( " TOS: 0%s", "\n"); zlog_debug( " Metric: %d%s", GET_METRIC (al->e[0].metric), "\n"); zlog_debug( " Forward Address: %s%s", inet_ntoa (al->e[0].fwd_addr), "\n"); zlog_debug( " External Route Tag: %lu%s%s", (u_long)ntohl (al->e[0].route_tag), "\n", "\n"); return 0; } #endif /* Show AS-NSSA-LSA detail information. */ static 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: %lu%s%s", (u_long)ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); } return 0; } static int show_func_dummy (struct vty *vty, struct ospf_lsa *lsa) { return 0; } static 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; } 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, show_func_dummy, show_as_nssa_lsa_detail, /* almost same as external */ NULL, /* type-8 */ show_opaque_lsa_detail, show_opaque_lsa_detail, show_opaque_lsa_detail, }; static 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; } } static 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)) { 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. */ static void show_lsa_detail (struct vty *vty, struct ospf *ospf, int type, struct in_addr *id, struct in_addr *adv_router) { struct listnode *node; struct ospf_area *area; switch (type) { case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_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 (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { 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; } } static 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)) { if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) continue; if (show_function[lsa->data->type] != NULL) show_function[lsa->data->type] (vty, lsa); } } /* Show detail LSA information. */ static void show_lsa_detail_adv_router (struct vty *vty, struct ospf *ospf, int type, struct in_addr *adv_router) { struct listnode *node; struct ospf_area *area; switch (type) { case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_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 (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { 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; } } static void show_ip_ospf_database_summary (struct vty *vty, struct ospf *ospf, int self) { struct ospf_lsa *lsa; struct route_node *rn; struct ospf_area *area; struct listnode *node; int type; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) { switch (type) { case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_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: case OSPF_OPAQUE_AS_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); } static void show_ip_ospf_database_maxage (struct vty *vty, struct ospf *ospf) { struct route_node *rn; vty_out (vty, "%s MaxAge Link States:%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (rn = route_top (ospf->maxage_lsa); rn; rn = route_next (rn)) { struct ospf_lsa *lsa; if ((lsa = rn->info) != 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); } } } #define OSPF_LSA_TYPE_NSSA_DESC "NSSA external link state\n" #define OSPF_LSA_TYPE_NSSA_CMD_STR "|nssa-external" #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" #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) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); 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; else if (strncmp (argv[0], "ns", 2) == 0) type = OSPF_AS_NSSA_LSA; 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; } 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; 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) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); 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; else if (strncmp (argv[0], "ns", 2) == 0) type = OSPF_AS_NSSA_LSA; 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; 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; 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[0], &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[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; } 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 ((char *) 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 == 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; } 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 ((char *) 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_u32_inet4_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_u32_cmd, "ip ospf cost <1-65535>", "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost") ALIAS (ip_ospf_cost, ospf_cost_u32_cmd, "ospf cost <1-65535>", "OSPF interface commands\n" "Interface cost\n" "Cost") ALIAS (ip_ospf_cost, ospf_cost_u32_inet4_cmd, "ospf cost <1-65535> A.B.C.D", "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFUN (no_ip_ospf_cost, no_ip_ospf_cost_inet4_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") ALIAS (no_ip_ospf_cost, no_ospf_cost_inet4_cmd, "no ospf cost A.B.C.D", NO_STR "OSPF interface commands\n" "Interface cost\n" "Address of interface") DEFUN (no_ip_ospf_cost2, no_ip_ospf_cost_u32_cmd, "no ip ospf cost <1-65535>", NO_STR "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost") { struct interface *ifp = vty->index; struct in_addr addr; u_int32_t cost; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); /* According to the semantics we are mimicking "no ip ospf cost N" is * always treated as "no ip ospf cost" regardless of the actual value * of N already configured for the interface. Thus the first argument * is always checked to be a number, but is ignored after that. */ cost = strtol (argv[0], NULL, 10); 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_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_cost2, no_ospf_cost_u32_cmd, "no ospf cost <1-65535>", NO_STR "OSPF interface commands\n" "Interface cost\n" "Cost") ALIAS (no_ip_ospf_cost2, no_ip_ospf_cost_u32_inet4_cmd, "no ip ospf cost <1-65535> A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") ALIAS (no_ip_ospf_cost2, no_ospf_cost_u32_inet4_cmd, "no ospf cost <1-65535> A.B.C.D", NO_STR "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") static 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); } } static int ospf_vty_dead_interval_set (struct vty *vty, const char *interval_str, const char *nbr_str, const char *fast_hello_str) { struct interface *ifp = vty->index; u_int32_t seconds; u_char hellomult; struct in_addr addr; int ret; struct ospf_if_params *params; struct ospf_interface *oi; struct route_node *rn; params = IF_DEF_PARAMS (ifp); if (nbr_str) { ret = inet_aton(nbr_str, &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); } if (interval_str) { VTY_GET_INTEGER_RANGE ("Router Dead Interval", seconds, interval_str, 1, 65535); /* reset fast_hello too, just to be sure */ UNSET_IF_PARAM (params, fast_hello); params->fast_hello = OSPF_FAST_HELLO_DEFAULT; } else if (fast_hello_str) { VTY_GET_INTEGER_RANGE ("Hello Multiplier", hellomult, fast_hello_str, 1, 10); /* 1s dead-interval with sub-second hellos desired */ seconds = OSPF_ROUTER_DEAD_INTERVAL_MINIMAL; SET_IF_PARAM (params, fast_hello); params->fast_hello = hellomult; } else { vty_out (vty, "Please specify dead-interval or hello-multiplier%s", VTY_NEWLINE); return CMD_WARNING; } SET_IF_PARAM (params, v_wait); params->v_wait = seconds; /* Update timer values in neighbor structure. */ if (nbr_str) { struct ospf *ospf; if ((ospf = ospf_lookup())) { 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; } 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\n") { if (argc == 2) return ospf_vty_dead_interval_set (vty, argv[0], argv[1], NULL); else return ospf_vty_dead_interval_set (vty, argv[0], NULL, NULL); } 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 (ip_ospf_dead_interval_minimal, ip_ospf_dead_interval_minimal_addr_cmd, "ip ospf dead-interval minimal hello-multiplier <1-10> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Minimal 1s dead-interval with fast sub-second hellos\n" "Hello multiplier factor\n" "Number of Hellos to send each second\n" "Address of interface\n") { if (argc == 2) return ospf_vty_dead_interval_set (vty, NULL, argv[1], argv[0]); else return ospf_vty_dead_interval_set (vty, NULL, NULL, argv[0]); } ALIAS (ip_ospf_dead_interval_minimal, ip_ospf_dead_interval_minimal_cmd, "ip ospf dead-interval minimal hello-multiplier <1-10>", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Minimal 1s dead-interval with fast sub-second hellos\n" "Hello multiplier factor\n" "Number of Hellos to send each second\n") DEFUN (no_ip_ospf_dead_interval, no_ip_ospf_dead_interval_addr_cmd, "no ip ospf dead-interval <1-65535> A.B.C.D", NO_STR "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; struct in_addr addr; int ret; struct ospf_if_params *params; struct ospf_interface *oi; struct route_node *rn; 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; } UNSET_IF_PARAM (params, v_wait); params->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; UNSET_IF_PARAM (params, fast_hello); params->fast_hello = OSPF_FAST_HELLO_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) { struct ospf *ospf; if ((ospf = ospf_lookup())) { 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_seconds_cmd, "no ip ospf dead-interval <1-65535>", NO_STR "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") 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 <1-65535> A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\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 == 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, v_hello); params->v_hello = OSPF_HELLO_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_seconds_cmd, "no ip ospf hello-interval <1-65535>", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") 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; if (old_type == OSPF_IFTYPE_LOOPBACK) { vty_out (vty, "This is a loopback interface. Can't set network type.%s", VTY_NEWLINE); return CMD_WARNING; } 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); ospf_if_reset_type (ifp, IF_DEF_PARAMS (ifp)->type); 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; IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp); if (IF_DEF_PARAMS (ifp)->type == old_type) return CMD_SUCCESS; ospf_if_reset_type (ifp, IF_DEF_PARAMS (ifp)->type); 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; long 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 (ip_ospf_area, ip_ospf_area_cmd, "ip ospf area (A.B.C.D|<0-4294967295>) [A.B.C.D]", "IP Information\n" "OSPF interface commands\n" "Enable OSPF on this interface\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Address of interface\n") { struct interface *ifp = vty->index; struct in_addr area_id; struct in_addr addr; int format; struct ospf_if_params *params; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); OSPF_VTY_GET_IF_PARAMS(ifp, params, 1, addr, VTY_SET); if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { vty_out (vty, "There is already an interface area statement.%s", VTY_NEWLINE); return CMD_WARNING; } if (memcmp (ifp->name, "VLINK", 5) == 0) { vty_out (vty, "Cannot enable OSPF on a virtual link.%s", VTY_NEWLINE); return CMD_WARNING; } SET_IF_PARAM (params, if_area); params->if_area = area_id; ospf_interface_area_set (ifp); return CMD_SUCCESS; } DEFUN (no_ip_ospf_area, no_ip_ospf_area_cmd, "no ip ospf area [A.B.C.D]", NO_STR "IP Information\n" "OSPF interface commands\n" "Disable OSPF on this interface\n" "Address of interface\n") { struct interface *ifp = vty->index; struct ospf_if_params *params; struct in_addr addr; OSPF_VTY_GET_IF_PARAMS(ifp, params, 0, addr, VTY_UNSET); if (!OSPF_IF_PARAM_CONFIGURED(params, if_area)) return CMD_SUCCESS; OSPF_VTY_PARAM_UNSET(params, if_area, ifp, addr); ospf_interface_area_unset (ifp); return CMD_SUCCESS; } DEFUN (ospf_redistribute_source, ospf_redistribute_source_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " {metric <0-16777214>|metric-type (1|2)|route-map WORD}", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "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; if (argc < 4) return CMD_WARNING; /* should not happen */ /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ if (argv[1] != NULL) if (!str2metric (argv[1], &metric)) return CMD_WARNING; /* Get metric type. */ if (argv[2] != NULL) if (!str2metric_type (argv[2], &type)) return CMD_WARNING; if (argv[3] != NULL) ospf_routemap_set (ospf, source, argv[3]); else ospf_routemap_unset (ospf, source); return ospf_redistribute_set (ospf, source, type, metric); } DEFUN (no_ospf_redistribute_source, no_ospf_redistribute_source_cmd, "no redistribute " QUAGGA_REDIST_STR_OSPFD, NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; int source; source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) 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 " QUAGGA_REDIST_STR_OSPFD, "Filter networks in routing updates\n" "Access-list name\n" OUT_STR QUAGGA_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; int source; /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[1]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) 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 " QUAGGA_REDIST_STR_OSPFD, NO_STR "Filter networks in routing updates\n" "Access-list name\n" OUT_STR QUAGGA_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; int source; source = proto_redistnum(AFI_IP, argv[1]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; return ospf_distribute_list_out_unset (ospf, source, argv[0]); } /* Default information originate. */ DEFUN (ospf_default_information_originate, ospf_default_information_originate_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 default_originate = DEFAULT_ORIGINATE_ZEBRA; int type = -1; int metric = -1; if (argc < 4) return CMD_WARNING; /* this should not happen */ /* Check whether "always" was specified */ if (argv[0] != NULL) default_originate = DEFAULT_ORIGINATE_ALWAYS; /* Get metric value. */ if (argv[1] != NULL) if (!str2metric (argv[1], &metric)) return CMD_WARNING; /* Get metric type. */ if (argv[2] != NULL) if (!str2metric_type (argv[2], &type)) return CMD_WARNING; if (argv[3] != NULL) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[3]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, default_originate, type, metric); } 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; p.family = AF_INET; p.prefix.s_addr = 0; p.prefixlen = 0; ospf_external_lsa_flush (ospf, DEFAULT_ROUTE, &p, 0); 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 {intra-area|inter-area|external}", NO_STR "Define an administrative distance\n" "OSPF Administrative distance\n" "OSPF Distance\n" "Intra-area routes\n" "Inter-area routes\n" "External routes\n") { struct ospf *ospf = vty->index; if (argc < 3) return CMD_WARNING; if (argv[0] != NULL) ospf->distance_intra = 0; if (argv[1] != NULL) ospf->distance_inter = 0; if (argv[2] != NULL) ospf->distance_external = 0; if (argv[0] || argv[1] || argv[2]) return CMD_SUCCESS; /* If no arguments are given, clear all distance information */ ospf->distance_intra = 0; ospf->distance_inter = 0; ospf->distance_external = 0; return CMD_SUCCESS; } DEFUN (ospf_distance_ospf, ospf_distance_ospf_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; if (argc < 3) /* should not happen */ return CMD_WARNING; if (!argv[0] && !argv[1] && !argv[2]) { vty_out(vty, "%% Command incomplete. (Arguments required)%s", VTY_NEWLINE); return CMD_WARNING; } if (argv[0] != NULL) ospf->distance_intra = atoi(argv[0]); if (argv[1] != NULL) ospf->distance_inter = atoi(argv[1]); if (argv[2] != NULL) ospf->distance_external = 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; } DEFUN (ip_ospf_mtu_ignore, ip_ospf_mtu_ignore_addr_cmd, "ip ospf mtu-ignore A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; 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_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } params->mtu_ignore = 1; if (params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT) SET_IF_PARAM (params, mtu_ignore); else { UNSET_IF_PARAM (params, mtu_ignore); if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } } return CMD_SUCCESS; } ALIAS (ip_ospf_mtu_ignore, ip_ospf_mtu_ignore_cmd, "ip ospf mtu-ignore", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") DEFUN (no_ip_ospf_mtu_ignore, no_ip_ospf_mtu_ignore_addr_cmd, "no ip ospf mtu-ignore A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; 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_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } params->mtu_ignore = 0; if (params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT) SET_IF_PARAM (params, mtu_ignore); else { UNSET_IF_PARAM (params, mtu_ignore); 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_mtu_ignore, no_ip_ospf_mtu_ignore_cmd, "no ip ospf mtu-ignore", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") DEFUN (ospf_max_metric_router_lsa_admin, ospf_max_metric_router_lsa_admin_cmd, "max-metric router-lsa administrative", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") { struct listnode *ln; struct ospf_area *area; struct ospf *ospf = vty->index; for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) ospf_router_lsa_update_area (area); } /* Allows for areas configured later to get the property */ ospf->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_SET; return CMD_SUCCESS; } DEFUN (no_ospf_max_metric_router_lsa_admin, no_ospf_max_metric_router_lsa_admin_cmd, "no max-metric router-lsa administrative", NO_STR "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") { struct listnode *ln; struct ospf_area *area; struct ospf *ospf = vty->index; for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { UNSET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); /* Don't trample on the start-up stub timer */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED) && !area->t_stub_router) { UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); ospf_router_lsa_update_area (area); } } ospf->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET; return CMD_SUCCESS; } DEFUN (ospf_max_metric_router_lsa_startup, ospf_max_metric_router_lsa_startup_cmd, "max-metric router-lsa on-startup <5-86400>", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Automatically advertise stub Router-LSA on startup of OSPF\n" "Time (seconds) to advertise self as stub-router\n") { unsigned int seconds; struct ospf *ospf = vty->index; if (argc != 1) { vty_out (vty, "%% Must supply stub-router period"); return CMD_WARNING; } VTY_GET_INTEGER ("stub-router startup period", seconds, argv[0]); ospf->stub_router_startup_time = seconds; return CMD_SUCCESS; } DEFUN (no_ospf_max_metric_router_lsa_startup, no_ospf_max_metric_router_lsa_startup_cmd, "no max-metric router-lsa on-startup", NO_STR "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Automatically advertise stub Router-LSA on startup of OSPF\n") { struct listnode *ln; struct ospf_area *area; struct ospf *ospf = vty->index; ospf->stub_router_startup_time = OSPF_STUB_ROUTER_UNCONFIGURED; for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); OSPF_TIMER_OFF (area->t_stub_router); /* Don't trample on admin stub routed */ if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) { UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); ospf_router_lsa_update_area (area); } } return CMD_SUCCESS; } DEFUN (ospf_max_metric_router_lsa_shutdown, ospf_max_metric_router_lsa_shutdown_cmd, "max-metric router-lsa on-shutdown <5-86400>", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Advertise stub-router prior to full shutdown of OSPF\n" "Time (seconds) to wait till full shutdown\n") { unsigned int seconds; struct ospf *ospf = vty->index; if (argc != 1) { vty_out (vty, "%% Must supply stub-router shutdown period"); return CMD_WARNING; } VTY_GET_INTEGER ("stub-router shutdown wait period", seconds, argv[0]); ospf->stub_router_shutdown_time = seconds; return CMD_SUCCESS; } DEFUN (no_ospf_max_metric_router_lsa_shutdown, no_ospf_max_metric_router_lsa_shutdown_cmd, "no max-metric router-lsa on-shutdown", NO_STR "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Advertise stub-router prior to full shutdown of OSPF\n") { struct ospf *ospf = vty->index; ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; return CMD_SUCCESS; } static void config_write_stub_router (struct vty *vty, struct ospf *ospf) { struct listnode *ln; struct ospf_area *area; if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) vty_out (vty, " max-metric router-lsa on-startup %u%s", ospf->stub_router_startup_time, VTY_NEWLINE); if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) vty_out (vty, " max-metric router-lsa on-shutdown %u%s", ospf->stub_router_shutdown_time, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) { vty_out (vty, " max-metric router-lsa administrative%s", VTY_NEWLINE); break; } } return; } static void show_ip_ospf_route_network (struct vty *vty, struct route_table *rt) { struct route_node *rn; struct ospf_route *or; struct listnode *pnode, *pnnode; 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 (ALL_LIST_ELEMENTS (or->paths, pnode, pnnode, path)) { if (if_lookup_by_index(path->ifindex)) { if (path->nexthop.s_addr == 0) vty_out (vty, "%24s directly attached to %s%s", "", ifindex2ifname (path->ifindex), VTY_NEWLINE); else vty_out (vty, "%24s via %s, %s%s", "", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex), VTY_NEWLINE); } } } vty_out (vty, "%s", VTY_NEWLINE); } static void show_ip_ospf_route_router (struct vty *vty, struct route_table *rtrs) { struct route_node *rn; struct ospf_route *or; struct listnode *pnode; struct listnode *node; 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 (ALL_LIST_ELEMENTS_RO ((struct list *)rn->info, node, or)) { if (flag++) vty_out (vty, "%24s", ""); /* 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 (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path)) { if (if_lookup_by_index(path->ifindex)) { if (path->nexthop.s_addr == 0) vty_out (vty, "%24s directly attached to %s%s", "", ifindex2ifname (path->ifindex), VTY_NEWLINE); else vty_out (vty, "%24s via %s, %s%s", "", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex), VTY_NEWLINE); } } } } vty_out (vty, "%s", VTY_NEWLINE); } static void show_ip_ospf_route_external (struct vty *vty, struct route_table *rt) { struct route_node *rn; struct ospf_route *er; struct listnode *pnode, *pnnode; 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 (ALL_LIST_ELEMENTS (er->paths, pnode, pnnode, path)) { if (if_lookup_by_index(path->ifindex)) { if (path->nexthop.s_addr == 0) vty_out (vty, "%24s directly attached to %s%s", "", ifindex2ifname (path->ifindex), VTY_NEWLINE); else vty_out (vty, "%24s via %s, %s%s", "", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex), VTY_NEWLINE); } } } vty_out (vty, "%s", VTY_NEWLINE); } 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; if ((ospf = ospf_lookup ()) == NULL) { vty_out (vty, " OSPF Routing Process 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; } 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; if ((ospf = ospf_lookup ()) == NULL) { vty_out (vty, " OSPF Routing Process 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; } const char *ospf_abr_type_str[] = { "unknown", "standard", "ibm", "cisco", "shortcut" }; const char *ospf_shortcut_mode_str[] = { "default", "enable", "disable" }; static 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)); } const 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. */ static int config_write_interface (struct vty *vty) { struct listnode *n1, *n2; struct interface *ifp; struct crypt_key *ck; int write = 0; struct route_node *rn = NULL; struct ospf_if_params *params; for (ALL_LIST_ELEMENTS_RO (iflist, n1, ifp)) { 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_LOOPBACK) { if (params->type != ospf_default_iftype(ifp)) { 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) { const 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 (ALL_LIST_ELEMENTS_RO (params->auth_crypt, n2, ck)) { 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 "); /* fast hello ? */ if (OSPF_IF_PARAM_CONFIGURED (params, fast_hello)) vty_out (vty, "minimal hello-multiplier %d", params->fast_hello); else vty_out (vty, "%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); } /* Area print. */ if (OSPF_IF_PARAM_CONFIGURED (params, if_area)) { vty_out (vty, " ip ospf area %s", inet_ntoa (params->if_area)); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* MTU ignore print. */ if (OSPF_IF_PARAM_CONFIGURED (params, mtu_ignore) && params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT) { if (params->mtu_ignore == 0) vty_out (vty, " no ip ospf mtu-ignore"); else vty_out (vty, " ip ospf mtu-ignore"); 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); ospf_opaque_config_write_if (vty, ifp); } return write; } static 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 ((char *) buf, inet_ntoa (n->area_id), INET_ADDRSTRLEN); else sprintf ((char *) 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; } static int config_write_ospf_area (struct vty *vty, struct ospf *ospf) { struct listnode *node; struct ospf_area *area; u_char buf[INET_ADDRSTRLEN]; /* Area configuration print. */ for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { struct route_node *rn1; area_id2str ((char *) 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) || (area->external_routing == OSPF_AREA_NSSA) ) { if (area->external_routing == OSPF_AREA_STUB) vty_out (vty, " area %s stub", buf); else if (area->external_routing == OSPF_AREA_NSSA) { vty_out (vty, " area %s nssa", buf); switch (area->NSSATranslatorRole) { case OSPF_NSSA_ROLE_NEVER: vty_out (vty, " translate-never"); break; case OSPF_NSSA_ROLE_ALWAYS: vty_out (vty, " translate-always"); break; case OSPF_NSSA_ROLE_CANDIDATE: default: vty_out (vty, " translate-candidate"); } } 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 != OSPF_AREA_RANGE_COST_UNSPEC) 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; } static 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; } static int config_write_virtual_link (struct vty *vty, struct ospf *ospf) { struct listnode *node; struct ospf_vl_data *vl_data; u_char buf[INET_ADDRSTRLEN]; /* Virtual-Link print */ for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) { struct listnode *n2; struct crypt_key *ck; struct ospf_interface *oi; if (vl_data != NULL) { memset (buf, 0, INET_ADDRSTRLEN); if (vl_data->format == OSPF_AREA_ID_FORMAT_ADDRESS) strncpy ((char *) buf, inet_ntoa (vl_data->vl_area_id), INET_ADDRSTRLEN); else sprintf ((char *) 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 (ALL_LIST_ELEMENTS_RO (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_crypt, n2, ck)) 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; } static 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 && vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) { vty_out (vty, " redistribute %s", zebra_route_string(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; } static 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; } static 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 (DISTRIBUTE_NAME (ospf, type)) vty_out (vty, " distribute-list %s out %s%s", DISTRIBUTE_NAME (ospf, type), zebra_route_string(type), VTY_NEWLINE); /* default-information print. */ if (ospf->default_originate != DEFAULT_ORIGINATE_NONE) { vty_out (vty, " default-information originate"); if (ospf->default_originate == DEFAULT_ORIGINATE_ALWAYS) vty_out (vty, " 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; } static 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. */ static int ospf_config_write (struct vty *vty) { struct ospf *ospf; struct interface *ifp; struct ospf_interface *oi; struct 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_DEFAULT) vty_out (vty, " ospf abr-type %s%s", ospf_abr_type_str[ospf->abr_type], VTY_NEWLINE); /* log-adjacency-changes flag print. */ if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES)) { vty_out(vty, " log-adjacency-changes"); if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) vty_out(vty, " detail"); vty_out(vty, "%s", 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, "! Important: ensure reference bandwidth " "is consistent across all routers%s", VTY_NEWLINE); vty_out (vty, " auto-cost reference-bandwidth %d%s", ospf->ref_bandwidth / 1000, VTY_NEWLINE); } /* LSA timers */ if (ospf->min_ls_interval != OSPF_MIN_LS_INTERVAL) vty_out (vty, " timers throttle lsa all %d%s", ospf->min_ls_interval, VTY_NEWLINE); if (ospf->min_ls_arrival != OSPF_MIN_LS_ARRIVAL) vty_out (vty, " timers lsa arrival %d%s", ospf->min_ls_arrival, VTY_NEWLINE); /* SPF timers print. */ if (ospf->spf_delay != OSPF_SPF_DELAY_DEFAULT || ospf->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT || ospf->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT) vty_out (vty, " timers throttle spf %d %d %d%s", ospf->spf_delay, ospf->spf_holdtime, ospf->spf_max_holdtime, VTY_NEWLINE); /* Max-metric router-lsa print */ config_write_stub_router (vty, ospf); /* 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. */ if (ospf->passive_interface_default == OSPF_IF_PASSIVE) vty_out (vty, " passive-interface default%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), passive_interface) && IF_DEF_PARAMS (ifp)->passive_interface != ospf->passive_interface_default) { vty_out (vty, " %spassive-interface %s%s", IF_DEF_PARAMS (ifp)->passive_interface ? "" : "no ", ifp->name, VTY_NEWLINE); } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { if (!OSPF_IF_PARAM_CONFIGURED (oi->params, passive_interface)) continue; if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (oi->ifp), passive_interface)) { if (oi->params->passive_interface == IF_DEF_PARAMS (oi->ifp)->passive_interface) continue; } else if (oi->params->passive_interface == ospf->passive_interface_default) continue; vty_out (vty, " %spassive-interface %s %s%s", oi->params->passive_interface ? "" : "no ", oi->ifp->name, 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); ospf_opaque_config_write_router (vty, ospf); } return write; } void ospf_vty_show_init (void) { /* "show ip ospf" commands. */ install_element (VIEW_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); /* "show ip ospf interface" commands. */ install_element (VIEW_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); /* "show ip ospf route" commands. */ install_element (VIEW_NODE, &show_ip_ospf_route_cmd); install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd); } /* ospfd's interface node. */ static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 }; /* Initialization of OSPF interface. */ static void ospf_vty_if_init (void) { /* Install interface node. */ install_node (&interface_node, config_write_interface); install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_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_u32_inet4_cmd); install_element (INTERFACE_NODE, &ip_ospf_cost_u32_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_cost_u32_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_cost_u32_inet4_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_cost_inet4_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd); /* "ip ospf mtu-ignore" commands. */ install_element (INTERFACE_NODE, &ip_ospf_mtu_ignore_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_mtu_ignore_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_mtu_ignore_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_mtu_ignore_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, &ip_ospf_dead_interval_minimal_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_seconds_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); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_seconds_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); /* "ip ospf area" commands. */ install_element (INTERFACE_NODE, &ip_ospf_area_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_area_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_u32_cmd); install_element (INTERFACE_NODE, &ospf_cost_u32_inet4_cmd); install_element (INTERFACE_NODE, &no_ospf_cost_cmd); install_element (INTERFACE_NODE, &no_ospf_cost_u32_cmd); install_element (INTERFACE_NODE, &no_ospf_cost_u32_inet4_cmd); install_element (INTERFACE_NODE, &no_ospf_cost_inet4_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); } static void ospf_vty_zebra_init (void) { install_element (OSPF_NODE, &ospf_redistribute_source_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_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_cmd); #if 0 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); #endif /* 0 */ } static struct cmd_node ospf_node = { OSPF_NODE, "%s(config-router)# ", 1 }; static void ospf_interface_clear (struct interface *ifp) { if (!if_is_operative (ifp)) return; if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: clear by reset", ifp->name); ospf_if_reset(ifp); } DEFUN (clear_ip_ospf_interface, clear_ip_ospf_interface_cmd, "clear ip ospf interface [IFNAME]", CLEAR_STR IP_STR "OSPF information\n" "Interface information\n" "Interface name\n") { struct interface *ifp; struct listnode *node; if (argc == 0) /* Clear all the ospfv2 interfaces. */ { for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ospf_interface_clear(ifp); } else /* Interface name is specified. */ { if ((ifp = if_lookup_by_name (argv[0])) == NULL) vty_out (vty, "No such interface name%s", VTY_NEWLINE); else ospf_interface_clear(ifp); } return CMD_SUCCESS; } void ospf_vty_clear_init (void) { install_element (ENABLE_NODE, &clear_ip_ospf_interface_cmd); } /* Install OSPF related vty commands. */ void ospf_vty_init (void) { /* 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, &ospf_passive_interface_default_cmd); install_element (OSPF_NODE, &no_ospf_passive_interface_addr_cmd); install_element (OSPF_NODE, &no_ospf_passive_interface_cmd); install_element (OSPF_NODE, &no_ospf_passive_interface_default_cmd); /* "ospf abr-type" commands. */ install_element (OSPF_NODE, &ospf_abr_type_cmd); install_element (OSPF_NODE, &no_ospf_abr_type_cmd); /* "ospf log-adjacency-changes" commands. */ install_element (OSPF_NODE, &ospf_log_adjacency_changes_cmd); install_element (OSPF_NODE, &ospf_log_adjacency_changes_detail_cmd); install_element (OSPF_NODE, &no_ospf_log_adjacency_changes_cmd); install_element (OSPF_NODE, &no_ospf_log_adjacency_changes_detail_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); /* "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); 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); /* LSA timer commands */ install_element (OSPF_NODE, &ospf_timers_min_ls_interval_cmd); install_element (OSPF_NODE, &no_ospf_timers_min_ls_interval_cmd); install_element (OSPF_NODE, &ospf_timers_min_ls_arrival_cmd); install_element (OSPF_NODE, &no_ospf_timers_min_ls_arrival_cmd); /* SPF timer commands */ install_element (OSPF_NODE, &ospf_timers_spf_cmd); install_element (OSPF_NODE, &no_ospf_timers_spf_cmd); install_element (OSPF_NODE, &ospf_timers_throttle_spf_cmd); install_element (OSPF_NODE, &no_ospf_timers_throttle_spf_cmd); /* refresh timer commands */ 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); /* max-metric commands */ install_element (OSPF_NODE, &ospf_max_metric_router_lsa_admin_cmd); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_admin_cmd); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_startup_cmd); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_startup_cmd); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_shutdown_cmd); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_shutdown_cmd); /* reference bandwidth commands */ 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 (); } quagga-1.2.4/ospfd/ospf_vty.h000066400000000000000000000056351325323223500161310ustar00rootroot00000000000000/* 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. */ #ifndef _QUAGGA_OSPF_VTY_H #define _QUAGGA_OSPF_VTY_H /* Macros. */ #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. */ extern void ospf_vty_init (void); extern void ospf_vty_show_init (void); extern int ospf_str2area_id (const char *, struct in_addr *, int *); extern void ospf_vty_clear_init (void); #endif /* _QUAGGA_OSPF_VTY_H */ quagga-1.2.4/ospfd/ospf_zebra.c000066400000000000000000001106441325323223500164020ustar00rootroot00000000000000/* * 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 "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_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 */ #include "ospfd/ospf_te.h" /* Zebra structure to hold current status. */ struct zclient *zclient = NULL; /* For registering threads. */ extern struct thread_master *master; struct in_addr router_id_zebra; /* Router-id update message from zebra. */ static int ospf_router_id_update_zebra (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct ospf *ospf; struct prefix router_id; zebra_router_id_update_read(zclient->ibuf,&router_id); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) { char buf[128]; prefix2str(&router_id, buf, sizeof(buf)); zlog_debug("Zebra rcvd: router id update %s", buf); } router_id_zebra = router_id.u.prefix4; ospf = ospf_lookup (); if (ospf != NULL) ospf_router_id_update (ospf); return 0; } /* Inteface addition message from zebra. */ static int ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: interface add %s index %d flags %llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); assert (ifp->info); if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type)) { SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp); } ospf_if_update (NULL, ifp); #ifdef HAVE_SNMP ospf_snmp_if_update (ifp); #endif /* HAVE_SNMP */ return 0; } static int ospf_interface_delete (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { 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, vrf_id); 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_debug ("Zebra: interface delete %s index %d flags %llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)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); ifp->ifindex = IFINDEX_INTERNAL; return 0; } static struct interface * zebra_interface_if_lookup (struct stream *s, vrf_id_t vrf_id) { char ifname_tmp[INTERFACE_NAMSIZ]; /* Read interface name. */ stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); /* And look it up. */ return if_lookup_by_name_len(ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ)); } static int ospf_interface_state_up (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct ospf_interface *oi; struct route_node *rn; ifp = zebra_interface_if_lookup (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; /* Interface is already up. */ if (if_is_operative (ifp)) { /* Temporarily keep ifp values. */ struct interface if_tmp; memcpy (&if_tmp, ifp, sizeof (struct interface)); zebra_interface_if_set_value (zclient->ibuf, ifp); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: Interface[%s] state update.", ifp->name); if (if_tmp.bandwidth != ifp->bandwidth) { if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.", ifp->name, if_tmp.bandwidth, ifp->bandwidth); ospf_if_recalculate_output_cost (ifp); } if (if_tmp.mtu != ifp->mtu) { if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: Interface[%s] MTU change %u -> %u.", ifp->name, if_tmp.mtu, ifp->mtu); /* Must reset the interface (simulate down/up) when MTU changes. */ ospf_if_reset(ifp); } return 0; } zebra_interface_if_set_value (zclient->ibuf, ifp); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("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; } static int ospf_interface_state_down (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct ospf_interface *oi; struct route_node *node; ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("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; } static int ospf_interface_address_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; c = zebra_interface_address_read (command, zclient->ibuf, vrf_id); if (c == NULL) return 0; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) { char buf[128]; prefix2str(c->address, buf, sizeof(buf)); zlog_debug("Zebra: interface %s address add %s", c->ifp->name, buf); } ospf_if_update (NULL, c->ifp); #ifdef HAVE_SNMP ospf_snmp_if_update (c->ifp); #endif /* HAVE_SNMP */ return 0; } static int ospf_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct interface *ifp; struct ospf_interface *oi; struct route_node *rn; struct prefix p; c = zebra_interface_address_read (command, zclient->ibuf, vrf_id); if (c == NULL) return 0; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) { char buf[128]; prefix2str(c->address, buf, sizeof(buf)); zlog_debug("Zebra: interface %s address delete %s", c->ifp->name, buf); } ifp = c->ifp; p = *c->address; p.prefixlen = IPV4_MAX_PREFIXLEN; rn = route_node_lookup (IF_OIFS (ifp), &p); if (!rn) { connected_free (c); return 0; } assert (rn->info); oi = rn->info; route_unlock_node (rn); /* 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); return 0; } static int ospf_interface_link_params (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_link_params_read (zclient->ibuf); if (ifp == NULL) return 0; /* Update TE TLV */ ospf_mpls_te_update_if (ifp); 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; struct listnode *node; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF], VRF_DEFAULT)) { 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); /* Check if path type is ASE */ if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL) || (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)) && (or->u.ext.tag > 0) && (or->u.ext.tag <= ROUTE_TAG_MAX)) SET_FLAG (message, ZAPI_MESSAGE_TAG); /* Make packet. */ s = zclient->obuf; stream_reset (s); /* Put command, type, flags, message. */ zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT); stream_putc (s, ZEBRA_ROUTE_OSPF); stream_putc (s, flags); stream_putc (s, message); stream_putw (s, SAFI_UNICAST); /* 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->paths->count); /* Nexthop, ifindex, distance and metric information. */ for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) { if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); stream_put_in_addr (s, &path->nexthop); stream_putl (s, path->ifindex); } else 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->ifindex) stream_putl (s, path->ifindex); else stream_putl (s, 0); } if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra: Route add %s/%d nexthop %s", inet_ntop(AF_INET, &p->prefix, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, &path->nexthop, buf[1], sizeof(buf[1]))); } } 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); } if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) stream_putl (s, or->u.ext.tag); stream_putw_at (s, 0, stream_get_endp (s)); zclient_send_message(zclient); } } void ospf_zebra_delete (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; struct listnode *node; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF], VRF_DEFAULT)) { message = 0; flags = 0; /* Distance value. */ distance = ospf_distance_apply (p, or); /* Make packet. */ s = zclient->obuf; stream_reset (s); /* Put command, type, flags, message. */ zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE, VRF_DEFAULT); stream_putc (s, ZEBRA_ROUTE_OSPF); stream_putc (s, flags); stream_putc (s, message); stream_putw (s, SAFI_UNICAST); /* 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->paths->count); /* Nexthop, ifindex, distance and metric information. */ for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) { if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); stream_put_in_addr (s, &path->nexthop); stream_putl (s, path->ifindex); } else 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); stream_putl (s, path->ifindex); } if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra: Route delete %s/%d nexthop %s", inet_ntop(AF_INET, &p->prefix, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, &path->nexthop, buf[1], sizeof(buf[1]))); } } 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)); zclient_send_message(zclient); } } void ospf_zebra_add_discard (struct prefix_ipv4 *p) { struct zapi_ipv4 api; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF], VRF_DEFAULT)) { api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF; api.flags = ZEBRA_FLAG_BLACKHOLE; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 0; api.ifindex_num = 0; api.tag = 0; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Zebra: Route add discard %s/%d", inet_ntoa (p->prefix), p->prefixlen); } } void ospf_zebra_delete_discard (struct prefix_ipv4 *p) { struct zapi_ipv4 api; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_OSPF], VRF_DEFAULT)) { api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF; api.flags = ZEBRA_FLAG_BLACKHOLE; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 0; api.ifindex_num = 0; api.tag = 0; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Zebra: Route delete discard %s/%d", inet_ntoa (p->prefix), p->prefixlen); } } int ospf_is_type_redistributed (int type) { return (DEFAULT_ROUTE_TYPE (type)) ? vrf_bitmap_check (zclient->default_information, VRF_DEFAULT) : \ vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT); } 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_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", ospf_redist_string(type), metric_type (ospf, type), metric_value (ospf, type)); return CMD_SUCCESS; } ospf->dmetric[type].type = mtype; ospf->dmetric[type].value = mvalue; zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]", ospf_redist_string(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 (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Stop", ospf_redist_string(type)); ospf->dmetric[type].type = -1; ospf->dmetric[type].value = -1; /* Remove the routes from OSPF table. */ ospf_redistribute_withdraw (ospf, 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) { ospf->default_originate = originate; ospf->dmetric[DEFAULT_ROUTE].type = mtype; ospf->dmetric[DEFAULT_ROUTE].value = mvalue; if (ospf_is_type_redistributed (DEFAULT_ROUTE)) { /* if ospf->default_originate changes value, is calling ospf_external_lsa_refresh_default sufficient to implement the change? */ ospf_external_lsa_refresh_default (ospf); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", ospf_redist_string(DEFAULT_ROUTE), metric_type (ospf, DEFAULT_ROUTE), metric_value (ospf, DEFAULT_ROUTE)); return CMD_SUCCESS; } zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, VRF_DEFAULT); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("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, 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 (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, VRF_DEFAULT); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[DEFAULT]: Stop"); ospf_asbr_status_update (ospf, --ospf->redistribute); return CMD_SUCCESS; } static 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-external-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 listnode *node; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (prefix_match (oi->address, (struct prefix *) &ei->p)) 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_debug ("Redistribute[%s]: %s/%d filtered by ditribute-list.", ospf_redist_string(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_debug ("Redistribute[%s]: %s/%d filtered by route-map.", ospf_redist_string(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, const 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. */ static int ospf_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { 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; unsigned char plength = 0; 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; plength = stream_getc (s); p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); if (IPV4_NET127(ntohl(p.prefix.s_addr))) return 0; /* 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); /* XXX assert(api.ifindex_num == 1); */ 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); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) api.tag = stream_getl (s); else api.tag = 0; ospf = ospf_lookup (); if (ospf == NULL) return 0; if (command == ZEBRA_IPV4_ROUTE_ADD) { /* XXX|HACK|TODO|FIXME: * Maybe we should ignore reject/blackhole routes? Testing shows that * there is no problems though and this is only way to "summarize" * routes in ASBR at the moment. Maybe we need just a better generalised * solution for these types? * * if ( CHECK_FLAG (api.flags, ZEBRA_FLAG_BLACKHOLE) * || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT)) * return 0; */ /* Protocol tag overwrites all other tag value send by zebra */ if (ospf->dtag[api.type] > 0) api.tag = ospf->dtag[api.type]; ei = ospf_external_info_add (api.type, p, ifindex, nexthop, api.tag); 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_refresh_default (ospf); else ospf_external_lsa_flush (ospf, api.type, &p, ifindex /*, nexthop */); } return 0; } int ospf_distribute_list_out_set (struct ospf *ospf, int type, const 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, const 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. */ static 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; int type, default_refresh = 0; struct ospf *ospf; 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. */ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { rt = EXTERNAL_INFO (type); if (!rt) continue; for (rn = route_top (rt); rn; rn = route_next (rn)) if ((ei = rn->info) != NULL) { if (is_prefix_default (&ei->p)) default_refresh = 1; 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); } } if (default_refresh) ospf_external_lsa_refresh_default (ospf); return 0; } /* Update distribute-list and set timer to apply access-list. */ void ospf_distribute_list_update (struct ospf *ospf, uintptr_t type) { struct route_table *rt; /* External info does not exist. */ if (!(rt = EXTERNAL_INFO (type))) return; /* If exists previously invoked thread, then let it continue. */ if (ospf->t_distribute_update) return; /* Set timer. */ ospf->t_distribute_update = thread_add_timer_msec (master, ospf_distribute_list_update_timer, (void *) type, ospf->min_ls_interval); } /* If access-list is updated, apply some check. */ static void ospf_filter_update (const char *name) { struct ospf *ospf; int type; int abr_inv = 0; struct ospf_area *area; struct 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; } /* There is place for route-map for default-information (ZEBRA_ROUTE_MAX), * but no distribute list. */ if (type == ZEBRA_ROUTE_MAX) break; 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), name) == 0) ospf_distribute_list_update (ospf, type); } } /* Update Area access-list. */ for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { 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); } /* If prefix-list is updated, do some updates. */ void ospf_prefix_list_update (struct prefix_list *plist) { struct ospf *ospf; int type; int abr_inv = 0; struct ospf_area *area; struct listnode *node; /* If OSPF instatnce does not exist, return right now. */ ospf = ospf_lookup (); if (ospf == NULL) return; /* Update all route-maps which are used as redistribution filters. * They might use prefix-list. */ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { if (ROUTEMAP (ospf, type) != NULL) { /* If route-map is not NULL it may be using this prefix list */ ospf_distribute_list_update (ospf, type); continue; } } /* Update area filter-lists. */ for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { /* Update filter-list in. */ if (PREFIX_NAME_IN (area)) if (strcmp (PREFIX_NAME_IN (area), prefix_list_name (plist)) == 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), prefix_list_name (plist)) == 0) { PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area)); abr_inv++; } } /* Schedule ABR task. */ if (IS_OSPF_ABR (ospf) && abr_inv) ospf_schedule_abr_task (ospf); } static struct ospf_distance * ospf_distance_new (void) { return XCALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance)); } static void ospf_distance_free (struct ospf_distance *odistance) { XFREE (MTYPE_OSPF_DISTANCE, odistance); } int ospf_distance_set (struct vty *vty, struct ospf *ospf, const char *distance_str, const char *ip_str, const 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, const char *distance_str, const char *ip_str, char const *access_list_str) { int ret; struct prefix_ipv4 p; 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; } 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; } static void ospf_zebra_connected (struct zclient *zclient) { zclient_send_requests (zclient, VRF_DEFAULT); } void ospf_zebra_init (struct thread_master *master) { /* Allocate zebra structure. */ zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_OSPF); zclient->zebra_connected = ospf_zebra_connected; zclient->router_id_update = ospf_router_id_update_zebra; 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->interface_link_params = ospf_interface_link_params; 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); prefix_list_add_hook (ospf_prefix_list_update); prefix_list_delete_hook (ospf_prefix_list_update); } quagga-1.2.4/ospfd/ospf_zebra.h000066400000000000000000000055211325323223500164040ustar00rootroot00000000000000/* * 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 #include "vty.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 */ extern void ospf_zclient_start (void); extern void ospf_zebra_add (struct prefix_ipv4 *, struct ospf_route *); extern void ospf_zebra_delete (struct prefix_ipv4 *, struct ospf_route *); extern void ospf_zebra_add_discard (struct prefix_ipv4 *); extern void ospf_zebra_delete_discard (struct prefix_ipv4 *); extern int ospf_redistribute_check (struct ospf *, struct external_info *, int *); extern int ospf_distribute_check_connected (struct ospf *, struct external_info *); extern void ospf_distribute_list_update (struct ospf *, uintptr_t); extern int ospf_is_type_redistributed (int); extern void ospf_distance_reset (struct ospf *); extern u_char ospf_distance_apply (struct prefix_ipv4 *, struct ospf_route *); extern int ospf_redistribute_set (struct ospf *, int, int, int); extern int ospf_redistribute_unset (struct ospf *, int); extern int ospf_redistribute_default_set (struct ospf *, int, int, int); extern int ospf_redistribute_default_unset (struct ospf *); extern int ospf_distribute_list_out_set (struct ospf *, int, const char *); extern int ospf_distribute_list_out_unset (struct ospf *, int, const char *); extern void ospf_routemap_set (struct ospf *, int, const char *); extern void ospf_routemap_unset (struct ospf *, int); extern int ospf_distance_set (struct vty *, struct ospf *, const char *, const char *, const char *); extern int ospf_distance_unset (struct vty *, struct ospf *, const char *, const char *, const char *); extern void ospf_zebra_init (struct thread_master *); #endif /* _ZEBRA_OSPF_ZEBRA_H */ quagga-1.2.4/ospfd/ospfd.c000066400000000000000000001270651325323223500153700ustar00rootroot00000000000000/* 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 "sockopt.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; extern struct in_addr router_id_zebra; static void ospf_remove_vls_through_area (struct ospf *, struct ospf_area *); static void ospf_network_free (struct ospf *, struct ospf_network *); static void ospf_area_free (struct ospf_area *); static void ospf_network_run (struct prefix *, struct ospf_area *); static void ospf_network_run_interface (struct ospf *, struct interface *, struct prefix *, struct ospf_area *); static void ospf_network_run_subnet (struct ospf *, struct connected *, struct prefix *, struct ospf_area *); static int ospf_network_match_iface (const struct connected *, const struct prefix *); static void ospf_finish_final (struct ospf *); #define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 void ospf_router_id_update (struct ospf *ospf) { struct in_addr router_id, router_id_old; struct ospf_interface *oi; struct interface *ifp; struct listnode *node; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Router-ID[OLD:%s]: Update", inet_ntoa (ospf->router_id)); router_id_old = ospf->router_id; /* Select the router ID based on these priorities: 1. Statically assigned router ID is always the first choice. 2. If there is no statically assigned router ID, then try to stick with the most recent value, since changing router ID's is very disruptive. 3. Last choice: just go with whatever the zebra daemon recommends. */ if (ospf->router_id_static.s_addr != 0) router_id = ospf->router_id_static; else if (ospf->router_id.s_addr != 0) router_id = ospf->router_id; else router_id = router_id_zebra; ospf->router_id = router_id; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Router-ID[NEW:%s]: Update", inet_ntoa (ospf->router_id)); if (!IPV4_ADDR_SAME (&router_id_old, &router_id)) { for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { /* Some nbrs are identified by router_id, these needs * to be rebuilt. Possible optimization would be to do * oi->nbr_self->router_id = router_id for * !(virtual | ptop) links */ ospf_nbr_self_reset (oi); } /* 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, 0); ospf->external_origin = 0; } /* update router-lsa's for each area */ ospf_router_lsa_update (ospf); /* update ospf_interface's */ for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) ospf_if_update (ospf, ifp); } } /* For OSPF area sort by area id. */ static 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. */ static struct ospf * ospf_new (void) { 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_DEFAULT; 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->passive_interface_default = OSPF_IF_ACTIVE; new->new_external_route = route_table_init (); new->old_external_route = route_table_init (); new->external_lsas = route_table_init (); new->stub_router_startup_time = OSPF_STUB_ROUTER_UNCONFIGURED; new->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; new->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET; /* Distribute parameter init. */ for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { new->dmetric[i].type = -1; new->dmetric[i].value = -1; new->dtag[i] = 0; } new->default_metric = -1; new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; /* LSA timers */ new->min_ls_interval = OSPF_MIN_LS_INTERVAL; new->min_ls_arrival = OSPF_MIN_LS_ARRIVAL; /* SPF timer value init. */ new->spf_delay = OSPF_SPF_DELAY_DEFAULT; new->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; new->spf_max_holdtime = OSPF_SPF_MAX_HOLDTIME_DEFAULT; new->spf_hold_multiplier = 1; /* MaxAge init. */ new->maxage_delay = OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT; new->maxage_lsa = route_table_init(); 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 = quagga_time (NULL); if ((new->fd = ospf_sock_init()) < 0) { zlog_err("ospf_new: fatal error: ospf_sock_init was unable to open " "a socket"); exit(1); } new->maxsndbuflen = getsockopt_so_sendbuf (new->fd); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("%s: starting with OSPF send buffer size %u", __func__, new->maxsndbuflen); if ((new->ibuf = stream_new(OSPF_MAX_PACKET_SIZE+1)) == NULL) { zlog_err("ospf_new: fatal error: stream_new(%u) failed allocating ibuf", OSPF_MAX_PACKET_SIZE+1); exit(1); } 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 listgetdata ((struct listnode *)listhead (om->ospf)); } static int ospf_is_ready (struct ospf *ospf) { /* OSPF must be on and Router-ID must be configured. */ if (!ospf || ospf->router_id.s_addr == 0) return 0; return 1; } static void ospf_add (struct ospf *ospf) { listnode_add (om->ospf, ospf); } static 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); ospf_opaque_type11_lsa_init (ospf); } return ospf; } /* Handle the second half of deferred shutdown. This is called either * from the deferred-shutdown timer thread, or directly through * ospf_deferred_shutdown_check. * * Function is to cleanup G-R state, if required then call ospf_finish_final * to complete shutdown of this ospf instance. Possibly exit if the * whole process is being shutdown and this was the last OSPF instance. */ static void ospf_deferred_shutdown_finish (struct ospf *ospf) { ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; OSPF_TIMER_OFF (ospf->t_deferred_shutdown); ospf_finish_final (ospf); /* *ospf is now invalid */ /* ospfd being shut-down? If so, was this the last ospf instance? */ if (CHECK_FLAG (om->options, OSPF_MASTER_SHUTDOWN) && (listcount (om->ospf) == 0)) exit (0); return; } /* Timer thread for G-R */ static int ospf_deferred_shutdown_timer (struct thread *t) { struct ospf *ospf = THREAD_ARG(t); ospf_deferred_shutdown_finish (ospf); return 0; } /* Check whether deferred-shutdown must be scheduled, otherwise call * down directly into second-half of instance shutdown. */ static void ospf_deferred_shutdown_check (struct ospf *ospf) { unsigned long timeout; struct listnode *ln; struct ospf_area *area; /* deferred shutdown already running? */ if (ospf->t_deferred_shutdown) return; /* Should we try push out max-metric LSAs? */ if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) { for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) ospf_router_lsa_update_area (area); } timeout = ospf->stub_router_shutdown_time; } else { /* No timer needed */ ospf_deferred_shutdown_finish (ospf); return; } OSPF_TIMER_ON (ospf->t_deferred_shutdown, ospf_deferred_shutdown_timer, timeout); return; } /* Shut down the entire process */ void ospf_terminate (void) { struct ospf *ospf; struct listnode *node, *nnode; /* shutdown already in progress */ if (CHECK_FLAG (om->options, OSPF_MASTER_SHUTDOWN)) return; SET_FLAG (om->options, OSPF_MASTER_SHUTDOWN); /* exit immediately if OSPF not actually running */ if (listcount(om->ospf) == 0) exit(0); for (ALL_LIST_ELEMENTS (om->ospf, node, nnode, ospf)) ospf_finish (ospf); /* Deliberately go back up, hopefully to thread scheduler, as * One or more ospf_finish()'s may have deferred shutdown to a timer * thread */ } void ospf_finish (struct ospf *ospf) { /* let deferred shutdown decide */ ospf_deferred_shutdown_check (ospf); /* if ospf_deferred_shutdown returns, then ospf_finish_final is * deferred to expiry of G-S timer thread. Return back up, hopefully * to thread scheduler. */ return; } /* Final cleanup of ospf instance */ static void ospf_finish_final (struct ospf *ospf) { struct route_node *rn; struct ospf_nbr_nbma *nbr_nbma; struct ospf_lsa *lsa; struct ospf_interface *oi; struct ospf_area *area; struct ospf_vl_data *vl_data; struct listnode *node, *nnode; int i; ospf_opaque_type11_lsa_term (ospf); /* be nice if this worked, but it doesn't */ /*ospf_flush_self_originated_lsas_now (ospf);*/ /* Unregister redistribution */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) ospf_redistribute_unset (ospf, i); ospf_redistribute_default_unset (ospf); for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) ospf_remove_vls_through_area (ospf, area); for (ALL_LIST_ELEMENTS (ospf->vlinks, node, nnode, vl_data)) ospf_vl_delete (ospf, vl_data); list_delete (ospf->vlinks); /* Reset interface. */ for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, 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 (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { listnode_delete (ospf->areas, area); ospf_area_free (area); } /* Cancel all timers. */ OSPF_TIMER_OFF (ospf->t_external_lsa); 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_asbr_check); 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); OSPF_TIMER_OFF (ospf->t_opaque_lsa_self); close (ospf->fd); stream_free(ospf->ibuf); LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, 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 (rn = route_top (ospf->maxage_lsa); rn; rn = route_next (rn)) { struct ospf_lsa *lsa; if ((lsa = rn->info) != NULL) { ospf_lsa_unlock (&lsa); rn->info = NULL; } route_unlock_node (rn); } route_table_finish (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 */ static 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; ospf_opaque_type10_lsa_init (new); new->oiflist = list_new (); new->ranges = route_table_init (); if (area_id.s_addr == OSPF_AREA_BACKBONE) ospf->backbone = new; return new; } static 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); LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, 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); ospf_lsdb_delete_all (area->lsdb); ospf_lsdb_free (area->lsdb); 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_stub_router); OSPF_TIMER_OFF (area->t_opaque_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); if (ospf->stub_router_admin_set == OSPF_STUB_ROUTER_ADMINISTRATIVE_SET) { SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); } } return area; } struct ospf_area * ospf_area_lookup_by_area_id (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) 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. */ static 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; } static void add_ospf_interface (struct connected *co, struct ospf_area *area) { struct ospf_interface *oi; oi = ospf_if_new (area->ospf, co->ifp, co->address); oi->connected = co; oi->area = area; oi->params = ospf_lookup_if_params (co->ifp, oi->address->u.prefix4); oi->output_cost = ospf_if_get_output_cost (oi); /* Relate ospf interface to ospf instance. */ oi->ospf = area->ospf; /* update network type as interface flag */ /* If network type is specified previously, skip network type setting. */ oi->type = IF_DEF_PARAMS (co->ifp)->type; /* Add pseudo neighbor. */ ospf_nbr_self_reset (oi); ospf_area_add_if (oi->area, oi); /* if router_id is not configured, dont bring up * interfaces. * ospf_router_id_update() will call ospf_if_update * whenever r-id is configured instead. */ if ((area->ospf->router_id.s_addr != 0) && if_is_operative (co->ifp)) ospf_if_up (oi); } static void update_redistributed (struct ospf *ospf, int add_to_ospf) { struct route_node *rn; struct external_info *ei; 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 (add_to_ospf) { 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 */); } else { if (!ospf_external_info_find_lsa (ospf, &ei->p)) if (ospf_distribute_check_connected (ospf, ei)) ospf_external_lsa_originate (ospf, ei); } } } static 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; 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 ((struct prefix *)p, area); /* Update connected redistribute. */ update_redistributed(ospf, 1); 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 listnode *node, *nnode; struct ospf_interface *oi; rn = route_node_lookup (ospf->networks, (struct prefix *)p); if (rn == NULL) return 0; network = rn->info; route_unlock_node (rn); if (!IPV4_ADDR_SAME (&area_id, &network->area_id)) return 0; ospf_network_free (ospf, rn->info); rn->info = NULL; route_unlock_node (rn); /* initial reference */ /* Find interfaces that not configured already. */ for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; ospf_network_run_subnet (ospf, oi->connected, NULL, NULL); } /* Update connected redistribute. */ update_redistributed(ospf, 0); ospf_area_check_free (ospf, area_id); return 1; } /* Ensure there's an OSPF instance, as "ip ospf area" enabled OSPF means * there might not be any 'router ospf' config. * * Otherwise, doesn't do anything different to ospf_if_update for now */ void ospf_interface_area_set (struct interface *ifp) { struct ospf *ospf = ospf_get(); ospf_if_update (ospf, ifp); /* if_update does a update_redistributed */ return; } void ospf_interface_area_unset (struct interface *ifp) { struct route_node *rn_oi; struct ospf *ospf; if ((ospf = ospf_lookup ()) == NULL) return; /* Ospf not ready yet */ /* Find interfaces that may need to be removed. */ for (rn_oi = route_top (IF_OIFS (ifp)); rn_oi; rn_oi = route_next (rn_oi)) { struct ospf_interface *oi; if ( (oi = rn_oi->info) == NULL) continue; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; ospf_network_run_subnet (ospf, oi->connected, NULL, NULL); } /* Update connected redistribute. */ update_redistributed (ospf, 0); /* interfaces possibly removed */ return; } /* Check whether interface matches given network * returns: 1, true. 0, false */ static int ospf_network_match_iface(const struct connected *co, const struct prefix *net) { /* new approach: more elegant and conceptually clean */ return prefix_match(net, CONNECTED_PREFIX(co)); } static void ospf_update_interface_area (struct connected *co, struct ospf_area *area) { struct ospf_interface *oi = ospf_if_table_lookup (co->ifp, co->address); /* nothing to be done case */ if (oi && oi->area == area) return; if (oi) ospf_if_free (oi); add_ospf_interface (co, area); } /* Run OSPF for the given subnet, taking into account the following * possible sources of area configuration, in the given order of preference: * * - Whether there is interface+address specific area configuration * - Whether there is a default area for the interface * - Whether there is an area given as a parameter. * - If no specific network prefix/area is supplied, whether there's * a matching network configured. */ static void ospf_network_run_subnet (struct ospf *ospf, struct connected *co, struct prefix *p, struct ospf_area *given_area) { struct ospf_interface *oi; struct ospf_if_params *params; struct ospf_area *area = NULL; struct route_node *rn; int configed = 0; if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY)) return; if (co->address->family != AF_INET) return; /* Try determine the appropriate area for this interface + address * Start by checking interface config */ if (!(params = ospf_lookup_if_params (co->ifp, co->address->u.prefix4))) params = IF_DEF_PARAMS (co->ifp); if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) area = (ospf_area_get (ospf, params->if_area, OSPF_AREA_ID_FORMAT_ADDRESS)); /* If we've found an interface and/or addr specific area, then we're * done */ if (area) { ospf_update_interface_area (co, area); return; } /* Otherwise, only remaining possibility is a matching network statement */ if (p) { assert (given_area != NULL); /* Which either was supplied as a parameter.. (e.g. cause a new * network/area was just added).. */ if (p->family == co->address->family && ospf_network_match_iface (co, p)) ospf_update_interface_area (co, given_area); return; } /* Else we have to search the existing network/area config to see * if any match.. */ for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) if (rn->info != NULL && ospf_network_match_iface (co, &rn->p)) { struct ospf_network *network = (struct ospf_network *) rn->info; area = ospf_area_get (ospf, network->area_id, network->format); ospf_update_interface_area (co, area); configed = 1; } /* If the subnet isn't in any area, deconfigure */ if (!configed && (oi = ospf_if_table_lookup (co->ifp, co->address))) ospf_if_free (oi); } static void ospf_network_run_interface (struct ospf *ospf, struct interface *ifp, struct prefix *p, struct ospf_area *given_area) { struct listnode *cnode; struct connected *co; if (memcmp (ifp->name, "VLINK", 5) == 0) return; /* Network prefix without area is nonsensical */ if (p) assert (given_area != NULL); /* if interface prefix is match specified prefix, then create socket and join multicast group. */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co)) ospf_network_run_subnet (ospf, co, p, given_area); } static void ospf_network_run (struct prefix *p, struct ospf_area *area) { struct interface *ifp; struct listnode *node; /* Schedule Router ID Update. */ if (area->ospf->router_id.s_addr == 0) ospf_router_id_update (area->ospf); /* Get target interface. */ for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) ospf_network_run_interface (area->ospf, ifp, p, area); } void ospf_ls_upd_queue_empty (struct ospf_interface *oi) { struct route_node *rn; struct listnode *node, *nnode; struct 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 = (struct list *) rn->info)) { for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa)) ospf_lsa_unlock (&lsa); /* oi->ls_upd_queue */ 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 interface *ifp) { if (!ospf) ospf = ospf_lookup (); /* OSPF must be ready. */ if (!ospf_is_ready (ospf)) return; ospf_network_run_interface (ospf, ifp, NULL, NULL); /* Update connected redistribute. */ update_redistributed(ospf, 1); } void ospf_remove_vls_through_area (struct ospf *ospf, struct ospf_area *area) { struct listnode *node, *nnode; struct ospf_vl_data *vl_data; for (ALL_LIST_ELEMENTS (ospf->vlinks, node, nnode, vl_data)) if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) ospf_vl_delete (ospf, vl_data); } static const struct message ospf_area_type_msg[] = { { OSPF_AREA_DEFAULT, "Default" }, { OSPF_AREA_STUB, "Stub" }, { OSPF_AREA_NSSA, "NSSA" }, }; static const int ospf_area_type_msg_max = OSPF_AREA_TYPE_MAX; static void ospf_area_type_set (struct ospf_area *area, int type) { struct listnode *node; struct ospf_interface *oi; if (area->external_routing == type) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Area[%s]: Types are the same, ignored.", inet_ntoa (area->area_id)); return; } area->external_routing = type; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("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 (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) if (oi->nbr_self != NULL) { UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); } break; case OSPF_AREA_STUB: for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) if (oi->nbr_self != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("setting options on %s accordingly", IF_NAME (oi)); UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("options set on %s: %x", IF_NAME (oi), OPTIONS (oi)); } break; case OSPF_AREA_NSSA: for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) if (oi->nbr_self != NULL) { zlog_debug ("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_debug ("options set on %s: %x", IF_NAME (oi), OPTIONS (oi)); } break; default: break; } ospf_router_lsa_update_area (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_update_area (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_update_area (area); ospf_area_check_free (ospf, area->area_id); ospf_schedule_abr_task (ospf); return 1; } static int ospf_area_vlink_count (struct ospf *ospf, struct ospf_area *area) { struct ospf_vl_data *vl; struct listnode *node; int count = 0; for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl)) 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++; } /* set NSSA area defaults */ area->no_summary = 0; area->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE; area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; area->NSSATranslatorStabilityInterval = OSPF_NSSA_TRANS_STABLE_DEFAULT; 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->NSSATranslatorRole = role; return 1; } #if 0 /* XXX: unused? Leave for symmetry? */ static 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->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE; ospf_area_check_free (ospf, area_id); return 1; } #endif int ospf_area_export_list_set (struct ospf *ospf, struct ospf_area *area, const 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, const 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_refresh_set (struct ospf *ospf, int interval) { int time_left; if (ospf->lsa_refresh_interval == interval) return 1; time_left = ospf->lsa_refresh_interval - (quagga_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 - (quagga_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; } static struct ospf_nbr_nbma * ospf_nbr_nbma_new (void) { struct ospf_nbr_nbma *nbr_nbma; nbr_nbma = XCALLOC (MTYPE_OSPF_NEIGHBOR_STATIC, sizeof (struct ospf_nbr_nbma)); nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT; return nbr_nbma; } static void ospf_nbr_nbma_free (struct ospf_nbr_nbma *nbr_nbma) { XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma); } static 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); } } static 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); } static 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; } struct ospf_nbr_nbma * ospf_nbr_nbma_lookup_next (struct ospf *ospf, struct in_addr *addr, int first) { #if 0 struct ospf_nbr_nbma *nbr_nbma; struct listnode *node; #endif if (ospf == NULL) return NULL; #if 0 for (ALL_LIST_ELEMENTS_RO (ospf->nbr_nbma, node, nbr_nbma)) { if (first) { *addr = nbr_nbma->addr; return nbr_nbma; } else if (ntohl (nbr_nbma->addr.s_addr) > ntohl (addr->s_addr)) { *addr = nbr_nbma->addr; return nbr_nbma; } } #endif 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; struct 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); if (rn->info) route_unlock_node (rn); rn->info = nbr_nbma; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { 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, unsigned 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_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 = quagga_time (NULL); } quagga-1.2.4/ospfd/ospfd.conf.sample000066400000000000000000000002661325323223500173440ustar00rootroot00000000000000! -*- 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 quagga-1.2.4/ospfd/ospfd.h000066400000000000000000000465031325323223500153720ustar00rootroot00000000000000/* * 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 #include "libospf.h" #include "filter.h" #include "log.h" #define OSPF_VERSION 2 /* VTY port number. */ #define OSPF_VTY_PORT 2604 /* 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" #define OSPF_NSSA_TRANS_STABLE_DEFAULT 40 #define OSPF_ALLSPFROUTERS 0xe0000005 /* 224.0.0.5 */ #define OSPF_ALLDROUTERS 0xe0000006 /* 224.0.0.6 */ /* 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 options. */ #define OSPF_OPTION_MT 0x01 /* M/T */ #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 #define OSPF_OPTION_DN 0x80 /* 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 #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; #define OSPF_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ }; /* 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 #define OSPF_ABR_DEFAULT OSPF_ABR_CISCO /* 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) #define OSPF_LOG_ADJACENCY_CHANGES (1 << 3) #define OSPF_LOG_ADJACENCY_DETAIL (1 << 4) /* Opaque-LSA administrative flags. */ u_char opaque; #define OPAQUE_OPERATION_READY_BIT (1 << 0) /* RFC3137 stub router. Configured time to stay stub / max-metric */ unsigned int stub_router_startup_time; /* seconds */ unsigned int stub_router_shutdown_time; /* seconds */ #define OSPF_STUB_ROUTER_UNCONFIGURED 0 u_char stub_router_admin_set; #define OSPF_STUB_ROUTER_ADMINISTRATIVE_SET 1 #define OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET 0 #define OSPF_STUB_MAX_METRIC_SUMMARY_COST 0x00ff0000 /* LSA timers */ unsigned int min_ls_interval; /* minimum delay between LSAs (in msec) */ unsigned int min_ls_arrival; /* minimum interarrival time between LSAs (in msec) */ /* SPF parameters */ unsigned int spf_delay; /* SPF delay time. */ unsigned int spf_holdtime; /* SPF hold time. */ unsigned int spf_max_holdtime; /* SPF maximum-holdtime */ unsigned int spf_hold_multiplier; /* Adaptive multiplier for 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. */ struct list *vlinks; /* Configured Virtual-Links. */ struct list *areas; /* OSPF areas. */ struct route_table *nbr_nbma; struct ospf_area *backbone; /* Pointer to the Backbone Area. */ struct list *oiflist; /* ospf interfaces */ u_char passive_interface_default; /* passive-interface default */ /* LSDB of AS-external-LSAs. */ struct ospf_lsdb *lsdb; /* Flags. */ int external_origin; /* AS-external-LSA origin flag. */ int ase_calc; /* ASE calculation flag. */ struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */ /* 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 */ struct timeval ts_spf; /* SPF calculation time stamp. */ struct timeval ts_spf_duration; /* Execution time of last SPF */ struct route_table *maxage_lsa; /* List of MaxAge LSA for deletion. */ int redistribute; /* Num of redistributed protocols. */ /* Threads. */ 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. */ struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ unsigned int maxage_delay; /* Delay on Maxage remover timer, sec */ struct thread *t_maxage; /* MaxAge LSA remover timer. */ struct thread *t_maxage_walker; /* MaxAge LSA checking timer. */ struct thread *t_deferred_shutdown; /* deferred/stub-router shutdown timer*/ struct thread *t_write; struct thread *t_read; int fd; unsigned int maxsndbuflen; struct stream *ibuf; struct 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]; /* Redistribute tag info. */ route_tag_t dtag [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; struct 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. */ struct 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. */ struct 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 configured role */ #define OSPF_NSSA_ROLE_NEVER 0 #define OSPF_NSSA_ROLE_CANDIDATE 1 #define OSPF_NSSA_ROLE_ALWAYS 2 u_char NSSATranslatorState; /* NSSA operational role */ #define OSPF_NSSA_TRANSLATE_DISABLED 0 #define OSPF_NSSA_TRANSLATE_ENABLED 1 int NSSATranslatorStabilityInterval; u_char transit; /* TransitCapability. */ #define OSPF_TRANSIT_FALSE 0 #define OSPF_TRANSIT_TRUE 1 struct route_table *ranges; /* Configured Area Ranges. */ /* RFC3137 stub router state flags for area */ u_char stub_router_state; #define OSPF_AREA_ADMIN_STUB_ROUTED (1 << 0) /* admin stub-router set */ #define OSPF_AREA_IS_STUB_ROUTED (1 << 1) /* stub-router active */ #define OSPF_AREA_WAS_START_STUB_ROUTED (1 << 2) /* startup SR was done */ /* Area related LSDBs[Type1-4]. */ struct ospf_lsdb *lsdb; /* Self-originated LSAs. */ struct ospf_lsa *router_lsa_self; struct list *opaque_lsa_self; /* Type-10 Opaque-LSAs */ /* 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_stub_router; /* Stub-router timer */ struct thread *t_opaque_lsa_self; /* Type-10 Opaque-LSAs origin. */ /* Statistics field. */ u_int32_t spf_calculation; /* SPF Calculation Count. */ /* Time stamps. */ struct timeval ts_spf; /* SPF calculation time stamp. */ /* 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) #define LSA_OPTIONS_NSSA_GET(area) \ (((area)->external_routing == OSPF_AREA_NSSA) ? OSPF_OPTION_NP : 0) #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 const struct message ospf_ism_state_msg[]; extern const struct message ospf_nsm_state_msg[]; extern const struct message ospf_lsa_type_msg[]; extern const struct message ospf_link_state_id_type_msg[]; extern const struct message ospf_network_type_msg[]; extern const int ospf_ism_state_msg_max; extern const int ospf_nsm_state_msg_max; extern const int ospf_lsa_type_msg_max; extern const int ospf_link_state_id_type_msg_max; extern const int ospf_redistributed_proto_max; extern const int ospf_network_type_msg_max; extern struct zclient *zclient; extern struct thread_master *master; extern int ospf_zlog; /* Prototypes. */ extern const char *ospf_redist_string(u_int route_type); extern struct ospf *ospf_lookup (void); extern struct ospf *ospf_get (void); extern void ospf_finish (struct ospf *); extern void ospf_router_id_update (struct ospf *ospf); extern int ospf_network_set (struct ospf *, struct prefix_ipv4 *, struct in_addr); extern int ospf_network_unset (struct ospf *, struct prefix_ipv4 *, struct in_addr); extern int ospf_area_stub_set (struct ospf *, struct in_addr); extern int ospf_area_stub_unset (struct ospf *, struct in_addr); extern int ospf_area_no_summary_set (struct ospf *, struct in_addr); extern int ospf_area_no_summary_unset (struct ospf *, struct in_addr); extern int ospf_area_nssa_set (struct ospf *, struct in_addr); extern int ospf_area_nssa_unset (struct ospf *, struct in_addr); extern int ospf_area_nssa_translator_role_set (struct ospf *, struct in_addr, int); extern int ospf_area_export_list_set (struct ospf *, struct ospf_area *, const char *); extern int ospf_area_export_list_unset (struct ospf *, struct ospf_area *); extern int ospf_area_import_list_set (struct ospf *, struct ospf_area *, const char *); extern int ospf_area_import_list_unset (struct ospf *, struct ospf_area *); extern int ospf_area_shortcut_set (struct ospf *, struct ospf_area *, int); extern int ospf_area_shortcut_unset (struct ospf *, struct ospf_area *); extern int ospf_timers_refresh_set (struct ospf *, int); extern int ospf_timers_refresh_unset (struct ospf *); extern int ospf_nbr_nbma_set (struct ospf *, struct in_addr); extern int ospf_nbr_nbma_unset (struct ospf *, struct in_addr); extern int ospf_nbr_nbma_priority_set (struct ospf *, struct in_addr, u_char); extern int ospf_nbr_nbma_priority_unset (struct ospf *, struct in_addr); extern int ospf_nbr_nbma_poll_interval_set (struct ospf *, struct in_addr, unsigned int); extern int ospf_nbr_nbma_poll_interval_unset (struct ospf *, struct in_addr); extern void ospf_prefix_list_update (struct prefix_list *); extern void ospf_init (void); extern void ospf_if_update (struct ospf *, struct interface *); extern void ospf_ls_upd_queue_empty (struct ospf_interface *); extern void ospf_terminate (void); extern void ospf_nbr_nbma_if_update (struct ospf *, struct ospf_interface *); extern struct ospf_nbr_nbma *ospf_nbr_nbma_lookup (struct ospf *, struct in_addr); extern struct ospf_nbr_nbma *ospf_nbr_nbma_lookup_next (struct ospf *, struct in_addr *, int); extern int ospf_oi_count (struct interface *); extern struct ospf_area *ospf_area_get (struct ospf *, struct in_addr, int); extern void ospf_area_check_free (struct ospf *, struct in_addr); extern struct ospf_area *ospf_area_lookup_by_area_id (struct ospf *, struct in_addr); extern void ospf_area_add_if (struct ospf_area *, struct ospf_interface *); extern void ospf_area_del_if (struct ospf_area *, struct ospf_interface *); extern void ospf_interface_area_set (struct interface *); extern void ospf_interface_area_unset (struct interface *); extern void ospf_route_map_init (void); extern void ospf_snmp_init (void); extern void ospf_master_init (void); #endif /* _ZEBRA_OSPFD_H */ quagga-1.2.4/pimd/000077500000000000000000000000001325323223500137145ustar00rootroot00000000000000quagga-1.2.4/pimd/AUTHORS000066400000000000000000000003061325323223500147630ustar00rootroot00000000000000# $QuaggaId: $Format:%an, %ai, %h$ $ # Everton da Silva Marques $ more ~/.gitconfig [user] name = Everton Marques email = everton.marques@gmail.com -x- quagga-1.2.4/pimd/COPYING000066400000000000000000000431331325323223500147530ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 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. quagga-1.2.4/pimd/Makefile.am000066400000000000000000000055101325323223500157510ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. ## $QuaggaId: $Format:%an, %ai, %h$ $ # qpimd - pimd for quagga # Copyright (C) 2008 Everton da Silva Marques # # qpimd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, # or (at your option) any later version. # # qpimd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with qpimd; see the file COPYING. If not, write # to the Free Software Foundation, Inc., 59 Temple Place - Suite # 330, Boston, MA 02111-1307, USA. # PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands # PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging # PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries # PIM_UNEXPECTED_KERNEL_UPCALL: Report unexpected kernel upcall PIM_DEFS = #PIM_DEFS += -DPIM_DEBUG_BYDEFAULT PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY #PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH PIM_DEFS += -DPIM_ZCLIENT_DEBUG PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libpim.a sbin_PROGRAMS = pimd bin_PROGRAMS = test_igmpv3_join libpim_a_SOURCES = \ pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \ pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c \ pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \ pim_igmp_join.c pim_ssmpingd.c pim_int.c pim_static.c \ pim_routemap.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h \ pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_static.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) test_igmpv3_join_SOURCES = \ test_igmpv3_join.c pim_igmp_join.c pimd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = pimd.conf.sample quagga-1.2.4/pimd/Makefile.in000066400000000000000000001002171325323223500157620ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ # qpimd - pimd for quagga # Copyright (C) 2008 Everton da Silva Marques # # qpimd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, # or (at your option) any later version. # # qpimd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with qpimd; see the file COPYING. If not, write # to the Free Software Foundation, Inc., 59 Temple Place - Suite # 330, Boston, MA 02111-1307, USA. # PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands # PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging # PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries # PIM_UNEXPECTED_KERNEL_UPCALL: Report unexpected kernel upcall VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = pimd$(EXEEXT) bin_PROGRAMS = test_igmpv3_join$(EXEEXT) subdir = pimd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libpim_a_AR = $(AR) $(ARFLAGS) libpim_a_LIBADD = am_libpim_a_OBJECTS = pimd.$(OBJEXT) pim_version.$(OBJEXT) \ pim_cmd.$(OBJEXT) pim_signals.$(OBJEXT) pim_iface.$(OBJEXT) \ pim_vty.$(OBJEXT) pim_igmp.$(OBJEXT) pim_sock.$(OBJEXT) \ pim_zebra.$(OBJEXT) pim_igmpv3.$(OBJEXT) pim_str.$(OBJEXT) \ pim_mroute.$(OBJEXT) pim_util.$(OBJEXT) pim_time.$(OBJEXT) \ pim_oil.$(OBJEXT) pim_zlookup.$(OBJEXT) pim_pim.$(OBJEXT) \ pim_tlv.$(OBJEXT) pim_neighbor.$(OBJEXT) pim_hello.$(OBJEXT) \ pim_ifchannel.$(OBJEXT) pim_join.$(OBJEXT) \ pim_assert.$(OBJEXT) pim_msg.$(OBJEXT) pim_upstream.$(OBJEXT) \ pim_rpf.$(OBJEXT) pim_macro.$(OBJEXT) pim_igmp_join.$(OBJEXT) \ pim_ssmpingd.$(OBJEXT) pim_int.$(OBJEXT) pim_static.$(OBJEXT) \ pim_routemap.$(OBJEXT) libpim_a_OBJECTS = $(am_libpim_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(examplesdir)" PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) am__objects_1 = pimd.$(OBJEXT) pim_version.$(OBJEXT) pim_cmd.$(OBJEXT) \ pim_signals.$(OBJEXT) pim_iface.$(OBJEXT) pim_vty.$(OBJEXT) \ pim_igmp.$(OBJEXT) pim_sock.$(OBJEXT) pim_zebra.$(OBJEXT) \ pim_igmpv3.$(OBJEXT) pim_str.$(OBJEXT) pim_mroute.$(OBJEXT) \ pim_util.$(OBJEXT) pim_time.$(OBJEXT) pim_oil.$(OBJEXT) \ pim_zlookup.$(OBJEXT) pim_pim.$(OBJEXT) pim_tlv.$(OBJEXT) \ pim_neighbor.$(OBJEXT) pim_hello.$(OBJEXT) \ pim_ifchannel.$(OBJEXT) pim_join.$(OBJEXT) \ pim_assert.$(OBJEXT) pim_msg.$(OBJEXT) pim_upstream.$(OBJEXT) \ pim_rpf.$(OBJEXT) pim_macro.$(OBJEXT) pim_igmp_join.$(OBJEXT) \ pim_ssmpingd.$(OBJEXT) pim_int.$(OBJEXT) pim_static.$(OBJEXT) \ pim_routemap.$(OBJEXT) am_pimd_OBJECTS = pim_main.$(OBJEXT) $(am__objects_1) pimd_OBJECTS = $(am_pimd_OBJECTS) pimd_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_test_igmpv3_join_OBJECTS = test_igmpv3_join.$(OBJEXT) \ pim_igmp_join.$(OBJEXT) test_igmpv3_join_OBJECTS = $(am_test_igmpv3_join_OBJECTS) test_igmpv3_join_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libpim_a_SOURCES) $(pimd_SOURCES) \ $(test_igmpv3_join_SOURCES) DIST_SOURCES = $(libpim_a_SOURCES) $(pimd_SOURCES) \ $(test_igmpv3_join_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp AUTHORS \ COPYING README TODO DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ #PIM_DEFS += -DPIM_DEBUG_BYDEFAULT #PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH PIM_DEFS = -DPIM_CHECK_RECV_IFINDEX_SANITY -DPIM_ZCLIENT_DEBUG \ -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libpim.a libpim_a_SOURCES = \ pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \ pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c \ pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \ pim_igmp_join.c pim_ssmpingd.c pim_int.c pim_static.c \ pim_routemap.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h \ pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_static.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) test_igmpv3_join_SOURCES = \ test_igmpv3_join.c pim_igmp_join.c pimd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = pimd.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu pimd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu pimd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libpim.a: $(libpim_a_OBJECTS) $(libpim_a_DEPENDENCIES) $(EXTRA_libpim_a_DEPENDENCIES) $(AM_V_at)-rm -f libpim.a $(AM_V_AR)$(libpim_a_AR) libpim.a $(libpim_a_OBJECTS) $(libpim_a_LIBADD) $(AM_V_at)$(RANLIB) libpim.a install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list pimd$(EXEEXT): $(pimd_OBJECTS) $(pimd_DEPENDENCIES) $(EXTRA_pimd_DEPENDENCIES) @rm -f pimd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(pimd_OBJECTS) $(pimd_LDADD) $(LIBS) test_igmpv3_join$(EXEEXT): $(test_igmpv3_join_OBJECTS) $(test_igmpv3_join_DEPENDENCIES) $(EXTRA_test_igmpv3_join_DEPENDENCIES) @rm -f test_igmpv3_join$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_igmpv3_join_OBJECTS) $(test_igmpv3_join_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_assert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_cmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_hello.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_iface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_ifchannel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_igmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_igmp_join.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_igmpv3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_int.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_join.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_macro.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_mroute.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_msg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_neighbor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_oil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_pim.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_routemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_rpf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_signals.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_sock.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_ssmpingd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_static.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_str.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_tlv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_upstream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_vty.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_zlookup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pimd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_igmpv3_join.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/pimd/README000066400000000000000000000105551325323223500146020ustar00rootroot00000000000000# # $QuaggaId: $Format:%an, %ai, %h$ $ # INTRODUCTION qpimd aims to implement a PIM (Protocol Independent Multicast) daemon for the Quagga Routing Suite. Initially qpimd targets only PIM SSM (Source-Specific Multicast) mode as defined in section 4.8.2 (PIM-SSM-Only Routers) of RFC 4601. In order to deliver end-to-end multicast routing control plane, qpimd includes the router-side of IGMPv3 (RFC 3376). LICENSE qpimd - pimd for quagga Copyright (C) 2008 Everton da Silva Marques qpimd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. qpimd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with qpimd; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. HOME SITE qpimd lives at: https://github.com/udhos/qpimd PLATFORMS qpimd has been tested with Debian Lenny under Linux 2.6. REQUIREMENTS qpimd requires Quagga (0.99.11 or higher from http://www.quagga.net) The GNU Build System (Autotools) is required to build from source code repository. gawk is also needed to build with Autotools. Any other awk usually won't work. BUILDING FROM QUAGGA GIT REPOSITORY 1) Get the latest quagga source tree # git clone git://code.quagga.net/quagga.git quagga 2) Apply qpimd patch into quagga source tree # patch -p1 -d quagga < pimd-0.153-quagga-git20090623.patch 3) Compile and install quagga # cd quagga # ./bootstrap.sh # ./configure --prefix=/usr/local/quagga --enable-pimd # make # make install BUILDING FROM QUAGGA TARBALL 1) Get the latest quagga tarball # wget http://www.quagga.net/download/quagga-0.99.13.tar.gz 2) Unpack the quagga tarball # tar xzf quagga-0.99.13.tar.gz 3) Apply qpimd patch into quagga source tree # patch -p1 -d quagga-0.99.13 < pimd-0.153-quagga-0.99.13.patch 4) Compile and install quagga # cd quagga-0.99.13 # ./configure --prefix=/usr/local/quagga --enable-pimd # make # make install USAGE 1) Configure and start the zebra daemon # cp /usr/local/quagga/etc/zebra.conf.sample /usr/local/quagga/etc/zebra.conf # vi /usr/local/quagga/etc/zebra.conf # /usr/local/quagga/sbin/zebra 2) Configure and start the pimd daemon # cp /usr/local/quagga/etc/pimd.conf.sample /usr/local/quagga/etc/pimd.conf # vi /usr/local/quagga/etc/pimd.conf # /usr/local/quagga/sbin/pimd 3) Access pimd vty interface at port TCP 2611 # telnet localhost 2611 CONFIGURATION COMMANDS See available commands in the file pimd/COMMANDS. KNOWN CAVEATS See list of known caveats in the file pimd/CAVEATS. SUPPORT Please post comments, questions, patches, bug reports at the support site: https://github.com/udhos/qpimd RELATED WORK igmprt: An IGMPv3-router implementation - http://www.loria.fr/~lahmadi/igmpv3-router.html USC pimd: PIMv2-SM daemon - http://netweb.usc.edu/pim/pimd (URL broken in 2008-12-23) - http://packages.debian.org/source/sid/pimd (from Debian) troglobit pimd: This is the original USC pimd from http://netweb.usc.edu/pim/. In January 16, 2010 it was revived with the intention to collect patches floating around in Debian, Gentoo, Lintrack and other distribution repositories and to provide a central point of collaboration. - http://github.com/troglobit/pimd zpimd: zpimd is not dependent of zebra or any other routing daemon - ftp://robur.slu.se/pub/Routing/Zebra - http://sunsite2.icm.edu.pl/pub/unix/routing/zpimd mrd6: an IPv6 Multicast Router for Linux systems - http://fivebits.net/proj/mrd6/ MBGP: Implementation of RFC 2858 for Quagga - git://git.coplanar.net/~balajig/quagga - http://www.gossamer-threads.com/lists/quagga/dev/18000 REFERENCES IANA Protocol Independent Multicast (PIM) Parameters http://www.iana.org/assignments/pim-parameters/pim-parameters.txt Address Family Numbers http://www.iana.org/assignments/address-family-numbers -- END -- quagga-1.2.4/pimd/TODO000066400000000000000000000374461325323223500144220ustar00rootroot00000000000000# $QuaggaId: $Format:%an, %ai, %h$ $ T1 DONE Implement debug command test pim receive join T2 DONE Implement debug command test pim receive prune T3 DONE Per-interface Downstream (S,G) state machine (RFC 4601 4.5.3. Receiving (S,G) Join/Prune Messages) T4 DONE Upstream (S,G) state machine (RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages) T5 DONE Verify Data Packet Forwarding Rules RFC 4601 4.2. Data Packet Forwarding Rules RFC 4601 4.8.2. PIM-SSM-Only Routers Additionally, the Packet forwarding rules of Section 4.2 can be simplified in a PIM-SSM-only router: iif is the incoming interface of the packet. oiflist = NULL if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) { oiflist = inherited_olist(S,G) } else if (iif is in inherited_olist(S,G)) { send Assert(S,G) on iif } oiflist = oiflist (-) iif forward packet on all interfaces in oiflist Macro: inherited_olist(S,G) = joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) T6 DONE Implement (S,G) Assert state machine (RFC 4601, section 4.6.1). Changes in pim_ifchannel.ifassert_winner should trigger pim_upstream_update_join_desired(). Depends on TODO T27. Depends on TODO T33. See also CAVEAT C7. See also: RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages Transitions from Joined State RPF'(S,G) changes due to an Assert http://www.hep.ucl.ac.uk/~ytl/multi-cast/pim-dm_01.html: The PIM Assert mechanism is used to shutoff duplicate flows onto the same multiaccess network. Routers detect this condiction when they receive an (S,G) packet via a multi-access interface that is in the (S,G) OIL. This causes the routers to send Assert Messages. Note that neighbors will not accept Join/Prune or Assert messages from a router unless they have first heard a Hello message from that router. Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. T7 DONE Implement hello option: LAN Prune Delay T8 DONE Implement J/P_Override_Interval(I) Depends on TODO T7. See pim_ifchannel.c, pim_ifchannel_prune(), jp_override_interval. T9 DONE Detect change in IGMPv3 RPF interface/next-hop for S and update. channel_oil vif index accordingly ? Beware accidentaly adding looped MFC entries (IIF=OIF). T10 DONE React to (S,G) join directed to another upstream address. See also: RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages If a router wishes to propagate a Join(S,G) upstream, it must also watch for messages on its upstream interface from other routers on that subnet, and these may modify its behavior. If it sees a Join(S,G) to the correct upstream neighbor, it should suppress its own Join(S,G). If it sees a Prune(S,G), Prune(S,G,rpt), or Prune(*,G) to the correct upstream neighbor towards S, it should be prepared to override that prune by scheduling a Join(S,G) to be sent almost immediately. T11 DONE Review protocol modifications for SSM (RFC 4601 4.8.1. Protocol Modifications for SSM Destination Addresses) T12 DONE Review updates of RPF entries. FIXME pim_upstream.c send_join(): Currently only one upstream state is affected by detection of RPF change. RPF change should affect all upstream states sharing the RPF cache. T13 DONE Check that RFC macros using S,G,RPF_interface(S) are actually implemented with this strategy: rpf_ifch=find_ifch(up->rpf->interface). See pim_rpf.c pim_rpf_find_rpf_addr() for a correct example. $ grep -i macro pimd/*.c pimd/pim_iface.c: RFC 4601: 4.1.6. State Summarization Macros pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros pimd/pim_ifchannel.c: Macro: pimd/pim_rpf.c: RFC 4601: 4.1.6. State Summarization Macros T14 DONE Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. See pim_mroute.c mroute_msg(). T15 DONE Interface command to statically join (S,G). interface eth0 ip igmp join-group 239.1.1.1 source 1.1.1.1 T16 DONE RPF'(S,G) lookup is not working for S reachable with default route. See "RPF'(S,G) not found" in pim_rpf_update() from pim_rpf.c. Zebra daemon RIB is not reflecting changes in kernel routes accurately? T17 DONE Prevent CLI from creating bogus interfaces. Example: conf t interface xxx T18 Consider reliable pim solution (refresh reduction) A Reliable Transport Mechanism for PIM http://tools.ietf.org/wg/pim/draft-ietf-pim-port/ PORT=PIM-Over-Reliable-Transport T19 DONE Fix self as neighbor See mailing list post: http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html T20 DONE Fix debug message: "pim_neighbor_update: internal error: trying to replace same prefix list" See mailing list post: http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html T21 DONE Clean-up PIM/IGMP interface mismatch debugging See option PIM_CHECK_RECV_IFINDEX_SANITY in pimd/Makefile.am See mailing list post: http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00003.html T22 DONE IGMP must be protected against adding looped MFC entries created by both source and receiver attached to the same interface. T23 DONE libzebra crash after zclient_lookup_nexthop. See mailing list post: http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00008.html T24 DONE zserv may return recursive routes: - nexthop type is set to ZEBRA_NEXTHOP_IPV4 - ifindex is not reported - calls expecting ifindex (fib_lookup_if_vif_index) are disrupted See also this mailing list post: [PATCH 21/21] Link detect and recursive routes http://www.gossamer-threads.com/lists/quagga/dev/17564 T25 DONE Zclient nexthop lookup missing OSPF route to 1.1.1.1/32 See also: pim_zlookup.c zclient_lookup_nexthop misses OSPF 1.1.1.1/32 zebra/zebra_vty.c show_ip_route_addr_cmd hits OSPF 1.1.1.1/32 T26 DONE Zebra daemon is marking recursive static route as inactive. FIXED: zebra daemon was incorrectly marking recursive routes pointing to kernel routes as inactive: zebra/zebra_rib.c nexthop_active_ipv4: -- Original: else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) -- Fixed: else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || match->type == ZEBRA_ROUTE_KERNEL) Old problem description: This prevents rib_match_ipv4 from returning its nexthop: client: pim_zlookup.c zclient_read_nexthop server: zebra/zserv.c zsend_ipv4_nexthop_lookup_v2 -> rib_match_ipv4 Kernel route is injected into zebra in zebra_rib.c rib_add_ipv4 Examples: rt_netlink.c:726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0); rt_netlink.c:864: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0); This patch didn't fix the issue: [PATCH 21/21] Link detect and recursive routes http://www.gossamer-threads.com/lists/quagga/dev/17564 See the example below for the route 2.2.2.2. bash# route add -host 1.1.1.1 gw 127.0.0.1 bash# route add -host 2.2.2.2 gw 1.1.1.1 bash# netstat -nvr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 2.2.2.2 1.1.1.1 255.255.255.255 UGH 0 0 0 lo 1.1.1.1 127.0.0.1 255.255.255.255 UGH 0 0 0 lo 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 0.0.0.0 192.168.0.2 0.0.0.0 UG 0 0 0 eth0 bash# zebra# sh ip route Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - ISIS, B - BGP, > - selected route, * - FIB route K>* 0.0.0.0/0 via 192.168.0.2, eth0 K>* 1.1.1.1/32 via 127.0.0.1, lo K * 2.2.2.2/32 via 1.1.1.1, lo inactive C>* 127.0.0.0/8 is directly connected, lo C>* 192.168.0.0/24 is directly connected, eth0 quagga-pimd-router# sh ip route 1.1.1.1 Address NextHop Interface Metric Preference 1.1.1.1 127.0.0.1 lo 0 0 quagga-pimd-router# quagga-pimd-router# sh ip route 2.2.2.2 Address NextHop Interface Metric Preference 2.2.2.2 192.168.0.2 eth0 0 0 quagga-pimd-router# T27 DONE Implement debug command test pim receive assert See also TODO T6: (S,G) Assert state machine. T28 DONE Bad IPv4 address family=02 in Join/Prune dump Reported by Andrew Lunn # 58-byte pim v2 Join/Prune dump # ------------------------------ # IPv4 address family=02 is wrong, correct IPv4 address family is 01 # See http://www.iana.org/assignments/address-family-numbers # c8XX YY03 : ip src 200.xx.yy.3 e000 000d : ip dst 224.0.0.13 9404 0000 : ip router alert option 148.4.0.0 2300 ab13 : pimv2,type=3 res=00 checksum=ab13 0200 : upstream family=02, encoding=00 c8XX YY08 : upstream 200.xx.yy.8 0001 00d2 : res=00 groups=01 holdtime=00d2 0200 0020 : group family=02, encoding=00, res=00, mask_len=20 ef01 0101 : group address 239.1.1.1 0001 0000 : joined=0001 pruned=0000 0200 0020 : source family=02, encoding=00, res=00, mask_len=20 0101 0101 : source address 1.1.1.1 T29 DONE Reset interface PIM-hello-sent counter when primary address changes See pim_ifp->pim_ifstat_hello_sent RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. T30 DONE Run interface DR election when primary address changes Reported by Andrew Lunn See pim_if_dr_election(). T31 If an interface changes one of its secondary IP addresses, a Hello message with an updated Address_List option and a non-zero HoldTime should be sent immediately. See also detect_secondary_address_change See also CAVEAT C15. See also RFC 4601: 4.3.1. Sending Hello Messages T32 FIXED Detection of interface primary address changes may fail when there are multiple addresses. See also CAVEAT C14. pim_find_primary_addr() should return interface primary address from connected list. Currently it returns the first address. Zebra daemon "show int" is able to keep the primary address as first address. T33 DONE Implement debug command: test pim receive upcall See also TODO T6: (S,G) Assert state machine. T34 DONE assert_action_a1 T35 DONE Review macros depending on interface I. See also: grep ,I\) pimd/*.c For the case (S,G,I) check if I is either 1) interface attached to this per-interface S,G state (don't think so) or 2) an arbitrary interface (most probably) For the arbitrary interface case (2), consider representing interface ifp as its primary address (struct in_addr ifaddr). The benefit is in_addr does not need to be dereferenced, so it does not demand protection against crashes. T36 DONE React to zebra daemon link-detect up/down notification. pim_ifp->primary_address is managed by detect_primary_address_change() depending on to ifp->connected (managed by zebra_interface_address_read()). T37 DONE Review list of variables which may affect pim_upstream.c pim_upstream_evaluate_join_desired(). Call pim_upstream_update_join_desired() accordingly. See the order of invokation: pim_if_dr_election(ifp); pim_if_update_join_desired(pim_ifp); /* depends on DR */ pim_if_update_could_assert(ifp); /* depends on DR */ pim_if_update_my_assert_metric(ifp); /* depends on could_assert */ join_desired depends on: pim_ifp->primary_address pim_ifp->pim_dr_addr ch->ifassert_winner_metric ch->ifassert_winner ch->local_ifmembership ch->ifjoin_state ch->upstream->rpf.source_nexthop.mrib_metric_preference ch->upstream->rpf.source_nexthop.mrib_route_metric ch->upstream->rpf.source_nexthop.interface T38 DONE Detect change in AssertTrackingDesired(S,G,I) See the order of invokation: dr_election: none update_join_desired: depends on DR update_tracking_desired: depends on DR, join_desired AssertTrackingDesired(S,G,I) depends on: pim_ifp->primary_address pim_ifp->pim_dr_addr ch->local_ifmembership ch->ifassert_winner ch->ifjoin_state ch->upstream->rpf.source_nexthop.interface PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags) T39 DONE AssertTrackingDesired: flags is not matching evaluation # show ip pim assert-internal CA: CouldAssert ECA: Evaluate CouldAssert ATD: AssertTrackingDesired eATD: Evaluate AssertTrackingDesired Interface Address Source Group CA eCA ATD eATD eth0 192.168.1.100 1.1.1.1 239.1.1.1 no no no yes # T40 Lightweight MLDv2 http://tools.ietf.org/html/draft-ietf-mboned-lightweight-igmpv3-mldv2-05 http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt http://www.ietf.org/html.charters/mboned-charter.html T41 DONE ssmping support See also: http://www.venaas.no/multicast/ssmping/ draft-ietf-mboned-ssmping-07 http://tools.ietf.org/html/draft-ietf-mboned-ssmping-07 Example: debug ssmpingd conf t ip ssmpingd 1.1.1.1 show ip ssmpingd T42 Static igmp join fails when loading config at boot time ! Wrong behavior seen at boot time: ! 2010/02/22 08:59:00 PIM: igmp_source_forward_start: ignoring request for looped MFC entry (S,G)=(3.3.3.3,239.3.3.3): igmp_sock=12 oif=eth0 vif_index=2 ! Correct behavior seen later: ! 2010/02/22 09:03:16 PIM: igmp_source_forward_start: ignoring request for looped MFC entry (S,G)=(2.2.2.2,239.2.2.2): igmp_sock=17 oif=lo vif_index=1 ! To see the wrong message at boot: ! debug igmp trace ! interface lo ip igmp ip igmp join 239.2.2.2 2.2.2.2 ip igmp join 239.3.3.3 3.3.3.3 ! ! Interfaces indexes: Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut eth0 200.202.112.3 2 2 0 0 0 0 lo 127.0.0.1 1 1 0 0 0 0 T43 PIM Neighbor Reduction https://datatracker.ietf.org/doc/draft-wijnands-pim-neighbor-reduction/ "In a transit LAN (no directly connected source or receiver), many of the PIM procedures don't apply. (...) This proposal describes a procedure to reduce the amount of neighbors established over a transit LAN." T44 Single Stream Multicast Fast Reroute (SMFR) Method https://datatracker.ietf.org/doc/draft-liu-pim-single-stream-multicast-frr/ "This document proposes an IP multicast fast convergence method based on differentiating primary and backup PIM join." T45 RFC5384 - The Join Attribute Format "This document describes a modification of the Join message that allows a node to associate attributes with a particular tree." T46 PIM Multi-Topology ID (MT-ID) Join-Attribute http://tools.ietf.org/html/draft-cai-pim-mtid-00 Depends on T45. "This draft introduces a new type of PIM Join Attribute used to encode the identity of the topology PIM uses for RPF." -x- quagga-1.2.4/pimd/pim_assert.c000066400000000000000000000555361325323223500162440ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "pimd.h" #include "pim_str.h" #include "pim_tlv.h" #include "pim_msg.h" #include "pim_pim.h" #include "pim_int.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_hello.h" #include "pim_macro.h" #include "pim_assert.h" #include "pim_ifchannel.h" static int assert_action_a3(struct pim_ifchannel *ch); static void assert_action_a2(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric); static void assert_action_a6(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric); void pim_ifassert_winner_set(struct pim_ifchannel *ch, enum pim_ifassert_state new_state, struct in_addr winner, struct pim_assert_metric winner_metric) { int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr); int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric, &winner_metric); if (PIM_DEBUG_PIM_EVENTS) { if (ch->ifassert_state != new_state) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, pim_ifchannel_ifassert_name(ch->ifassert_state), pim_ifchannel_ifassert_name(new_state), ch->interface->name); } if (winner_changed) { char src_str[100]; char grp_str[100]; char was_str[100]; char winner_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", ch->ifassert_winner, was_str, sizeof(was_str)); pim_inet4_dump("", winner, winner_str, sizeof(winner_str)); zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, was_str, winner_str, ch->interface->name); } } /* PIM_DEBUG_PIM_EVENTS */ ch->ifassert_state = new_state; ch->ifassert_winner = winner; ch->ifassert_winner_metric = winner_metric; ch->ifassert_creation = pim_time_monotonic_sec(); if (winner_changed || metric_changed) { pim_upstream_update_join_desired(ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } } static void on_trace(const char *label, struct interface *ifp, struct in_addr src) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src, src_str, sizeof(src_str)); zlog_debug("%s: from %s on %s", label, src_str, ifp->name); } } static int preferred_assert(const struct pim_ifchannel *ch, const struct pim_assert_metric *recv_metric) { return pim_assert_metric_better(recv_metric, &ch->ifassert_winner_metric); } static int acceptable_assert(const struct pim_assert_metric *my_metric, const struct pim_assert_metric *recv_metric) { return pim_assert_metric_better(recv_metric, my_metric); } static int inferior_assert(const struct pim_assert_metric *my_metric, const struct pim_assert_metric *recv_metric) { return pim_assert_metric_better(my_metric, recv_metric); } static int cancel_assert(const struct pim_assert_metric *recv_metric) { return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) && (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX); } static void if_could_assert_do_a1(const char *caller, struct pim_ifchannel *ch) { if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { if (assert_action_a1(ch)) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s", __PRETTY_FUNCTION__, caller, src_str, grp_str, ch->interface->name); /* log warning only */ } } } static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr, struct pim_assert_metric recv_metric) { struct pim_ifchannel *ch; ch = pim_ifchannel_add(ifp, source_addr, group_addr); if (!ch) { char source_str[100]; char group_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ifp->name); return -1; } switch (ch->ifassert_state) { case PIM_IFASSERT_NOINFO: if (recv_metric.rpt_bit_flag) { /* RPT bit set */ if_could_assert_do_a1(__PRETTY_FUNCTION__, ch); } else { /* RPT bit clear */ if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { if_could_assert_do_a1(__PRETTY_FUNCTION__, ch); } else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) { if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)) { assert_action_a6(ch, recv_metric); } } } break; case PIM_IFASSERT_I_AM_WINNER: if (preferred_assert(ch, &recv_metric)) { assert_action_a2(ch, recv_metric); } else { if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ assert_action_a3(ch); } } break; case PIM_IFASSERT_I_AM_LOSER: if (recv_metric.ip_address.s_addr == ch->ifassert_winner.s_addr) { /* Assert from current winner */ if (cancel_assert(&recv_metric)) { assert_action_a5(ch); } else { if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { assert_action_a5(ch); } else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) { if (!recv_metric.rpt_bit_flag) { assert_action_a2(ch, recv_metric); } } } } else if (preferred_assert(ch, &recv_metric)) { assert_action_a2(ch, recv_metric); } break; default: { char source_str[100]; char group_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ch->ifassert_state, ifp->name); } return -2; } return 0; } int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *buf, int buf_size) { struct prefix msg_group_addr; struct prefix msg_source_addr; struct pim_assert_metric msg_metric; int offset; uint8_t *curr; int curr_size; on_trace(__PRETTY_FUNCTION__, ifp, src_addr); curr = buf; curr_size = buf_size; /* Parse assert group addr */ offset = pim_parse_addr_group(ifp->name, src_addr, &msg_group_addr, curr, curr_size); if (offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s", __PRETTY_FUNCTION__, src_str, ifp->name); return -1; } curr += offset; curr_size -= offset; /* Parse assert source addr */ offset = pim_parse_addr_ucast(ifp->name, src_addr, &msg_source_addr, curr, curr_size); if (offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", __PRETTY_FUNCTION__, src_str, ifp->name); return -2; } curr += offset; curr_size -= offset; if (curr_size != 8) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s", __PRETTY_FUNCTION__, curr_size, src_str, ifp->name); return -3; } /* Parse assert metric preference */ msg_metric.metric_preference = pim_read_uint32_host(curr); msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */ msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */ curr += 4; /* Parse assert route metric */ msg_metric.route_metric = pim_read_uint32_host(curr); if (PIM_DEBUG_PIM_TRACE) { char neigh_str[100]; char source_str[100]; char group_str[100]; pim_inet4_dump("", src_addr, neigh_str, sizeof(neigh_str)); pim_inet4_dump("", msg_source_addr.u.prefix4, source_str, sizeof(source_str)); pim_inet4_dump("", msg_group_addr.u.prefix4, group_str, sizeof(group_str)); zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u", __PRETTY_FUNCTION__, neigh_str, ifp->name, source_str, group_str, msg_metric.metric_preference, msg_metric.route_metric, PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag)); } msg_metric.ip_address = src_addr; return dispatch_assert(ifp, msg_source_addr.u.prefix4, msg_group_addr.u.prefix4, msg_metric); } /* RFC 4601: 4.6.3. Assert Metrics Assert metrics are defined as: When comparing assert_metrics, the rpt_bit_flag, metric_preference, and route_metric field are compared in order, where the first lower value wins. If all fields are equal, the primary IP address of the router that sourced the Assert message is used as a tie-breaker, with the highest IP address winning. */ int pim_assert_metric_better(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2) { if (m1->rpt_bit_flag < m2->rpt_bit_flag) return 1; if (m1->rpt_bit_flag > m2->rpt_bit_flag) return 0; if (m1->metric_preference < m2->metric_preference) return 1; if (m1->metric_preference > m2->metric_preference) return 0; if (m1->route_metric < m2->route_metric) return 1; if (m1->route_metric > m2->route_metric) return 0; return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr); } int pim_assert_metric_match(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2) { if (m1->rpt_bit_flag != m2->rpt_bit_flag) return 0; if (m1->metric_preference != m2->metric_preference) return 0; if (m1->route_metric != m2->route_metric) return 0; return m1->ip_address.s_addr == m2->ip_address.s_addr; } int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr, uint32_t metric_preference, uint32_t route_metric, uint32_t rpt_bit_flag) { uint8_t *buf_pastend = pim_msg + buf_size; uint8_t *pim_msg_curr; int pim_msg_size; int remain; pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */ /* Encode group */ remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, remain, group_addr); if (!pim_msg_curr) { char group_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: failure encoding group address %s: space left=%d", __PRETTY_FUNCTION__, group_str, remain); return -1; } /* Encode source */ remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, remain, source_addr); if (!pim_msg_curr) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure encoding source address %s: space left=%d", __PRETTY_FUNCTION__, source_str, remain); return -2; } /* Metric preference */ pim_write_uint32(pim_msg_curr, rpt_bit_flag ? metric_preference | 0x80000000 : metric_preference); pim_msg_curr += 4; /* Route metric */ pim_write_uint32(pim_msg_curr, route_metric); pim_msg_curr += 4; /* Add PIM header */ pim_msg_size = pim_msg_curr - pim_msg; pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_ASSERT); return pim_msg_size; } static int pim_assert_do(struct pim_ifchannel *ch, struct pim_assert_metric metric) { struct interface *ifp; struct pim_interface *pim_ifp; uint8_t pim_msg[1000]; int pim_msg_size; ifp = ch->interface; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: pim not enabled on interface: %s", __PRETTY_FUNCTION__, ifp->name); return -1; } pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp, ch->group_addr, ch->source_addr, metric.metric_preference, metric.route_metric, metric.rpt_bit_flag); if (pim_msg_size < 1) { zlog_warn("%s: failure building PIM assert message: msg_size=%d", __PRETTY_FUNCTION__, pim_msg_size); return -2; } /* RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ pim_hello_require(ifp); if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u", __PRETTY_FUNCTION__, ifp->name, source_str, group_str, metric.metric_preference, metric.route_metric, PIM_FORCE_BOOLEAN(metric.rpt_bit_flag)); } if (pim_msg_send(pim_ifp->pim_sock_fd, qpim_all_pim_routers_addr, pim_msg, pim_msg_size, ifp->name)) { zlog_warn("%s: could not send PIM message on interface %s", __PRETTY_FUNCTION__, ifp->name); return -3; } return 0; } int pim_assert_send(struct pim_ifchannel *ch) { return pim_assert_do(ch, ch->ifassert_my_metric); } /* RFC 4601: 4.6.4. AssertCancel Messages An AssertCancel(S,G) is an infinite metric assert with the RPT bit set that names S as the source. */ static int pim_assert_cancel(struct pim_ifchannel *ch) { struct pim_assert_metric metric; metric.rpt_bit_flag = 0; metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX; metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; metric.ip_address = ch->source_addr; return pim_assert_do(ch, metric); } static int on_assert_timer(struct thread *t) { struct pim_ifchannel *ch; struct interface *ifp; zassert(t); ch = THREAD_ARG(t); zassert(ch); ifp = ch->interface; zassert(ifp); if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); } ch->t_ifassert_timer = 0; switch (ch->ifassert_state) { case PIM_IFASSERT_I_AM_WINNER: zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ assert_action_a3(ch); break; case PIM_IFASSERT_I_AM_LOSER: assert_action_a5(ch); break; default: { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ch->ifassert_state, ifp->name); } } return 0; } static void assert_timer_off(struct pim_ifchannel *ch) { struct interface *ifp; zassert(ch); ifp = ch->interface; zassert(ifp); if (PIM_DEBUG_PIM_TRACE) { if (ch->t_ifassert_timer) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); } } THREAD_OFF(ch->t_ifassert_timer); zassert(!ch->t_ifassert_timer); } static void pim_assert_timer_set(struct pim_ifchannel *ch, int interval) { struct interface *ifp; zassert(ch); ifp = ch->interface; zassert(ifp); assert_timer_off(ch); if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, interval, ifp->name); } THREAD_TIMER_ON(master, ch->t_ifassert_timer, on_assert_timer, ch, interval); } static void pim_assert_timer_reset(struct pim_ifchannel *ch) { pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A1: Send Assert(S,G). Set Assert Timer to (Assert_Time - Assert_Override_Interval). Store self as AssertWinner(S,G,I). Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I). */ int assert_action_a1(struct pim_ifchannel *ch) { struct interface *ifp = ch->interface; struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -1; /* must return since pim_ifp is used below */ } /* Switch to I_AM_WINNER before performing action_a3 below */ pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER, pim_ifp->primary_address, pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address)); zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ if (assert_action_a3(ch)) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); /* warning only */ } zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); return 0; } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A2: Store new assert winner as AssertWinner(S,G,I) and assert winner metric as AssertWinnerMetric(S,G,I). Set Assert Timer to Assert_Time. */ static void assert_action_a2(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric) { pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER, winner_metric.ip_address, winner_metric); pim_assert_timer_set(ch, PIM_ASSERT_TIME); zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A3: Send Assert(S,G). Set Assert Timer to (Assert_Time - Assert_Override_Interval). */ static int assert_action_a3(struct pim_ifchannel *ch) { zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); pim_assert_timer_reset(ch); if (pim_assert_send(ch)) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name); return -1; } zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); return 0; } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A4: Send AssertCancel(S,G). Delete assert info (AssertWinner(S,G,I) and AssertWinnerMetric(S,G,I) will then return their default values). */ void assert_action_a4(struct pim_ifchannel *ch) { if (pim_assert_cancel(ch)) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name); /* log warning only */ } assert_action_a5(ch); zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A5: Delete assert info (AssertWinner(S,G,I) and AssertWinnerMetric(S,G,I) will then return their default values). */ void assert_action_a5(struct pim_ifchannel *ch) { reset_ifassert_state(ch); zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A6: Store new assert winner as AssertWinner(S,G,I) and assert winner metric as AssertWinnerMetric(S,G,I). Set Assert Timer to Assert_Time. If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set SPTbit(S,G) to TRUE. */ static void assert_action_a6(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric) { assert_action_a2(ch, winner_metric); /* If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set SPTbit(S,G) to TRUE. Notice: For PIM SSM, SPTbit(S,G) is already always true. */ zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER); } quagga-1.2.4/pimd/pim_assert.h000066400000000000000000000045471325323223500162450ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_ASSERT_H #define PIM_ASSERT_H #include #include "if.h" #include "pim_neighbor.h" #include "pim_ifchannel.h" /* RFC 4601: 4.11. Timer Values Note that for historical reasons, the Assert message lacks a Holdtime field. Thus, changing the Assert Time from the default value is not recommended. */ #define PIM_ASSERT_OVERRIDE_INTERVAL (3) /* seconds */ #define PIM_ASSERT_TIME (180) /* seconds */ #define PIM_ASSERT_METRIC_PREFERENCE_MAX (0xFFFFFFFF) #define PIM_ASSERT_ROUTE_METRIC_MAX (0xFFFFFFFF) void pim_ifassert_winner_set(struct pim_ifchannel *ch, enum pim_ifassert_state new_state, struct in_addr winner, struct pim_assert_metric winner_metric); int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *buf, int buf_size); int pim_assert_metric_better(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); int pim_assert_metric_match(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr, uint32_t metric_preference, uint32_t route_metric, uint32_t rpt_bit_flag); int pim_assert_send(struct pim_ifchannel *ch); int assert_action_a1(struct pim_ifchannel *ch); void assert_action_a4(struct pim_ifchannel *ch); void assert_action_a5(struct pim_ifchannel *ch); #endif /* PIM_ASSERT_H */ quagga-1.2.4/pimd/pim_cmd.c000066400000000000000000004050631325323223500155000ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include "command.h" #include "if.h" #include "prefix.h" #include "zclient.h" #include "pimd.h" #include "pim_cmd.h" #include "pim_iface.h" #include "pim_vty.h" #include "pim_mroute.h" #include "pim_str.h" #include "pim_igmp.h" #include "pim_igmpv3.h" #include "pim_sock.h" #include "pim_time.h" #include "pim_util.h" #include "pim_oil.h" #include "pim_neighbor.h" #include "pim_pim.h" #include "pim_ifchannel.h" #include "pim_hello.h" #include "pim_msg.h" #include "pim_upstream.h" #include "pim_rpf.h" #include "pim_macro.h" #include "pim_ssmpingd.h" #include "pim_zebra.h" #include "pim_static.h" static struct cmd_node pim_global_node = { PIM_NODE, "", 1 /* vtysh ? yes */ }; static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */ }; static void pim_if_membership_clear(struct interface *ifp) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(pim_ifp); if (PIM_IF_TEST_PIM(pim_ifp->options) && PIM_IF_TEST_IGMP(pim_ifp->options)) { return; } pim_ifchannel_membership_clear(ifp); } /* When PIM is disabled on interface, IGMPv3 local membership information is not injected into PIM interface state. The function pim_if_membership_refresh() fetches all IGMPv3 local membership information into PIM. It is intented to be called whenever PIM is enabled on the interface in order to collect missed local membership information. */ static void pim_if_membership_refresh(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *sock_node; struct igmp_sock *igmp; pim_ifp = ifp->info; zassert(pim_ifp); if (!PIM_IF_TEST_PIM(pim_ifp->options)) return; if (!PIM_IF_TEST_IGMP(pim_ifp->options)) return; /* First clear off membership from all PIM (S,G) entries on the interface */ pim_ifchannel_membership_clear(ifp); /* Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on the interface */ /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { struct listnode *grpnode; struct igmp_group *grp; /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { struct listnode *srcnode; struct igmp_source *src; /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { if (IGMP_SOURCE_TEST_FORWARDING(src->source_flags)) { pim_ifchannel_local_membership_add(ifp, src->source_addr, grp->group_addr); } } /* scan group sources */ } /* scan igmp groups */ } /* scan igmp sockets */ /* Finally delete every PIM (S,G) entry lacking all state info */ pim_ifchannel_delete_on_noinfo(ifp); } static void pim_show_assert(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Source Group State Winner Uptime Timer%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; char winner_str[100]; char uptime[10]; char timer[10]; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", ch->ifassert_winner, winner_str, sizeof(winner_str)); pim_time_uptime(uptime, sizeof(uptime), now - ch->ifassert_creation); pim_time_timer_to_mmss(timer, sizeof(timer), ch->t_ifassert_timer); vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, pim_ifchannel_ifassert_name(ch->ifassert_state), winner_str, uptime, timer, VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_assert_internal(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "CA: CouldAssert%s" "ECA: Evaluate CouldAssert%s" "ATD: AssertTrackingDesired%s" "eATD: Evaluate AssertTrackingDesired%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address Source Group CA eCA ATD eATD%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no", pim_macro_ch_could_assert_eval(ch) ? "yes" : "no", PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) ? "yes" : "no", pim_macro_assert_tracking_desired_eval(ch) ? "yes" : "no", VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_assert_metric(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Source Group RPT Pref Metric Address %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; char addr_str[100]; struct pim_assert_metric am; am = pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", am.ip_address, addr_str, sizeof(addr_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, am.rpt_bit_flag ? "yes" : "no", am.metric_preference, am.route_metric, addr_str, VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_assert_winner_metric(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Source Group RPT Pref Metric Address %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; char addr_str[100]; struct pim_assert_metric *am; char pref_str[5]; char metr_str[7]; am = &ch->ifassert_winner_metric; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", am->ip_address, addr_str, sizeof(addr_str)); if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) snprintf(pref_str, sizeof(pref_str), "INFI"); else snprintf(pref_str, sizeof(pref_str), "%4u", am->metric_preference); if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX) snprintf(metr_str, sizeof(metr_str), "INFI"); else snprintf(metr_str, sizeof(metr_str), "%6u", am->route_metric); vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str, metr_str, addr_str, VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_membership(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Source Group Membership%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %-10s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO ? "NOINFO" : "INCLUDE", VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void igmp_show_interfaces(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address ifIndex Socket Uptime Multi Broad MLoop AllMu Prmsc Del%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct listnode *sock_node; struct igmp_sock *igmp; pim_ifp = ifp->info; if (!pim_ifp) continue; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char uptime[10]; int mloop; pim_time_uptime(uptime, sizeof(uptime), now - igmp->sock_creation); mloop = pim_socket_mcastloop_get(igmp->fd); vty_out(vty, "%-9s %-15s %7d %6d %8s %5s %5s %5s %5s %5s %3s%s", ifp->name, inet_ntoa(igmp->ifaddr), ifp->ifindex, igmp->fd, uptime, if_is_multicast(ifp) ? "yes" : "no", if_is_broadcast(ifp) ? "yes" : "no", (mloop < 0) ? "?" : (mloop ? "yes" : "no"), (ifp->flags & IFF_ALLMULTI) ? "yes" : "no", (ifp->flags & IFF_PROMISC) ? "yes" : "no", PIM_IF_IS_DELETED(ifp) ? "yes" : "no", VTY_NEWLINE); } } } static void igmp_show_interface_join(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Source Group Socket Uptime %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct listnode *join_node; struct igmp_join *ij; struct in_addr pri_addr; char pri_addr_str[100]; pim_ifp = ifp->info; if (!pim_ifp) continue; if (!pim_ifp->igmp_join_list) continue; pri_addr = pim_find_primary_addr(ifp); pim_inet4_dump("", pri_addr, pri_addr_str, sizeof(pri_addr_str)); for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, join_node, ij)) { char group_str[100]; char source_str[100]; char uptime[10]; pim_time_uptime(uptime, sizeof(uptime), now - ij->sock_creation); pim_inet4_dump("", ij->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", ij->source_addr, source_str, sizeof(source_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %6d %8s%s", ifp->name, pri_addr_str, source_str, group_str, ij->sock_fd, uptime, VTY_NEWLINE); } /* for (pim_ifp->igmp_join_list) */ } /* for (iflist) */ } static void show_interface_address(struct vty *vty) { struct listnode *ifpnode; struct interface *ifp; vty_out(vty, "Interface Primary Secondary %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifpnode, ifp)) { struct listnode *ifcnode; struct connected *ifc; struct in_addr pri_addr; char pri_addr_str[100]; pri_addr = pim_find_primary_addr(ifp); pim_inet4_dump("", pri_addr, pri_addr_str, sizeof(pri_addr_str)); for (ALL_LIST_ELEMENTS_RO(ifp->connected, ifcnode, ifc)) { char sec_addr_str[100]; struct prefix *p = ifc->address; if (p->family != AF_INET) continue; if (p->u.prefix4.s_addr == pri_addr.s_addr) { sec_addr_str[0] = '\0'; } else { pim_inet4_dump("", p->u.prefix4, sec_addr_str, sizeof(sec_addr_str)); } vty_out(vty, "%-9s %-15s %-15s%s", ifp->name, pri_addr_str, sec_addr_str, VTY_NEWLINE); } } } static void pim_show_dr(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "NonPri: Number of neighbors missing DR Priority hello option%s" "DrPri: Designated Router Priority sent%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address DR Uptime Elections Changes NonPri DrPri%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; char dr_str[100]; char dr_uptime[10]; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), now, pim_ifp->pim_dr_election_last); pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_str, sizeof(dr_str)); vty_out(vty, "%-9s %-15s %-15s %8s %9d %7d %6d %10d%s", ifp->name, inet_ntoa(ifaddr), dr_str, dr_uptime, pim_ifp->pim_dr_election_count, pim_ifp->pim_dr_election_changes, pim_ifp->pim_dr_num_nondrpri_neighbors, pim_ifp->pim_dr_priority, VTY_NEWLINE); } } static void pim_show_hello(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Period Timer StatStart Recv Rfail Send Sfail%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; char hello_period[10]; char hello_timer[10]; char stat_uptime[10]; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; pim_time_timer_to_mmss(hello_timer, sizeof(hello_timer), pim_ifp->t_pim_hello_timer); pim_time_mmss(hello_period, sizeof(hello_period), pim_ifp->pim_hello_period); pim_time_uptime(stat_uptime, sizeof(stat_uptime), now - pim_ifp->pim_ifstat_start); vty_out(vty, "%-9s %-15s %6s %5s %9s %4u %5u %4u %5u%s", ifp->name, inet_ntoa(ifaddr), hello_period, hello_timer, stat_uptime, pim_ifp->pim_ifstat_hello_recv, pim_ifp->pim_ifstat_hello_recvfail, pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_hello_sendfail, VTY_NEWLINE); } } static void pim_show_interfaces(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address ifIndex Socket Uptime Multi Broad MLoop AllMu Prmsc Del%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; char uptime[10]; int mloop; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; pim_time_uptime(uptime, sizeof(uptime), now - pim_ifp->pim_sock_creation); mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd); vty_out(vty, "%-9s %-15s %7d %6d %8s %5s %5s %5s %5s %5s %3s%s", ifp->name, inet_ntoa(ifaddr), ifp->ifindex, pim_ifp->pim_sock_fd, uptime, if_is_multicast(ifp) ? "yes" : "no", if_is_broadcast(ifp) ? "yes" : "no", (mloop < 0) ? "?" : (mloop ? "yes" : "no"), (ifp->flags & IFF_ALLMULTI) ? "yes" : "no", (ifp->flags & IFF_PROMISC) ? "yes" : "no", PIM_IF_IS_DELETED(ifp) ? "yes" : "no", VTY_NEWLINE); } } static void pim_show_join(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Source Group State Uptime Expire Prune%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; char uptime[10]; char expire[10]; char prune[10]; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation); pim_time_timer_to_mmss(expire, sizeof(expire), ch->t_ifjoin_expiry_timer); pim_time_timer_to_mmss(prune, sizeof(prune), ch->t_ifjoin_prune_pending_timer); vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, pim_ifchannel_ifjoin_name(ch->ifjoin_state), uptime, expire, prune, VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_neighbors(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Recv flags: H=holdtime L=lan_prune_delay P=dr_priority G=generation_id A=address_list%s" " T=can_disable_join_suppression%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address Neighbor Uptime Timer Holdt DrPri GenId Recv %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *neighnode; struct pim_neighbor *neigh; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { char uptime[10]; char holdtime[10]; char expire[10]; char neigh_src_str[100]; char recv[7]; pim_inet4_dump("", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str)); pim_time_uptime(uptime, sizeof(uptime), now - neigh->creation); pim_time_mmss(holdtime, sizeof(holdtime), neigh->holdtime); pim_time_timer_to_mmss(expire, sizeof(expire), neigh->t_expire_timer); recv[0] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_HOLDTIME) ? 'H' : ' '; recv[1] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY) ? 'L' : ' '; recv[2] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY) ? 'P' : ' '; recv[3] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ? 'G' : ' '; recv[4] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_ADDRESS_LIST) ? 'A' : ' '; recv[5] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION) ? 'T' : ' '; recv[6] = '\0'; vty_out(vty, "%-9s %-15s %-15s %8s %5s %5s %5u %08x %6s%s", ifp->name, inet_ntoa(ifaddr), neigh_src_str, uptime, expire, holdtime, neigh->dr_priority, neigh->generation_id, recv, VTY_NEWLINE); } } } static void pim_show_lan_prune_delay(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "PrDly=propagation_delay (msec) OvInt=override_interval (msec)%s" "HiDly=highest_propagation_delay (msec) HiInt=highest_override_interval (msec)%s" "NoDly=number_of_non_lan_delay_neighbors%s" "T=t_bit LPD=lan_prune_delay_hello_option%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address PrDly OvInt NoDly HiDly HiInt T | Neighbor LPD PrDly OvInt T%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *neighnode; struct pim_neighbor *neigh; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { char neigh_src_str[100]; pim_inet4_dump("", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str)); vty_out(vty, "%-9s %-15s %5u %5u %5u %5u %5u %1u | %-15s %-3s %5u %5u %1u%s", ifp->name, inet_ntoa(ifaddr), pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, pim_ifp->pim_number_of_nonlandelay_neighbors, pim_ifp->pim_neighbors_highest_propagation_delay_msec, pim_ifp->pim_neighbors_highest_override_interval_msec, PIM_FORCE_BOOLEAN(PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)), neigh_src_str, PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY) ? "yes" : "no", neigh->propagation_delay_msec, neigh->override_interval_msec, PIM_FORCE_BOOLEAN(PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION)), VTY_NEWLINE); } } } static void pim_show_jp_override_interval(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "EffPDelay=effective_propagation_delay (msec)%s" "EffOvrInt=override_interval (msec)%s" "JPOvrInt=jp_override_interval (msec)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address LAN_Delay EffPDelay EffOvrInt JPOvrInt%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; vty_out(vty, "%-9s %-15s %-9s %9u %9u %8u%s", ifp->name, inet_ntoa(ifaddr), pim_if_lan_delay_enabled(ifp) ? "enabled" : "disabled", pim_if_effective_propagation_delay_msec(ifp), pim_if_effective_override_interval_msec(ifp), pim_if_jp_override_interval_msec(ifp), VTY_NEWLINE); } } static void pim_show_neighbors_secondary(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "Interface Address Neighbor Secondary %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *neighnode; struct pim_neighbor *neigh; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { char neigh_src_str[100]; struct listnode *prefix_node; struct prefix *p; if (!neigh->prefix_list) continue; pim_inet4_dump("", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str)); for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) { char neigh_sec_str[100]; if (p->family != AF_INET) continue; pim_inet4_dump("", p->u.prefix4, neigh_sec_str, sizeof(neigh_sec_str)); vty_out(vty, "%-9s %-15s %-15s %-15s%s", ifp->name, inet_ntoa(ifaddr), neigh_src_str, neigh_sec_str, VTY_NEWLINE); } } } } static void pim_show_upstream(struct vty *vty) { struct listnode *upnode; struct pim_upstream *up; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Source Group State Uptime JoinTimer RefCnt%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, upnode, up)) { char src_str[100]; char grp_str[100]; char uptime[10]; char join_timer[10]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition); pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), up->t_join_timer); vty_out(vty, "%-15s %-15s %-5s %-8s %-9s %6d%s", src_str, grp_str, up->join_state == PIM_UPSTREAM_JOINED ? "Jnd" : "NtJnd", uptime, join_timer, up->ref_count, VTY_NEWLINE); } } static void pim_show_join_desired(struct vty *vty) { struct listnode *ifnode; struct listnode *chnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; char src_str[100]; char grp_str[100]; vty_out(vty, "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD%s", VTY_NEWLINE); /* scan all interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, chnode, ch)) { struct pim_upstream *up = ch->upstream; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); vty_out(vty, "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s%s", ifp->name, src_str, grp_str, pim_macro_ch_lost_assert(ch) ? "yes" : "no", pim_macro_chisin_joins(ch) ? "yes" : "no", pim_macro_chisin_pim_include(ch) ? "yes" : "no", PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags) ? "yes" : "no", pim_upstream_evaluate_join_desired(up) ? "yes" : "no", VTY_NEWLINE); } } } static void pim_show_upstream_rpf(struct vty *vty) { struct listnode *upnode; struct pim_upstream *up; vty_out(vty, "Source Group RpfIface RibNextHop RpfAddress %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, upnode, up)) { char src_str[100]; char grp_str[100]; char rpf_nexthop_str[100]; char rpf_addr_str[100]; struct pim_rpf *rpf; const char *rpf_ifname; rpf = &up->rpf; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, rpf_nexthop_str, sizeof(rpf_nexthop_str)); pim_inet4_dump("", rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""; vty_out(vty, "%-15s %-15s %-8s %-15s %-15s%s", src_str, grp_str, rpf_ifname, rpf_nexthop_str, rpf_addr_str, VTY_NEWLINE); } } static void show_rpf_refresh_stats(struct vty *vty, time_t now) { char refresh_uptime[10]; pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now, qpim_rpf_cache_refresh_last); vty_out(vty, "RPF Cache Refresh Delay: %ld msecs%s" "RPF Cache Refresh Timer: %ld msecs%s" "RPF Cache Refresh Requests: %lld%s" "RPF Cache Refresh Events: %lld%s" "RPF Cache Refresh Last: %s%s", qpim_rpf_cache_refresh_delay_msec, VTY_NEWLINE, pim_time_timer_remain_msec(qpim_rpf_cache_refresher), VTY_NEWLINE, (long long)qpim_rpf_cache_refresh_requests, VTY_NEWLINE, (long long)qpim_rpf_cache_refresh_events, VTY_NEWLINE, refresh_uptime, VTY_NEWLINE); } static void show_scan_oil_stats(struct vty *vty, time_t now) { char uptime_scan_oil[10]; char uptime_mroute_add[10]; char uptime_mroute_del[10]; pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now, qpim_scan_oil_last); pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now, qpim_mroute_add_last); pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now, qpim_mroute_del_last); vty_out(vty, "Scan OIL - Last: %s Events: %lld%s" "MFC Add - Last: %s Events: %lld%s" "MFC Del - Last: %s Events: %lld%s", uptime_scan_oil, (long long) qpim_scan_oil_events, VTY_NEWLINE, uptime_mroute_add, (long long) qpim_mroute_add_events, VTY_NEWLINE, uptime_mroute_del, (long long) qpim_mroute_del_events, VTY_NEWLINE); } static void pim_show_rpf(struct vty *vty) { struct listnode *up_node; struct pim_upstream *up; time_t now = pim_time_monotonic_sec(); show_rpf_refresh_stats(vty, now); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Source Group RpfIface RpfAddress RibNextHop Metric Pref%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) { char src_str[100]; char grp_str[100]; char rpf_addr_str[100]; char rib_nexthop_str[100]; const char *rpf_ifname; struct pim_rpf *rpf = &up->rpf; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, rib_nexthop_str, sizeof(rib_nexthop_str)); rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""; vty_out(vty, "%-15s %-15s %-8s %-15s %-15s %6d %4d%s", src_str, grp_str, rpf_ifname, rpf_addr_str, rib_nexthop_str, rpf->source_nexthop.mrib_route_metric, rpf->source_nexthop.mrib_metric_preference, VTY_NEWLINE); } } static void igmp_show_querier(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "Interface Address Querier StartCount Query-Timer Other-Timer%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char query_hhmmss[10]; char other_hhmmss[10]; pim_time_timer_to_hhmmss(query_hhmmss, sizeof(query_hhmmss), igmp->t_igmp_query_timer); pim_time_timer_to_hhmmss(other_hhmmss, sizeof(other_hhmmss), igmp->t_other_querier_timer); vty_out(vty, "%-9s %-15s %-7s %10d %11s %11s%s", ifp->name, inet_ntoa(igmp->ifaddr), igmp->t_igmp_query_timer ? "THIS" : "OTHER", igmp->startup_query_count, query_hhmmss, other_hhmmss, VTY_NEWLINE); } } } static void igmp_show_groups(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Group Mode Timer Srcs V Uptime %s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; struct listnode *grpnode; struct igmp_group *grp; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { char group_str[100]; char hhmmss[10]; char uptime[10]; pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss), grp->t_group_timer); pim_time_uptime(uptime, sizeof(uptime), now - grp->group_creation); vty_out(vty, "%-9s %-15s %-15s %4s %8s %4d %d %8s%s", ifp->name, ifaddr_str, group_str, grp->group_filtermode_isexcl ? "EXCL" : "INCL", hhmmss, grp->group_source_list ? listcount(grp->group_source_list) : 0, igmp_group_compat_mode(igmp, grp), uptime, VTY_NEWLINE); } /* scan igmp groups */ } /* scan igmp sockets */ } /* scan interfaces */ } static void igmp_show_group_retransmission(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Group RetTimer Counter RetSrcs%s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; struct listnode *grpnode; struct igmp_group *grp; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { char group_str[100]; char grp_retr_mmss[10]; struct listnode *src_node; struct igmp_source *src; int grp_retr_sources = 0; pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); pim_time_timer_to_mmss(grp_retr_mmss, sizeof(grp_retr_mmss), grp->t_group_query_retransmit_timer); /* count group sources with retransmission state */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, src_node, src)) { if (src->source_query_retransmit_count > 0) { ++grp_retr_sources; } } vty_out(vty, "%-9s %-15s %-15s %-8s %7d %7d%s", ifp->name, ifaddr_str, group_str, grp_retr_mmss, grp->group_specific_query_retransmit_count, grp_retr_sources, VTY_NEWLINE); } /* scan igmp groups */ } /* scan igmp sockets */ } /* scan interfaces */ } static void igmp_show_parameters(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "QRV: Robustness Variable SQI: Startup Query Interval%s" "QQI: Query Interval OQPI: Other Querier Present Interval%s" "QRI: Query Response Interval LMQT: Last Member Query Time%s" "GMI: Group Membership Interval OHPI: Older Host Present Interval%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address QRV QQI QRI GMI SQI OQPI LMQT OHPI %s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; long gmi_dsec; /* Group Membership Interval */ long oqpi_dsec; /* Other Querier Present Interval */ int sqi; long lmqt_dsec; long ohpi_dsec; long qri_dsec; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); gmi_dsec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec) / 100; sqi = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval); oqpi_dsec = PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec) / 100; lmqt_dsec = PIM_IGMP_LMQT_MSEC(pim_ifp->igmp_query_max_response_time_dsec, igmp->querier_robustness_variable) / 100; ohpi_dsec = PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); qri_dsec = pim_ifp->igmp_query_max_response_time_dsec; vty_out(vty, "%-9s %-15s %3d %3d %3ld.%ld %3ld.%ld %3d %3ld.%ld %3ld.%ld %3ld.%ld%s", ifp->name, ifaddr_str, igmp->querier_robustness_variable, igmp->querier_query_interval, qri_dsec / 10, qri_dsec % 10, gmi_dsec / 10, gmi_dsec % 10, sqi, oqpi_dsec / 10, oqpi_dsec % 10, lmqt_dsec / 10, lmqt_dsec % 10, ohpi_dsec / 10, ohpi_dsec % 10, VTY_NEWLINE); } /* scan igmp sockets */ } /* scan interfaces */ } static void igmp_show_sources(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Group Source Timer Fwd Uptime %s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; struct listnode *grpnode; struct igmp_group *grp; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { char group_str[100]; struct listnode *srcnode; struct igmp_source *src; pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { char source_str[100]; char mmss[10]; char uptime[10]; pim_inet4_dump("", src->source_addr, source_str, sizeof(source_str)); pim_time_timer_to_mmss(mmss, sizeof(mmss), src->t_source_timer); pim_time_uptime(uptime, sizeof(uptime), now - src->source_creation); vty_out(vty, "%-9s %-15s %-15s %-15s %5s %3s %8s%s", ifp->name, ifaddr_str, group_str, source_str, mmss, IGMP_SOURCE_TEST_FORWARDING(src->source_flags) ? "Y" : "N", uptime, VTY_NEWLINE); } /* scan group sources */ } /* scan igmp groups */ } /* scan igmp sockets */ } /* scan interfaces */ } static void igmp_show_source_retransmission(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Group Source Counter%s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; struct listnode *grpnode; struct igmp_group *grp; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { char group_str[100]; struct listnode *srcnode; struct igmp_source *src; pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { char source_str[100]; pim_inet4_dump("", src->source_addr, source_str, sizeof(source_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %7d%s", ifp->name, ifaddr_str, group_str, source_str, src->source_query_retransmit_count, VTY_NEWLINE); } /* scan group sources */ } /* scan igmp groups */ } /* scan igmp sockets */ } /* scan interfaces */ } static void clear_igmp_interfaces() { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_if_addr_del_all_igmp(ifp); } for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_if_addr_add_all(ifp); } } static void clear_pim_interfaces() { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { if (ifp->info) { pim_neighbor_delete_all(ifp, "interface cleared"); } } } static void clear_interfaces() { clear_igmp_interfaces(); clear_pim_interfaces(); } DEFUN (pim_interface, pim_interface_cmd, "interface IFNAME", "Select an interface to configure\n" "Interface's name\n") { struct interface *ifp; const char *ifname = argv[0]; size_t sl; sl = strlen(ifname); if (sl > INTERFACE_NAMSIZ) { vty_out(vty, "%% Interface name %s is invalid: length exceeds " "%d characters%s", ifname, INTERFACE_NAMSIZ, VTY_NEWLINE); return CMD_WARNING; } ifp = if_lookup_by_name_len(ifname, sl); if (!ifp) { vty_out(vty, "%% Interface %s does not exist%s", ifname, VTY_NEWLINE); /* Returning here would prevent pimd from booting when there are interface commands in pimd.conf, since all interfaces are unknown at pimd boot time (the zebra daemon has not been contacted for interface discovery). */ ifp = if_get_by_name_len(ifname, sl); if (!ifp) { vty_out(vty, "%% Could not create interface %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } } vty->index = ifp; vty->node = INTERFACE_NODE; return CMD_SUCCESS; } DEFUN (clear_ip_interfaces, clear_ip_interfaces_cmd, "clear ip interfaces", CLEAR_STR IP_STR "Reset interfaces\n") { clear_interfaces(); return CMD_SUCCESS; } DEFUN (clear_ip_igmp_interfaces, clear_ip_igmp_interfaces_cmd, "clear ip igmp interfaces", CLEAR_STR IP_STR CLEAR_IP_IGMP_STR "Reset IGMP interfaces\n") { clear_igmp_interfaces(); return CMD_SUCCESS; } static void mroute_add_all() { struct listnode *node; struct channel_oil *c_oil; for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { if (pim_mroute_add(&c_oil->oil)) { /* just log warning */ char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); } } } static void mroute_del_all() { struct listnode *node; struct channel_oil *c_oil; for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { if (pim_mroute_del(&c_oil->oil)) { /* just log warning */ char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); } } } static void static_mroute_add_all() { struct listnode *node; struct static_route *s_route; for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { if (pim_mroute_add(&s_route->mc)) { /* just log warning */ char source_str[100]; char group_str[100]; pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); } } } static void static_mroute_del_all() { struct listnode *node; struct static_route *s_route; for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { if (pim_mroute_del(&s_route->mc)) { /* just log warning */ char source_str[100]; char group_str[100]; pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); } } } DEFUN (clear_ip_mroute, clear_ip_mroute_cmd, "clear ip mroute", CLEAR_STR IP_STR "Reset multicast routes\n") { mroute_del_all(); mroute_add_all(); return CMD_SUCCESS; } DEFUN (clear_ip_pim_interfaces, clear_ip_pim_interfaces_cmd, "clear ip pim interfaces", CLEAR_STR IP_STR CLEAR_IP_PIM_STR "Reset PIM interfaces\n") { clear_pim_interfaces(); return CMD_SUCCESS; } DEFUN (clear_ip_pim_oil, clear_ip_pim_oil_cmd, "clear ip pim oil", CLEAR_STR IP_STR CLEAR_IP_PIM_STR "Rescan PIM OIL (output interface list)\n") { pim_scan_oil(); return CMD_SUCCESS; } DEFUN (show_ip_igmp_interface, show_ip_igmp_interface_cmd, "show ip igmp interface", SHOW_STR IP_STR IGMP_STR "IGMP interface information\n") { igmp_show_interfaces(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_join, show_ip_igmp_join_cmd, "show ip igmp join", SHOW_STR IP_STR IGMP_STR "IGMP static join information\n") { igmp_show_interface_join(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_groups, show_ip_igmp_groups_cmd, "show ip igmp groups", SHOW_STR IP_STR IGMP_STR IGMP_GROUP_STR) { igmp_show_groups(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_groups_retransmissions, show_ip_igmp_groups_retransmissions_cmd, "show ip igmp groups retransmissions", SHOW_STR IP_STR IGMP_STR IGMP_GROUP_STR "IGMP group retransmissions\n") { igmp_show_group_retransmission(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_parameters, show_ip_igmp_parameters_cmd, "show ip igmp parameters", SHOW_STR IP_STR IGMP_STR "IGMP parameters information\n") { igmp_show_parameters(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_sources, show_ip_igmp_sources_cmd, "show ip igmp sources", SHOW_STR IP_STR IGMP_STR IGMP_SOURCE_STR) { igmp_show_sources(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_sources_retransmissions, show_ip_igmp_sources_retransmissions_cmd, "show ip igmp sources retransmissions", SHOW_STR IP_STR IGMP_STR IGMP_SOURCE_STR "IGMP source retransmissions\n") { igmp_show_source_retransmission(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_querier, show_ip_igmp_querier_cmd, "show ip igmp querier", SHOW_STR IP_STR IGMP_STR "IGMP querier information\n") { igmp_show_querier(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_address, show_ip_pim_address_cmd, "show ip pim address", SHOW_STR IP_STR PIM_STR "PIM interface address\n") { show_interface_address(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert, show_ip_pim_assert_cmd, "show ip pim assert", SHOW_STR IP_STR PIM_STR "PIM interface assert\n") { pim_show_assert(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_internal, show_ip_pim_assert_internal_cmd, "show ip pim assert-internal", SHOW_STR IP_STR PIM_STR "PIM interface internal assert state\n") { pim_show_assert_internal(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_metric, show_ip_pim_assert_metric_cmd, "show ip pim assert-metric", SHOW_STR IP_STR PIM_STR "PIM interface assert metric\n") { pim_show_assert_metric(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_winner_metric, show_ip_pim_assert_winner_metric_cmd, "show ip pim assert-winner-metric", SHOW_STR IP_STR PIM_STR "PIM interface assert winner metric\n") { pim_show_assert_winner_metric(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_dr, show_ip_pim_dr_cmd, "show ip pim designated-router", SHOW_STR IP_STR PIM_STR "PIM interface designated router\n") { pim_show_dr(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_hello, show_ip_pim_hello_cmd, "show ip pim hello", SHOW_STR IP_STR PIM_STR "PIM interface hello information\n") { pim_show_hello(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_interface, show_ip_pim_interface_cmd, "show ip pim interface", SHOW_STR IP_STR PIM_STR "PIM interface information\n") { pim_show_interfaces(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_join, show_ip_pim_join_cmd, "show ip pim join", SHOW_STR IP_STR PIM_STR "PIM interface join information\n") { pim_show_join(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_lan_prune_delay, show_ip_pim_lan_prune_delay_cmd, "show ip pim lan-prune-delay", SHOW_STR IP_STR PIM_STR "PIM neighbors LAN prune delay parameters\n") { pim_show_lan_prune_delay(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_local_membership, show_ip_pim_local_membership_cmd, "show ip pim local-membership", SHOW_STR IP_STR PIM_STR "PIM interface local-membership\n") { pim_show_membership(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_jp_override_interval, show_ip_pim_jp_override_interval_cmd, "show ip pim jp-override-interval", SHOW_STR IP_STR PIM_STR "PIM interface J/P override interval\n") { pim_show_jp_override_interval(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_neighbor, show_ip_pim_neighbor_cmd, "show ip pim neighbor", SHOW_STR IP_STR PIM_STR "PIM neighbor information\n") { pim_show_neighbors(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_secondary, show_ip_pim_secondary_cmd, "show ip pim secondary", SHOW_STR IP_STR PIM_STR "PIM neighbor addresses\n") { pim_show_neighbors_secondary(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream, show_ip_pim_upstream_cmd, "show ip pim upstream", SHOW_STR IP_STR PIM_STR "PIM upstream information\n") { pim_show_upstream(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream_join_desired, show_ip_pim_upstream_join_desired_cmd, "show ip pim upstream-join-desired", SHOW_STR IP_STR PIM_STR "PIM upstream join-desired\n") { pim_show_join_desired(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream_rpf, show_ip_pim_upstream_rpf_cmd, "show ip pim upstream-rpf", SHOW_STR IP_STR PIM_STR "PIM upstream source rpf\n") { pim_show_upstream_rpf(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_rpf, show_ip_pim_rpf_cmd, "show ip pim rpf", SHOW_STR IP_STR PIM_STR "PIM cached source rpf information\n") { pim_show_rpf(vty); return CMD_SUCCESS; } static void show_multicast_interfaces(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct sioc_vif_req vreq; pim_ifp = ifp->info; if (!pim_ifp) continue; memset(&vreq, 0, sizeof(vreq)); vreq.vifi = pim_ifp->mroute_vif_index; if (ioctl(qpim_mroute_socket_fd, SIOCGETVIFCNT, &vreq)) { zlog_warn("ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s%s", (unsigned long)SIOCGETVIFCNT, ifp->name, pim_ifp->mroute_vif_index, errno, safe_strerror(errno), VTY_NEWLINE); } ifaddr = pim_ifp->primary_address; vty_out(vty, "%-9s %-15s %3d %3d %7lu %7lu %10lu %10lu%s", ifp->name, inet_ntoa(ifaddr), ifp->ifindex, pim_ifp->mroute_vif_index, vreq.icount, vreq.ocount, vreq.ibytes, vreq.obytes, VTY_NEWLINE); } } DEFUN (show_ip_multicast, show_ip_multicast_cmd, "show ip multicast", SHOW_STR IP_STR "Multicast global information\n") { time_t now = pim_time_monotonic_sec(); if (PIM_MROUTE_IS_ENABLED) { char uptime[10]; vty_out(vty, "Mroute socket descriptor: %d%s", qpim_mroute_socket_fd, VTY_NEWLINE); pim_time_uptime(uptime, sizeof(uptime), now - qpim_mroute_socket_creation); vty_out(vty, "Mroute socket uptime: %s%s", uptime, VTY_NEWLINE); } else { vty_out(vty, "Multicast disabled%s", VTY_NEWLINE); } vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Zclient update socket: "); if (qpim_zclient_update) { vty_out(vty, "%d failures=%d%s", qpim_zclient_update->sock, qpim_zclient_update->fail, VTY_NEWLINE); } else { vty_out(vty, "%s", VTY_NEWLINE); } vty_out(vty, "Zclient lookup socket: "); if (qpim_zclient_lookup) { vty_out(vty, "%d failures=%d%s", qpim_zclient_lookup->sock, qpim_zclient_lookup->fail, VTY_NEWLINE); } else { vty_out(vty, "%s", VTY_NEWLINE); } vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Current highest VifIndex: %d%s", qpim_mroute_oif_highest_vif_index, VTY_NEWLINE); vty_out(vty, "Maximum highest VifIndex: %d%s", MAXVIFS - 1, VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Upstream Join Timer: %d secs%s", qpim_t_periodic, VTY_NEWLINE); vty_out(vty, "Join/Prune Holdtime: %d secs%s", PIM_JP_HOLDTIME, VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE); show_rpf_refresh_stats(vty, now); vty_out(vty, "%s", VTY_NEWLINE); show_scan_oil_stats(vty, now); show_multicast_interfaces(vty); return CMD_SUCCESS; } static void show_mroute(struct vty *vty) { struct listnode *node; struct channel_oil *c_oil; struct static_route *s_route; time_t now; vty_out(vty, "Proto: I=IGMP P=PIM S=STATIC%s%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Source Group Proto Input iVifI Output oVifI TTL Uptime %s", VTY_NEWLINE); now = pim_time_monotonic_sec(); /* print list of PIM and IGMP routes */ for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { char group_str[100]; char source_str[100]; int oif_vif_index; pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) { struct interface *ifp_in; struct interface *ifp_out; char oif_uptime[10]; int ttl; char proto[5]; ttl = c_oil->oil.mfcc_ttls[oif_vif_index]; if (ttl < 1) continue; ifp_in = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); ifp_out = pim_if_find_by_vif_index(oif_vif_index); pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - c_oil->oif_creation[oif_vif_index]); proto[0] = '\0'; if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_PIM) { strcat(proto, "P"); } if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_IGMP) { strcat(proto, "I"); } vty_out(vty, "%-15s %-15s %-5s %-5s %5d %-6s %5d %3d %8s %s", source_str, group_str, proto, ifp_in ? ifp_in->name : "", c_oil->oil.mfcc_parent, ifp_out ? ifp_out->name : "", oif_vif_index, ttl, oif_uptime, VTY_NEWLINE); } } /* Print list of static routes */ for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { char group_str[100]; char source_str[100]; int oif_vif_index; pim_inet4_dump("", s_route->group, group_str, sizeof(group_str)); pim_inet4_dump("", s_route->source, source_str, sizeof(source_str)); for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) { struct interface *ifp_in; struct interface *ifp_out; char oif_uptime[10]; int ttl; char proto[5]; ttl = s_route->oif_ttls[oif_vif_index]; if (ttl < 1) continue; ifp_in = pim_if_find_by_vif_index(s_route->iif); ifp_out = pim_if_find_by_vif_index(oif_vif_index); pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - s_route->creation[oif_vif_index]); proto[0] = '\0'; strcat(proto, "S"); vty_out(vty, "%-15s %-15s %-5s %-5s %5d %-6s %5d %3d %8s %s", source_str, group_str, proto, ifp_in ? ifp_in->name : "", s_route->iif, ifp_out ? ifp_out->name : "", oif_vif_index, ttl, oif_uptime, VTY_NEWLINE); } } } DEFUN (show_ip_mroute, show_ip_mroute_cmd, "show ip mroute", SHOW_STR IP_STR MROUTE_STR) { show_mroute(vty); return CMD_SUCCESS; } static void show_mroute_count(struct vty *vty) { struct listnode *node; struct channel_oil *c_oil; struct static_route *s_route; vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Source Group Packets Bytes WrongIf %s", VTY_NEWLINE); /* Print PIM and IGMP route counts */ for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { char group_str[100]; char source_str[100]; struct sioc_sg_req sgreq; memset(&sgreq, 0, sizeof(sgreq)); sgreq.src = c_oil->oil.mfcc_origin; sgreq.grp = c_oil->oil.mfcc_mcastgrp; pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { int e = errno; vty_out(vty, "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s%s", (unsigned long)SIOCGETSGCNT, source_str, group_str, e, safe_strerror(e), VTY_NEWLINE); continue; } vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s", source_str, group_str, sgreq.pktcnt, sgreq.bytecnt, sgreq.wrong_if, VTY_NEWLINE); } /* Print static route counts */ for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { char group_str[100]; char source_str[100]; struct sioc_sg_req sgreq; memset(&sgreq, 0, sizeof(sgreq)); sgreq.src = s_route->mc.mfcc_origin; sgreq.grp = s_route->mc.mfcc_mcastgrp; pim_inet4_dump("", s_route->mc.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", s_route->mc.mfcc_origin, source_str, sizeof(source_str)); if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { int e = errno; vty_out(vty, "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s%s", /* note that typeof ioctl defs can vary across platforms, from * int, to unsigned int, to long unsigned int */ (unsigned long)SIOCGETSGCNT, source_str, group_str, e, safe_strerror(e), VTY_NEWLINE); continue; } vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s", source_str, group_str, sgreq.pktcnt, sgreq.bytecnt, sgreq.wrong_if, VTY_NEWLINE); } } DEFUN (show_ip_mroute_count, show_ip_mroute_count_cmd, "show ip mroute count", SHOW_STR IP_STR MROUTE_STR "Route and packet count data\n") { show_mroute_count(vty); return CMD_SUCCESS; } DEFUN (show_ip_rib, show_ip_rib_cmd, "show ip rib A.B.C.D", SHOW_STR IP_STR RIB_STR "Unicast address\n") { struct in_addr addr; const char *addr_str; struct pim_nexthop nexthop; char nexthop_addr_str[100]; int result; addr_str = argv[0]; result = inet_pton(AF_INET, addr_str, &addr); if (result <= 0) { vty_out(vty, "Bad unicast address %s: errno=%d: %s%s", addr_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } if (pim_nexthop_lookup(&nexthop, addr)) { vty_out(vty, "Failure querying RIB nexthop for unicast address %s%s", addr_str, VTY_NEWLINE); return CMD_WARNING; } vty_out(vty, "Address NextHop Interface Metric Preference%s", VTY_NEWLINE); pim_inet4_dump("", nexthop.mrib_nexthop_addr, nexthop_addr_str, sizeof(nexthop_addr_str)); vty_out(vty, "%-15s %-15s %-9s %6d %10d%s", addr_str, nexthop_addr_str, nexthop.interface ? nexthop.interface->name : "", nexthop.mrib_route_metric, nexthop.mrib_metric_preference, VTY_NEWLINE); return CMD_SUCCESS; } static void show_ssmpingd(struct vty *vty) { struct listnode *node; struct ssmpingd_sock *ss; time_t now; vty_out(vty, "Source Socket Address Port Uptime Requests%s", VTY_NEWLINE); if (!qpim_ssmpingd_list) return; now = pim_time_monotonic_sec(); for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { char source_str[100]; char ss_uptime[10]; struct sockaddr_in bind_addr; socklen_t len = sizeof(bind_addr); char bind_addr_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); if (pim_socket_getsockname(ss->sock_fd, (struct sockaddr *) &bind_addr, &len)) { vty_out(vty, "%% Failure reading socket name for ssmpingd source %s on fd=%d%s", source_str, ss->sock_fd, VTY_NEWLINE); } pim_inet4_dump("", bind_addr.sin_addr, bind_addr_str, sizeof(bind_addr_str)); pim_time_uptime(ss_uptime, sizeof(ss_uptime), now - ss->creation); vty_out(vty, "%-15s %6d %-15s %5d %8s %8lld%s", source_str, ss->sock_fd, bind_addr_str, ntohs(bind_addr.sin_port), ss_uptime, (long long)ss->requests, VTY_NEWLINE); } } DEFUN (show_ip_ssmpingd, show_ip_ssmpingd_cmd, "show ip ssmpingd", SHOW_STR IP_STR SHOW_SSMPINGD_STR) { show_ssmpingd(vty); return CMD_SUCCESS; } DEFUN (ip_multicast_routing, ip_multicast_routing_cmd, PIM_CMD_IP_MULTICAST_ROUTING, IP_STR "Enable IP multicast forwarding\n") { pim_mroute_socket_enable(); pim_if_add_vif_all(); mroute_add_all(); static_mroute_add_all(); return CMD_SUCCESS; } DEFUN (no_ip_multicast_routing, no_ip_multicast_routing_cmd, PIM_CMD_NO " " PIM_CMD_IP_MULTICAST_ROUTING, NO_STR IP_STR "Global IP configuration subcommands\n" "Enable IP multicast forwarding\n") { mroute_del_all(); static_mroute_del_all(); pim_if_del_vif_all(); pim_mroute_socket_disable(); return CMD_SUCCESS; } DEFUN (ip_ssmpingd, ip_ssmpingd_cmd, "ip ssmpingd [A.B.C.D]", IP_STR CONF_SSMPINGD_STR "Source address\n") { int result; struct in_addr source_addr; const char *source_str = (argc > 0) ? argv[0] : "0.0.0.0"; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "%% Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } result = pim_ssmpingd_start(source_addr); if (result) { vty_out(vty, "%% Failure starting ssmpingd for source %s: %d%s", source_str, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (no_ip_ssmpingd, no_ip_ssmpingd_cmd, "no ip ssmpingd [A.B.C.D]", NO_STR IP_STR CONF_SSMPINGD_STR "Source address\n") { int result; struct in_addr source_addr; const char *source_str = (argc > 0) ? argv[0] : "0.0.0.0"; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "%% Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } result = pim_ssmpingd_stop(source_addr); if (result) { vty_out(vty, "%% Failure stopping ssmpingd for source %s: %d%s", source_str, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (interface_ip_igmp, interface_ip_igmp_cmd, "ip igmp", IP_STR IFACE_IGMP_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { pim_ifp = pim_if_new(ifp, 1 /* igmp=true */, 0 /* pim=false */); if (!pim_ifp) { vty_out(vty, "Could not enable IGMP on interface %s%s", ifp->name, VTY_NEWLINE); return CMD_WARNING; } } else { PIM_IF_DO_IGMP(pim_ifp->options); } pim_if_addr_add_all(ifp); pim_if_membership_refresh(ifp); return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp, interface_no_ip_igmp_cmd, "no ip igmp", NO_STR IP_STR IFACE_IGMP_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; PIM_IF_DONT_IGMP(pim_ifp->options); pim_if_membership_clear(ifp); pim_if_addr_del_all_igmp(ifp); if (!PIM_IF_TEST_PIM(pim_ifp->options)) { pim_if_delete(ifp); } return CMD_SUCCESS; } DEFUN (interface_ip_igmp_join, interface_ip_igmp_join_cmd, "ip igmp join A.B.C.D A.B.C.D", IP_STR IFACE_IGMP_STR "IGMP join multicast group\n" "Multicast group address\n" "Source address\n") { struct interface *ifp; const char *group_str; const char *source_str; struct in_addr group_addr; struct in_addr source_addr; int result; ifp = vty->index; /* Group address */ group_str = argv[0]; result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Source address */ source_str = argv[1]; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } result = pim_if_igmp_join_add(ifp, group_addr, source_addr); if (result) { vty_out(vty, "%% Failure joining IGMP group %s source %s on interface %s: %d%s", group_str, source_str, ifp->name, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp_join, interface_no_ip_igmp_join_cmd, "no ip igmp join A.B.C.D A.B.C.D", NO_STR IP_STR IFACE_IGMP_STR "IGMP join multicast group\n" "Multicast group address\n" "Source address\n") { struct interface *ifp; const char *group_str; const char *source_str; struct in_addr group_addr; struct in_addr source_addr; int result; ifp = vty->index; /* Group address */ group_str = argv[0]; result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Source address */ source_str = argv[1]; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } result = pim_if_igmp_join_del(ifp, group_addr, source_addr); if (result) { vty_out(vty, "%% Failure leaving IGMP group %s source %s on interface %s: %d%s", group_str, source_str, ifp->name, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* CLI reconfiguration affects the interface level (struct pim_interface). This function propagates the reconfiguration to every active socket for that interface. */ static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) { struct interface *ifp; struct pim_interface *pim_ifp; zassert(igmp); /* other querier present? */ if (igmp->t_other_querier_timer) return; /* this is the querier */ zassert(igmp->interface); zassert(igmp->interface->info); ifp = igmp->interface; pim_ifp = ifp->info; if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("%s: Querier %s on %s reconfig query_interval=%d", __PRETTY_FUNCTION__, ifaddr_str, ifp->name, pim_ifp->igmp_default_query_interval); } /* igmp_startup_mode_on() will reset QQI: igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; */ igmp_startup_mode_on(igmp); } static void igmp_sock_query_reschedule(struct igmp_sock *igmp) { if (igmp->t_igmp_query_timer) { /* other querier present */ zassert(igmp->t_igmp_query_timer); zassert(!igmp->t_other_querier_timer); pim_igmp_general_query_off(igmp); pim_igmp_general_query_on(igmp); zassert(igmp->t_igmp_query_timer); zassert(!igmp->t_other_querier_timer); } else { /* this is the querier */ zassert(!igmp->t_igmp_query_timer); zassert(igmp->t_other_querier_timer); pim_igmp_other_querier_timer_off(igmp); pim_igmp_other_querier_timer_on(igmp); zassert(!igmp->t_igmp_query_timer); zassert(igmp->t_other_querier_timer); } } static void change_query_interval(struct pim_interface *pim_ifp, int query_interval) { struct listnode *sock_node; struct igmp_sock *igmp; pim_ifp->igmp_default_query_interval = query_interval; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { igmp_sock_query_interval_reconfig(igmp); igmp_sock_query_reschedule(igmp); } } static void change_query_max_response_time(struct pim_interface *pim_ifp, int query_max_response_time_dsec) { struct listnode *sock_node; struct igmp_sock *igmp; pim_ifp->igmp_query_max_response_time_dsec = query_max_response_time_dsec; /* Below we modify socket/group/source timers in order to quickly reflect the change. Otherwise, those timers would eventually catch up. */ /* scan all sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { struct listnode *grp_node; struct igmp_group *grp; /* reschedule socket general query */ igmp_sock_query_reschedule(igmp); /* scan socket groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node, grp)) { struct listnode *src_node; struct igmp_source *src; /* reset group timers for groups in EXCLUDE mode */ if (grp->group_filtermode_isexcl) { igmp_group_reset_gmi(grp); } /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, src_node, src)) { /* reset source timers for sources with running timers */ if (src->t_source_timer) { igmp_source_reset_gmi(igmp, grp, src); } } } } } #define IGMP_QUERY_INTERVAL_MIN (1) #define IGMP_QUERY_INTERVAL_MAX (1800) DEFUN (interface_ip_igmp_query_interval, interface_ip_igmp_query_interval_cmd, PIM_CMD_IP_IGMP_QUERY_INTERVAL " <1-1800>", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_INTERVAL_STR "Query interval in seconds\n") { struct interface *ifp; struct pim_interface *pim_ifp; int query_interval; int query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "IGMP not enabled on interface %s. Please enable IGMP first.%s", ifp->name, VTY_NEWLINE); return CMD_WARNING; } query_interval = atoi(argv[0]); query_interval_dsec = 10 * query_interval; /* It seems we don't need to check bounds since command.c does it already, but we verify them anyway for extra safety. */ if (query_interval < IGMP_QUERY_INTERVAL_MIN) { vty_out(vty, "General query interval %d lower than minimum %d%s", query_interval, IGMP_QUERY_INTERVAL_MIN, VTY_NEWLINE); return CMD_WARNING; } if (query_interval > IGMP_QUERY_INTERVAL_MAX) { vty_out(vty, "General query interval %d higher than maximum %d%s", query_interval, IGMP_QUERY_INTERVAL_MAX, VTY_NEWLINE); return CMD_WARNING; } if (query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) { vty_out(vty, "Can't set general query interval %d dsec <= query max response time %d dsec.%s", query_interval_dsec, pim_ifp->igmp_query_max_response_time_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_interval(pim_ifp, query_interval); return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp_query_interval, interface_no_ip_igmp_query_interval_cmd, PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_INTERVAL, NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_INTERVAL_STR) { struct interface *ifp; struct pim_interface *pim_ifp; int default_query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; default_query_interval_dsec = IGMP_GENERAL_QUERY_INTERVAL * 10; if (default_query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) { vty_out(vty, "Can't set default general query interval %d dsec <= query max response time %d dsec.%s", default_query_interval_dsec, pim_ifp->igmp_query_max_response_time_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_interval(pim_ifp, IGMP_GENERAL_QUERY_INTERVAL); return CMD_SUCCESS; } #define IGMP_QUERY_MAX_RESPONSE_TIME_MIN (1) #define IGMP_QUERY_MAX_RESPONSE_TIME_MAX (25) DEFUN (interface_ip_igmp_query_max_response_time, interface_ip_igmp_query_max_response_time_cmd, PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME " <1-25>", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR "Query response value in seconds\n") { struct interface *ifp; struct pim_interface *pim_ifp; int query_max_response_time; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "IGMP not enabled on interface %s. Please enable IGMP first.%s", ifp->name, VTY_NEWLINE); return CMD_WARNING; } query_max_response_time = atoi(argv[0]); /* It seems we don't need to check bounds since command.c does it already, but we verify them anyway for extra safety. */ if (query_max_response_time < IGMP_QUERY_MAX_RESPONSE_TIME_MIN) { vty_out(vty, "Query max response time %d sec lower than minimum %d sec%s", query_max_response_time, IGMP_QUERY_MAX_RESPONSE_TIME_MIN, VTY_NEWLINE); return CMD_WARNING; } if (query_max_response_time > IGMP_QUERY_MAX_RESPONSE_TIME_MAX) { vty_out(vty, "Query max response time %d sec higher than maximum %d sec%s", query_max_response_time, IGMP_QUERY_MAX_RESPONSE_TIME_MAX, VTY_NEWLINE); return CMD_WARNING; } if (query_max_response_time >= pim_ifp->igmp_default_query_interval) { vty_out(vty, "Can't set query max response time %d sec >= general query interval %d sec%s", query_max_response_time, pim_ifp->igmp_default_query_interval, VTY_NEWLINE); return CMD_WARNING; } change_query_max_response_time(pim_ifp, 10 * query_max_response_time); return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp_query_max_response_time, interface_no_ip_igmp_query_max_response_time_cmd, PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME, NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR) { struct interface *ifp; struct pim_interface *pim_ifp; int default_query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; if (IGMP_QUERY_MAX_RESPONSE_TIME_DSEC >= default_query_interval_dsec) { vty_out(vty, "Can't set default query max response time %d dsec >= general query interval %d dsec.%s", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, default_query_interval_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_max_response_time(pim_ifp, IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); return CMD_SUCCESS; } #define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10) #define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250) DEFUN (interface_ip_igmp_query_max_response_time_dsec, interface_ip_igmp_query_max_response_time_dsec_cmd, PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC " <10-250>", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "Query response value in deciseconds\n") { struct interface *ifp; struct pim_interface *pim_ifp; int query_max_response_time_dsec; int default_query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "IGMP not enabled on interface %s. Please enable IGMP first.%s", ifp->name, VTY_NEWLINE); return CMD_WARNING; } query_max_response_time_dsec = atoi(argv[0]); /* It seems we don't need to check bounds since command.c does it already, but we verify them anyway for extra safety. */ if (query_max_response_time_dsec < IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC) { vty_out(vty, "Query max response time %d dsec lower than minimum %d dsec%s", query_max_response_time_dsec, IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC, VTY_NEWLINE); return CMD_WARNING; } if (query_max_response_time_dsec > IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC) { vty_out(vty, "Query max response time %d dsec higher than maximum %d dsec%s", query_max_response_time_dsec, IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC, VTY_NEWLINE); return CMD_WARNING; } default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; if (query_max_response_time_dsec >= default_query_interval_dsec) { vty_out(vty, "Can't set query max response time %d dsec >= general query interval %d dsec%s", query_max_response_time_dsec, default_query_interval_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_max_response_time(pim_ifp, query_max_response_time_dsec); return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp_query_max_response_time_dsec, interface_no_ip_igmp_query_max_response_time_dsec_cmd, PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR) { struct interface *ifp; struct pim_interface *pim_ifp; int default_query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; if (IGMP_QUERY_MAX_RESPONSE_TIME_DSEC >= default_query_interval_dsec) { vty_out(vty, "Can't set default query max response time %d dsec >= general query interval %d dsec.%s", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, default_query_interval_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_max_response_time(pim_ifp, IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); return CMD_SUCCESS; } DEFUN (interface_ip_pim_drprio, interface_ip_pim_drprio_cmd, "ip pim drpriority <1-4294967295>", IP_STR PIM_STR "Set the Designated Router Election Priority\n" "Value of the new DR Priority\n") { struct interface *ifp; struct pim_interface *pim_ifp; uint32_t old_dr_prio; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "Please enable PIM on interface, first%s", VTY_NEWLINE); return CMD_WARNING; } old_dr_prio = pim_ifp->pim_dr_priority; pim_ifp->pim_dr_priority = strtol(argv[0], NULL, 10); if (old_dr_prio != pim_ifp->pim_dr_priority) { if (pim_if_dr_election(ifp)) pim_hello_restart_now(ifp); } return CMD_SUCCESS; } DEFUN (interface_no_ip_pim_drprio, interface_no_ip_pim_drprio_cmd, "no ip pim drpriority {<1-4294967295>}", IP_STR PIM_STR "Revert the Designated Router Priority to default\n" "Old Value of the Priority\n") { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "Pim not enabled on this interface%s", VTY_NEWLINE); return CMD_WARNING; } if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) { pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; if (pim_if_dr_election(ifp)) pim_hello_restart_now(ifp); } return CMD_SUCCESS; } DEFUN (interface_ip_pim_ssm, interface_ip_pim_ssm_cmd, "ip pim ssm", IP_STR PIM_STR IFACE_PIM_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { pim_ifp = pim_if_new(ifp, 0 /* igmp=false */, 1 /* pim=true */); if (!pim_ifp) { vty_out(vty, "Could not enable PIM on interface%s", VTY_NEWLINE); return CMD_WARNING; } } else { PIM_IF_DO_PIM(pim_ifp->options); } pim_if_addr_add_all(ifp); pim_if_membership_refresh(ifp); return CMD_SUCCESS; } DEFUN (interface_no_ip_pim_ssm, interface_no_ip_pim_ssm_cmd, "no ip pim ssm", NO_STR IP_STR PIM_STR IFACE_PIM_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; PIM_IF_DONT_PIM(pim_ifp->options); pim_if_membership_clear(ifp); /* pim_if_addr_del_all() removes all sockets from pim_ifp->igmp_socket_list. */ pim_if_addr_del_all(ifp); /* pim_sock_delete() removes all neighbors from pim_ifp->pim_neighbor_list. */ pim_sock_delete(ifp, "pim unconfigured on interface"); if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { pim_if_delete(ifp); } return CMD_SUCCESS; } DEFUN (interface_ip_mroute, interface_ip_mroute_cmd, "ip mroute INTERFACE A.B.C.D", IP_STR "Add multicast route\n" "Outgoing interface name\n" "Group address\n") { struct interface *iif; struct interface *oif; const char *oifname; const char *grp_str; struct in_addr grp_addr; struct in_addr src_addr; int result; iif = vty->index; oifname = argv[0]; oif = if_lookup_by_name(oifname); if (!oif) { vty_out(vty, "No such interface name %s%s", oifname, VTY_NEWLINE); return CMD_WARNING; } grp_str = argv[1]; result = inet_pton(AF_INET, grp_str, &grp_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", grp_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } src_addr.s_addr = INADDR_ANY; if (pim_static_add(iif, oif, grp_addr, src_addr)) { vty_out(vty, "Failed to add route%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (interface_ip_mroute_source, interface_ip_mroute_source_cmd, "ip mroute INTERFACE A.B.C.D A.B.C.D", IP_STR "Add multicast route\n" "Outgoing interface name\n" "Group address\n" "Source address\n") { struct interface *iif; struct interface *oif; const char *oifname; const char *grp_str; struct in_addr grp_addr; const char *src_str; struct in_addr src_addr; int result; iif = vty->index; oifname = argv[0]; oif = if_lookup_by_name(oifname); if (!oif) { vty_out(vty, "No such interface name %s%s", oifname, VTY_NEWLINE); return CMD_WARNING; } grp_str = argv[1]; result = inet_pton(AF_INET, grp_str, &grp_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", grp_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } src_str = argv[2]; result = inet_pton(AF_INET, src_str, &src_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", src_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } if (pim_static_add(iif, oif, grp_addr, src_addr)) { vty_out(vty, "Failed to add route%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (interface_no_ip_mroute, interface_no_ip_mroute_cmd, "no ip mroute INTERFACE A.B.C.D", NO_STR IP_STR "Add multicast route\n" "Outgoing interface name\n" "Group Address\n") { struct interface *iif; struct interface *oif; const char *oifname; const char *grp_str; struct in_addr grp_addr; struct in_addr src_addr; int result; iif = vty->index; oifname = argv[0]; oif = if_lookup_by_name(oifname); if (!oif) { vty_out(vty, "No such interface name %s%s", oifname, VTY_NEWLINE); return CMD_WARNING; } grp_str = argv[1]; result = inet_pton(AF_INET, grp_str, &grp_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", grp_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } src_addr.s_addr = INADDR_ANY; if (pim_static_del(iif, oif, grp_addr, src_addr)) { vty_out(vty, "Failed to remove route%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (interface_no_ip_mroute_source, interface_no_ip_mroute_source_cmd, "no ip mroute INTERFACE A.B.C.D A.B.C.D", NO_STR IP_STR "Add multicast route\n" "Outgoing interface name\n" "Group Address\n" "Source Address\n") { struct interface *iif; struct interface *oif; const char *oifname; const char *grp_str; struct in_addr grp_addr; const char *src_str; struct in_addr src_addr; int result; iif = vty->index; oifname = argv[0]; oif = if_lookup_by_name(oifname); if (!oif) { vty_out(vty, "No such interface name %s%s", oifname, VTY_NEWLINE); return CMD_WARNING; } grp_str = argv[1]; result = inet_pton(AF_INET, grp_str, &grp_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", grp_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } src_str = argv[2]; result = inet_pton(AF_INET, src_str, &src_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", src_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } if (pim_static_del(iif, oif, grp_addr, src_addr)) { vty_out(vty, "Failed to remove route%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (interface_ip_pim_hello, interface_ip_pim_hello_cmd, "ip pim hello <1-180>", IP_STR PIM_STR IFACE_PIM_HELLO_STR IFACE_PIM_HELLO_TIME_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "Pim not enabled on this interface%s", VTY_NEWLINE); return CMD_WARNING; } pim_ifp->pim_hello_period = strtol(argv[0], NULL, 10); if (argc == 2) pim_ifp->pim_default_holdtime = strtol(argv[1], NULL, 10); return CMD_SUCCESS; } ALIAS (interface_ip_pim_hello, interface_ip_pim_hello_hold_cmd, "ip pim hello <1-180> <1-180>", IP_STR PIM_STR IFACE_PIM_HELLO_STR IFACE_PIM_HELLO_TIME_STR IFACE_PIM_HELLO_HOLD_STR) DEFUN (interface_no_ip_pim_hello, interface_no_ip_pim_hello_cmd, "no ip pim hello {<1-180> <1-180>}", NO_STR IP_STR PIM_STR IFACE_PIM_HELLO_STR IFACE_PIM_HELLO_TIME_STR IFACE_PIM_HELLO_HOLD_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "Pim not enabled on this interface%s", VTY_NEWLINE); return CMD_WARNING; } pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD; pim_ifp->pim_default_holdtime = -1; return CMD_SUCCESS; } DEFUN (debug_igmp, debug_igmp_cmd, "debug igmp", DEBUG_STR DEBUG_IGMP_STR) { PIM_DO_DEBUG_IGMP_EVENTS; PIM_DO_DEBUG_IGMP_PACKETS; PIM_DO_DEBUG_IGMP_TRACE; return CMD_SUCCESS; } DEFUN (no_debug_igmp, no_debug_igmp_cmd, "no debug igmp", NO_STR DEBUG_STR DEBUG_IGMP_STR) { PIM_DONT_DEBUG_IGMP_EVENTS; PIM_DONT_DEBUG_IGMP_PACKETS; PIM_DONT_DEBUG_IGMP_TRACE; return CMD_SUCCESS; } ALIAS (no_debug_igmp, undebug_igmp_cmd, "undebug igmp", UNDEBUG_STR DEBUG_IGMP_STR) DEFUN (debug_igmp_events, debug_igmp_events_cmd, "debug igmp events", DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_EVENTS_STR) { PIM_DO_DEBUG_IGMP_EVENTS; return CMD_SUCCESS; } DEFUN (no_debug_igmp_events, no_debug_igmp_events_cmd, "no debug igmp events", NO_STR DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_EVENTS_STR) { PIM_DONT_DEBUG_IGMP_EVENTS; return CMD_SUCCESS; } ALIAS (no_debug_igmp_events, undebug_igmp_events_cmd, "undebug igmp events", UNDEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_EVENTS_STR) DEFUN (debug_igmp_packets, debug_igmp_packets_cmd, "debug igmp packets", DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_PACKETS_STR) { PIM_DO_DEBUG_IGMP_PACKETS; return CMD_SUCCESS; } DEFUN (no_debug_igmp_packets, no_debug_igmp_packets_cmd, "no debug igmp packets", NO_STR DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_PACKETS_STR) { PIM_DONT_DEBUG_IGMP_PACKETS; return CMD_SUCCESS; } ALIAS (no_debug_igmp_packets, undebug_igmp_packets_cmd, "undebug igmp packets", UNDEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_PACKETS_STR) DEFUN (debug_igmp_trace, debug_igmp_trace_cmd, "debug igmp trace", DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_TRACE_STR) { PIM_DO_DEBUG_IGMP_TRACE; return CMD_SUCCESS; } DEFUN (no_debug_igmp_trace, no_debug_igmp_trace_cmd, "no debug igmp trace", NO_STR DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_TRACE_STR) { PIM_DONT_DEBUG_IGMP_TRACE; return CMD_SUCCESS; } ALIAS (no_debug_igmp_trace, undebug_igmp_trace_cmd, "undebug igmp trace", UNDEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_TRACE_STR) DEFUN (debug_mroute, debug_mroute_cmd, "debug mroute", DEBUG_STR DEBUG_MROUTE_STR) { PIM_DO_DEBUG_MROUTE; return CMD_SUCCESS; } DEFUN (no_debug_mroute, no_debug_mroute_cmd, "no debug mroute", NO_STR DEBUG_STR DEBUG_MROUTE_STR) { PIM_DONT_DEBUG_MROUTE; return CMD_SUCCESS; } ALIAS (no_debug_mroute, undebug_mroute_cmd, "undebug mroute", UNDEBUG_STR DEBUG_MROUTE_STR) DEFUN (debug_static, debug_static_cmd, "debug static", DEBUG_STR DEBUG_STATIC_STR) { PIM_DO_DEBUG_STATIC; return CMD_SUCCESS; } DEFUN (no_debug_static, no_debug_static_cmd, "no debug static", NO_STR DEBUG_STR DEBUG_STATIC_STR) { PIM_DONT_DEBUG_STATIC; return CMD_SUCCESS; } ALIAS (no_debug_static, undebug_static_cmd, "undebug static", UNDEBUG_STR DEBUG_STATIC_STR) DEFUN (debug_pim, debug_pim_cmd, "debug pim", DEBUG_STR DEBUG_PIM_STR) { PIM_DO_DEBUG_PIM_EVENTS; PIM_DO_DEBUG_PIM_PACKETS; PIM_DO_DEBUG_PIM_TRACE; return CMD_SUCCESS; } DEFUN (no_debug_pim, no_debug_pim_cmd, "no debug pim", NO_STR DEBUG_STR DEBUG_PIM_STR) { PIM_DONT_DEBUG_PIM_EVENTS; PIM_DONT_DEBUG_PIM_PACKETS; PIM_DONT_DEBUG_PIM_TRACE; PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND; PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV; return CMD_SUCCESS; } ALIAS (no_debug_pim, undebug_pim_cmd, "undebug pim", UNDEBUG_STR DEBUG_PIM_STR) DEFUN (debug_pim_events, debug_pim_events_cmd, "debug pim events", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_EVENTS_STR) { PIM_DO_DEBUG_PIM_EVENTS; return CMD_SUCCESS; } DEFUN (no_debug_pim_events, no_debug_pim_events_cmd, "no debug pim events", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_EVENTS_STR) { PIM_DONT_DEBUG_PIM_EVENTS; return CMD_SUCCESS; } ALIAS (no_debug_pim_events, undebug_pim_events_cmd, "undebug pim events", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_EVENTS_STR) DEFUN (debug_pim_packets, debug_pim_packets_cmd, "debug pim packets", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR) { PIM_DO_DEBUG_PIM_PACKETS; vty_out (vty, "PIM Packet debugging is on %s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (debug_pim_packets_filter, debug_pim_packets_filter_cmd, "debug pim packets (hello|joins)", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR DEBUG_PIM_HELLO_PACKETS_STR DEBUG_PIM_J_P_PACKETS_STR) { if (strncmp(argv[0],"h",1) == 0) { PIM_DO_DEBUG_PIM_HELLO; vty_out (vty, "PIM Hello debugging is on %s", VTY_NEWLINE); } else if (strncmp(argv[0],"j",1) == 0) { PIM_DO_DEBUG_PIM_J_P; vty_out (vty, "PIM Join/Prune debugging is on %s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_pim_packets, no_debug_pim_packets_cmd, "no debug pim packets", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR DEBUG_PIM_HELLO_PACKETS_STR DEBUG_PIM_J_P_PACKETS_STR) { PIM_DONT_DEBUG_PIM_PACKETS; vty_out (vty, "PIM Packet debugging is off %s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (no_debug_pim_packets_filter, no_debug_pim_packets_filter_cmd, "no debug pim packets (hello|joins)", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR DEBUG_PIM_HELLO_PACKETS_STR DEBUG_PIM_J_P_PACKETS_STR) { if (strncmp(argv[0],"h",1) == 0) { PIM_DONT_DEBUG_PIM_HELLO; vty_out (vty, "PIM Hello debugging is off %s", VTY_NEWLINE); } else if (strncmp(argv[0],"j",1) == 0) { PIM_DONT_DEBUG_PIM_J_P; vty_out (vty, "PIM Join/Prune debugging is off %s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_pim_packets, undebug_pim_packets_cmd, "undebug pim packets", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR) DEFUN (debug_pim_packetdump_send, debug_pim_packetdump_send_cmd, "debug pim packet-dump send", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_SEND_STR) { PIM_DO_DEBUG_PIM_PACKETDUMP_SEND; return CMD_SUCCESS; } DEFUN (no_debug_pim_packetdump_send, no_debug_pim_packetdump_send_cmd, "no debug pim packet-dump send", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_SEND_STR) { PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND; return CMD_SUCCESS; } ALIAS (no_debug_pim_packetdump_send, undebug_pim_packetdump_send_cmd, "undebug pim packet-dump send", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_SEND_STR) DEFUN (debug_pim_packetdump_recv, debug_pim_packetdump_recv_cmd, "debug pim packet-dump receive", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_RECV_STR) { PIM_DO_DEBUG_PIM_PACKETDUMP_RECV; return CMD_SUCCESS; } DEFUN (no_debug_pim_packetdump_recv, no_debug_pim_packetdump_recv_cmd, "no debug pim packet-dump receive", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_RECV_STR) { PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV; return CMD_SUCCESS; } ALIAS (no_debug_pim_packetdump_recv, undebug_pim_packetdump_recv_cmd, "undebug pim packet-dump receive", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_RECV_STR) DEFUN (debug_pim_trace, debug_pim_trace_cmd, "debug pim trace", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_TRACE_STR) { PIM_DO_DEBUG_PIM_TRACE; return CMD_SUCCESS; } DEFUN (no_debug_pim_trace, no_debug_pim_trace_cmd, "no debug pim trace", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_TRACE_STR) { PIM_DONT_DEBUG_PIM_TRACE; return CMD_SUCCESS; } ALIAS (no_debug_pim_trace, undebug_pim_trace_cmd, "undebug pim trace", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_TRACE_STR) DEFUN (debug_ssmpingd, debug_ssmpingd_cmd, "debug ssmpingd", DEBUG_STR DEBUG_PIM_STR DEBUG_SSMPINGD_STR) { PIM_DO_DEBUG_SSMPINGD; return CMD_SUCCESS; } DEFUN (no_debug_ssmpingd, no_debug_ssmpingd_cmd, "no debug ssmpingd", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_SSMPINGD_STR) { PIM_DONT_DEBUG_SSMPINGD; return CMD_SUCCESS; } ALIAS (no_debug_ssmpingd, undebug_ssmpingd_cmd, "undebug ssmpingd", UNDEBUG_STR DEBUG_PIM_STR DEBUG_SSMPINGD_STR) DEFUN (debug_pim_zebra, debug_pim_zebra_cmd, "debug pim zebra", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_ZEBRA_STR) { PIM_DO_DEBUG_ZEBRA; return CMD_SUCCESS; } DEFUN (no_debug_pim_zebra, no_debug_pim_zebra_cmd, "no debug pim zebra", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_ZEBRA_STR) { PIM_DONT_DEBUG_ZEBRA; return CMD_SUCCESS; } ALIAS (no_debug_pim_zebra, undebug_pim_zebra_cmd, "undebug pim zebra", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_ZEBRA_STR) DEFUN (show_debugging_pim, show_debugging_pim_cmd, "show debugging pim", SHOW_STR DEBUG_STR PIM_STR) { pim_debug_config_write(vty); return CMD_SUCCESS; } static struct igmp_sock *find_igmp_sock_by_fd(int fd) { struct listnode *ifnode; struct interface *ifp; /* scan all interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct igmp_sock *igmp; if (!ifp->info) continue; pim_ifp = ifp->info; /* lookup igmp socket under current interface */ igmp = igmp_sock_lookup_by_fd(pim_ifp->igmp_socket_list, fd); if (igmp) return igmp; } return 0; } DEFUN (test_igmp_receive_report, test_igmp_receive_report_cmd, "test igmp receive report <0-65535> A.B.C.D <1-6> .LINE", "Test\n" "Test IGMP protocol\n" "Test IGMP message\n" "Test IGMP report\n" "Socket\n" "IGMP group address\n" "Record type\n" "Sources\n") { char buf[1000]; char *igmp_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; int igmp_msg_len; const char *socket; int socket_fd; const char *grp_str; struct in_addr grp_addr; const char *record_type_str; int record_type; const char *src_str; int result; struct igmp_sock *igmp; char *group_record; int num_sources; struct in_addr *sources; struct in_addr *src_addr; int argi; socket = argv[0]; socket_fd = atoi(socket); igmp = find_igmp_sock_by_fd(socket_fd); if (!igmp) { vty_out(vty, "Could not find IGMP socket %s: fd=%d%s", socket, socket_fd, VTY_NEWLINE); return CMD_WARNING; } grp_str = argv[1]; result = inet_pton(AF_INET, grp_str, &grp_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", grp_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } record_type_str = argv[2]; record_type = atoi(record_type_str); /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_IGMP; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = igmp->ifaddr; ip_hdr->ip_dst = igmp->ifaddr; /* Build IGMP v3 report message */ igmp_msg = buf + ip_hlen; group_record = igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET; *igmp_msg = PIM_IGMP_V3_MEMBERSHIP_REPORT; /* type */ *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET) = htons(1); /* one group record */ *(uint8_t *) (group_record + IGMP_V3_GROUP_RECORD_TYPE_OFFSET) = record_type; memcpy(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, &grp_addr, sizeof(struct in_addr)); /* Scan LINE sources */ sources = (struct in_addr *) (group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET); src_addr = sources; for (argi = 3; argi < argc; ++argi,++src_addr) { src_str = argv[argi]; result = inet_pton(AF_INET, src_str, src_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", src_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } } num_sources = src_addr - sources; *(uint16_t *)(group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET) = htons(num_sources); igmp_msg_len = IGMP_V3_MSG_MIN_SIZE + (num_sources << 4); /* v3 report for one single group record */ /* compute checksum */ *(uint16_t *)(igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = in_cksum(igmp_msg, igmp_msg_len); /* "receive" message */ ip_msg_len = ip_hlen + igmp_msg_len; result = pim_igmp_packet(igmp, buf, ip_msg_len); if (result) { vty_out(vty, "pim_igmp_packet(len=%d) returned: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } static int hexval(uint8_t ch) { return isdigit(ch) ? (ch - '0') : (10 + tolower(ch) - 'a'); } DEFUN (test_pim_receive_dump, test_pim_receive_dump_cmd, "test pim receive dump INTERFACE A.B.C.D .LINE", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM packet dump reception from neighbor\n" "Interface\n" "Neighbor address\n" "Packet dump\n") { uint8_t buf[1000]; uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; int pim_msg_size; const char *neigh_str; struct in_addr neigh_addr; const char *ifname; struct interface *ifp; int argi; int result; /* Find interface */ ifname = argv[0]; ifp = if_lookup_by_name(ifname); if (!ifp) { vty_out(vty, "No such interface name %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } /* Neighbor address */ neigh_str = argv[1]; result = inet_pton(AF_INET, neigh_str, &neigh_addr); if (result <= 0) { vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_PIM; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = neigh_addr; ip_hdr->ip_dst = qpim_all_pim_routers_addr; /* Build PIM hello message */ pim_msg = buf + ip_hlen; pim_msg_size = 0; /* Scan LINE dump into buffer */ for (argi = 2; argi < argc; ++argi) { const char *str = argv[argi]; int str_len = strlen(str); int str_last = str_len - 1; int i; if (str_len % 2) { vty_out(vty, "%% Uneven hex array arg %d=%s%s", argi, str, VTY_NEWLINE); return CMD_WARNING; } for (i = 0; i < str_last; i += 2) { uint8_t octet; int left; uint8_t h1 = str[i]; uint8_t h2 = str[i + 1]; if (!isxdigit(h1) || !isxdigit(h2)) { vty_out(vty, "%% Non-hex octet %c%c at hex array arg %d=%s%s", h1, h2, argi, str, VTY_NEWLINE); return CMD_WARNING; } octet = (hexval(h1) << 4) + hexval(h2); left = sizeof(buf) - ip_hlen - pim_msg_size; if (left < 1) { vty_out(vty, "%% Overflow buf_size=%zu buf_left=%d at hex array arg %d=%s octet %02x%s", sizeof(buf), left, argi, str, octet, VTY_NEWLINE); return CMD_WARNING; } pim_msg[pim_msg_size++] = octet; } } ip_msg_len = ip_hlen + pim_msg_size; vty_out(vty, "Receiving: buf_size=%zu ip_msg_size=%d pim_msg_size=%d%s", sizeof(buf), ip_msg_len, pim_msg_size, VTY_NEWLINE); /* "receive" message */ result = pim_pim_packet(ifp, buf, ip_msg_len); if (result) { vty_out(vty, "%% pim_pim_packet(len=%d) returned failure: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (test_pim_receive_hello, test_pim_receive_hello_cmd, "test pim receive hello INTERFACE A.B.C.D <0-65535> <0-65535> <0-65535> <0-32767> <0-65535> <0-1>[LINE]", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM hello reception from neighbor\n" "Interface\n" "Neighbor address\n" "Neighbor holdtime\n" "Neighbor DR priority\n" "Neighbor generation ID\n" "Neighbor propagation delay (msec)\n" "Neighbor override interval (msec)\n" "Neighbor LAN prune delay T-bit\n" "Neighbor secondary addresses\n") { uint8_t buf[1000]; uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; int pim_tlv_size; int pim_msg_size; const char *neigh_str; struct in_addr neigh_addr; const char *ifname; struct interface *ifp; uint16_t neigh_holdtime; uint16_t neigh_propagation_delay; uint16_t neigh_override_interval; int neigh_can_disable_join_suppression; uint32_t neigh_dr_priority; uint32_t neigh_generation_id; int argi; int result; /* Find interface */ ifname = argv[0]; ifp = if_lookup_by_name(ifname); if (!ifp) { vty_out(vty, "No such interface name %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } /* Neighbor address */ neigh_str = argv[1]; result = inet_pton(AF_INET, neigh_str, &neigh_addr); if (result <= 0) { vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } neigh_holdtime = atoi(argv[2]); neigh_dr_priority = atoi(argv[3]); neigh_generation_id = atoi(argv[4]); neigh_propagation_delay = atoi(argv[5]); neigh_override_interval = atoi(argv[6]); neigh_can_disable_join_suppression = atoi(argv[7]); /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_PIM; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = neigh_addr; ip_hdr->ip_dst = qpim_all_pim_routers_addr; /* Build PIM hello message */ pim_msg = buf + ip_hlen; /* Scan LINE addresses */ for (argi = 8; argi < argc; ++argi) { const char *sec_str = argv[argi]; struct in_addr sec_addr; result = inet_pton(AF_INET, sec_str, &sec_addr); if (result <= 0) { vty_out(vty, "Bad neighbor secondary address %s: errno=%d: %s%s", sec_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } vty_out(vty, "FIXME WRITEME consider neighbor secondary address %s%s", sec_str, VTY_NEWLINE); } pim_tlv_size = pim_hello_build_tlv(ifp->name, pim_msg + PIM_PIM_MIN_LEN, sizeof(buf) - ip_hlen - PIM_PIM_MIN_LEN, neigh_holdtime, neigh_dr_priority, neigh_generation_id, neigh_propagation_delay, neigh_override_interval, neigh_can_disable_join_suppression, 0 /* FIXME secondary address list */); if (pim_tlv_size < 0) { vty_out(vty, "pim_hello_build_tlv() returned failure: %d%s", pim_tlv_size, VTY_NEWLINE); return CMD_WARNING; } pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN; pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO); /* "receive" message */ ip_msg_len = ip_hlen + pim_msg_size; result = pim_pim_packet(ifp, buf, ip_msg_len); if (result) { vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (test_pim_receive_assert, test_pim_receive_assert_cmd, "test pim receive assert INTERFACE A.B.C.D A.B.C.D A.B.C.D <0-65535> <0-65535> <0-1>", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test reception of PIM assert\n" "Interface\n" "Neighbor address\n" "Assert multicast group address\n" "Assert unicast source address\n" "Assert metric preference\n" "Assert route metric\n" "Assert RPT bit flag\n") { uint8_t buf[1000]; uint8_t *buf_pastend = buf + sizeof(buf); uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; int pim_msg_size; const char *neigh_str; struct in_addr neigh_addr; const char *group_str; struct in_addr group_addr; const char *source_str; struct in_addr source_addr; const char *ifname; struct interface *ifp; uint32_t assert_metric_preference; uint32_t assert_route_metric; uint32_t assert_rpt_bit_flag; int remain; int result; /* Find interface */ ifname = argv[0]; ifp = if_lookup_by_name(ifname); if (!ifp) { vty_out(vty, "No such interface name %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } /* Neighbor address */ neigh_str = argv[1]; result = inet_pton(AF_INET, neigh_str, &neigh_addr); if (result <= 0) { vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Group address */ group_str = argv[2]; result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Source address */ source_str = argv[3]; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } assert_metric_preference = atoi(argv[4]); assert_route_metric = atoi(argv[5]); assert_rpt_bit_flag = atoi(argv[6]); remain = buf_pastend - buf; if (remain < (int) sizeof(struct ip)) { vty_out(vty, "No room for ip header: buf_size=%d < ip_header_size=%zu%s", remain, sizeof(struct ip), VTY_NEWLINE); return CMD_WARNING; } /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_PIM; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = neigh_addr; ip_hdr->ip_dst = qpim_all_pim_routers_addr; /* Build PIM assert message */ pim_msg = buf + ip_hlen; /* skip ip header */ pim_msg_size = pim_assert_build_msg(pim_msg, buf_pastend - pim_msg, ifp, group_addr, source_addr, assert_metric_preference, assert_route_metric, assert_rpt_bit_flag); if (pim_msg_size < 0) { vty_out(vty, "Failure building PIM assert message: size=%d%s", pim_msg_size, VTY_NEWLINE); return CMD_WARNING; } /* "receive" message */ ip_msg_len = ip_hlen + pim_msg_size; result = pim_pim_packet(ifp, buf, ip_msg_len); if (result) { vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } static int recv_joinprune(struct vty *vty, const char *argv[], int src_is_join) { uint8_t buf[1000]; const uint8_t *buf_pastend = buf + sizeof(buf); uint8_t *pim_msg; uint8_t *pim_msg_curr; int pim_msg_size; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; uint16_t neigh_holdtime; const char *neigh_dst_str; struct in_addr neigh_dst_addr; const char *neigh_src_str; struct in_addr neigh_src_addr; const char *group_str; struct in_addr group_addr; const char *source_str; struct in_addr source_addr; const char *ifname; struct interface *ifp; int result; int remain; uint16_t num_joined; uint16_t num_pruned; /* Find interface */ ifname = argv[0]; ifp = if_lookup_by_name(ifname); if (!ifp) { vty_out(vty, "No such interface name %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } neigh_holdtime = atoi(argv[1]); /* Neighbor destination address */ neigh_dst_str = argv[2]; result = inet_pton(AF_INET, neigh_dst_str, &neigh_dst_addr); if (result <= 0) { vty_out(vty, "Bad neighbor destination address %s: errno=%d: %s%s", neigh_dst_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Neighbor source address */ neigh_src_str = argv[3]; result = inet_pton(AF_INET, neigh_src_str, &neigh_src_addr); if (result <= 0) { vty_out(vty, "Bad neighbor source address %s: errno=%d: %s%s", neigh_src_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Multicast group address */ group_str = argv[4]; result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Multicast source address */ source_str = argv[5]; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_PIM; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = neigh_src_addr; ip_hdr->ip_dst = qpim_all_pim_routers_addr; /* Build PIM message */ pim_msg = buf + ip_hlen; /* skip room for pim header */ pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, remain, neigh_dst_addr); if (!pim_msg_curr) { vty_out(vty, "Failure encoding destination address %s: space left=%d%s", neigh_dst_str, remain, VTY_NEWLINE); return CMD_WARNING; } remain = buf_pastend - pim_msg_curr; if (remain < 4) { vty_out(vty, "Group will not fit: space left=%d%s", remain, VTY_NEWLINE); return CMD_WARNING; } *pim_msg_curr = 0; /* reserved */ ++pim_msg_curr; *pim_msg_curr = 1; /* number of groups */ ++pim_msg_curr; *((uint16_t *) pim_msg_curr) = htons(neigh_holdtime); ++pim_msg_curr; ++pim_msg_curr; remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, remain, group_addr); if (!pim_msg_curr) { vty_out(vty, "Failure encoding group address %s: space left=%d%s", group_str, remain, VTY_NEWLINE); return CMD_WARNING; } remain = buf_pastend - pim_msg_curr; if (remain < 4) { vty_out(vty, "Sources will not fit: space left=%d%s", remain, VTY_NEWLINE); return CMD_WARNING; } if (src_is_join) { num_joined = 1; num_pruned = 0; } else { num_joined = 0; num_pruned = 1; } /* number of joined sources */ *((uint16_t *) pim_msg_curr) = htons(num_joined); ++pim_msg_curr; ++pim_msg_curr; /* number of pruned sources */ *((uint16_t *) pim_msg_curr) = htons(num_pruned); ++pim_msg_curr; ++pim_msg_curr; remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr, remain, source_addr); if (!pim_msg_curr) { vty_out(vty, "Failure encoding source address %s: space left=%d%s", source_str, remain, VTY_NEWLINE); return CMD_WARNING; } /* Add PIM header */ pim_msg_size = pim_msg_curr - pim_msg; pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_JOIN_PRUNE); /* "Receive" message */ ip_msg_len = ip_hlen + pim_msg_size; result = pim_pim_packet(ifp, buf, ip_msg_len); if (result) { vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (test_pim_receive_join, test_pim_receive_join_cmd, "test pim receive join INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM join reception from neighbor\n" "Interface\n" "Neighbor holdtime\n" "Upstream neighbor unicast destination address\n" "Downstream neighbor unicast source address\n" "Multicast group address\n" "Unicast source address\n") { return recv_joinprune(vty, argv, 1 /* src_is_join=true */); } DEFUN (test_pim_receive_prune, test_pim_receive_prune_cmd, "test pim receive prune INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM prune reception from neighbor\n" "Interface\n" "Neighbor holdtime\n" "Upstream neighbor unicast destination address\n" "Downstream neighbor unicast source address\n" "Multicast group address\n" "Unicast source address\n") { return recv_joinprune(vty, argv, 0 /* src_is_join=false */); } DEFUN (test_pim_receive_upcall, test_pim_receive_upcall_cmd, "test pim receive upcall (nocache|wrongvif|wholepkt) <0-65535> A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test reception of kernel upcall\n" "NOCACHE kernel upcall\n" "WRONGVIF kernel upcall\n" "WHOLEPKT kernel upcall\n" "Input interface vif index\n" "Multicast group address\n" "Multicast source address\n") { struct igmpmsg msg; const char *upcall_type; const char *group_str; const char *source_str; int result; upcall_type = argv[0]; if (upcall_type[0] == 'n') msg.im_msgtype = IGMPMSG_NOCACHE; else if (upcall_type[1] == 'r') msg.im_msgtype = IGMPMSG_WRONGVIF; else if (upcall_type[1] == 'h') msg.im_msgtype = IGMPMSG_WHOLEPKT; else { vty_out(vty, "Unknown kernel upcall type: %s%s", upcall_type, VTY_NEWLINE); return CMD_WARNING; } msg.im_vif = atoi(argv[1]); /* Group address */ group_str = argv[2]; result = inet_pton(AF_INET, group_str, &msg.im_dst); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Source address */ source_str = argv[3]; result = inet_pton(AF_INET, source_str, &msg.im_src); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } msg.im_mbz = 0; /* Must be zero */ result = pim_mroute_msg(-1, (char *) &msg, sizeof(msg)); if (result) { vty_out(vty, "pim_mroute_msg(len=%zu) returned failure: %d%s", sizeof(msg), result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } void pim_cmd_init() { install_node (&pim_global_node, pim_global_config_write); /* PIM_NODE */ install_node (&interface_node, pim_interface_config_write); /* INTERFACE_NODE */ install_element (CONFIG_NODE, &ip_multicast_routing_cmd); install_element (CONFIG_NODE, &no_ip_multicast_routing_cmd); install_element (CONFIG_NODE, &ip_ssmpingd_cmd); install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd); #if 0 install_element (CONFIG_NODE, &interface_cmd); /* from if.h */ #else install_element (CONFIG_NODE, &pim_interface_cmd); #endif install_element (CONFIG_NODE, &no_interface_cmd); /* from if.h */ install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_ip_igmp_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_join_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_join_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_interval_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_dsec_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd); install_element (INTERFACE_NODE, &interface_ip_pim_ssm_cmd); install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); install_element (INTERFACE_NODE, &interface_ip_pim_drprio_cmd); install_element (INTERFACE_NODE, &interface_no_ip_pim_drprio_cmd); install_element (INTERFACE_NODE, &interface_ip_pim_hello_cmd); install_element (INTERFACE_NODE, &interface_ip_pim_hello_hold_cmd); install_element (INTERFACE_NODE, &interface_no_ip_pim_hello_cmd); // Static mroutes NEB install_element (INTERFACE_NODE, &interface_ip_mroute_cmd); install_element (INTERFACE_NODE, &interface_ip_mroute_source_cmd); install_element (INTERFACE_NODE, &interface_no_ip_mroute_cmd); install_element (INTERFACE_NODE, &interface_no_ip_mroute_source_cmd); install_element (VIEW_NODE, &show_ip_igmp_interface_cmd); install_element (VIEW_NODE, &show_ip_igmp_join_cmd); install_element (VIEW_NODE, &show_ip_igmp_parameters_cmd); install_element (VIEW_NODE, &show_ip_igmp_groups_cmd); install_element (VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); install_element (VIEW_NODE, &show_ip_igmp_sources_cmd); install_element (VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd); install_element (VIEW_NODE, &show_ip_igmp_querier_cmd); install_element (VIEW_NODE, &show_ip_pim_assert_cmd); install_element (VIEW_NODE, &show_ip_pim_assert_internal_cmd); install_element (VIEW_NODE, &show_ip_pim_assert_metric_cmd); install_element (VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd); install_element (VIEW_NODE, &show_ip_pim_dr_cmd); install_element (VIEW_NODE, &show_ip_pim_hello_cmd); install_element (VIEW_NODE, &show_ip_pim_interface_cmd); install_element (VIEW_NODE, &show_ip_pim_join_cmd); install_element (VIEW_NODE, &show_ip_pim_jp_override_interval_cmd); install_element (VIEW_NODE, &show_ip_pim_lan_prune_delay_cmd); install_element (VIEW_NODE, &show_ip_pim_local_membership_cmd); install_element (VIEW_NODE, &show_ip_pim_neighbor_cmd); install_element (VIEW_NODE, &show_ip_pim_rpf_cmd); install_element (VIEW_NODE, &show_ip_pim_secondary_cmd); install_element (VIEW_NODE, &show_ip_pim_upstream_cmd); install_element (VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd); install_element (VIEW_NODE, &show_ip_pim_upstream_rpf_cmd); install_element (VIEW_NODE, &show_ip_multicast_cmd); install_element (VIEW_NODE, &show_ip_mroute_cmd); install_element (VIEW_NODE, &show_ip_mroute_count_cmd); install_element (VIEW_NODE, &show_ip_rib_cmd); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); install_element (VIEW_NODE, &show_debugging_pim_cmd); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_mroute_cmd); install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd); install_element (ENABLE_NODE, &test_igmp_receive_report_cmd); install_element (ENABLE_NODE, &test_pim_receive_assert_cmd); install_element (ENABLE_NODE, &test_pim_receive_dump_cmd); install_element (ENABLE_NODE, &test_pim_receive_hello_cmd); install_element (ENABLE_NODE, &test_pim_receive_join_cmd); install_element (ENABLE_NODE, &test_pim_receive_prune_cmd); install_element (ENABLE_NODE, &test_pim_receive_upcall_cmd); install_element (ENABLE_NODE, &debug_igmp_cmd); install_element (ENABLE_NODE, &no_debug_igmp_cmd); install_element (ENABLE_NODE, &undebug_igmp_cmd); install_element (ENABLE_NODE, &debug_igmp_events_cmd); install_element (ENABLE_NODE, &no_debug_igmp_events_cmd); install_element (ENABLE_NODE, &undebug_igmp_events_cmd); install_element (ENABLE_NODE, &debug_igmp_packets_cmd); install_element (ENABLE_NODE, &no_debug_igmp_packets_cmd); install_element (ENABLE_NODE, &undebug_igmp_packets_cmd); install_element (ENABLE_NODE, &debug_igmp_trace_cmd); install_element (ENABLE_NODE, &no_debug_igmp_trace_cmd); install_element (ENABLE_NODE, &undebug_igmp_trace_cmd); install_element (ENABLE_NODE, &debug_mroute_cmd); install_element (ENABLE_NODE, &no_debug_mroute_cmd); install_element (ENABLE_NODE, &debug_static_cmd); install_element (ENABLE_NODE, &no_debug_static_cmd); install_element (ENABLE_NODE, &debug_pim_cmd); install_element (ENABLE_NODE, &no_debug_pim_cmd); install_element (ENABLE_NODE, &undebug_pim_cmd); install_element (ENABLE_NODE, &debug_pim_events_cmd); install_element (ENABLE_NODE, &no_debug_pim_events_cmd); install_element (ENABLE_NODE, &undebug_pim_events_cmd); install_element (ENABLE_NODE, &debug_pim_packets_cmd); install_element (ENABLE_NODE, &debug_pim_packets_filter_cmd); install_element (ENABLE_NODE, &no_debug_pim_packets_cmd); install_element (ENABLE_NODE, &no_debug_pim_packets_filter_cmd); install_element (ENABLE_NODE, &undebug_pim_packets_cmd); install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd); install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd); install_element (ENABLE_NODE, &undebug_pim_packetdump_send_cmd); install_element (ENABLE_NODE, &debug_pim_packetdump_recv_cmd); install_element (ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd); install_element (ENABLE_NODE, &undebug_pim_packetdump_recv_cmd); install_element (ENABLE_NODE, &debug_pim_trace_cmd); install_element (ENABLE_NODE, &no_debug_pim_trace_cmd); install_element (ENABLE_NODE, &undebug_pim_trace_cmd); install_element (ENABLE_NODE, &debug_ssmpingd_cmd); install_element (ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element (ENABLE_NODE, &undebug_ssmpingd_cmd); install_element (ENABLE_NODE, &debug_pim_zebra_cmd); install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd); install_element (ENABLE_NODE, &undebug_pim_zebra_cmd); install_element (CONFIG_NODE, &debug_igmp_cmd); install_element (CONFIG_NODE, &no_debug_igmp_cmd); install_element (CONFIG_NODE, &undebug_igmp_cmd); install_element (CONFIG_NODE, &debug_igmp_events_cmd); install_element (CONFIG_NODE, &no_debug_igmp_events_cmd); install_element (CONFIG_NODE, &undebug_igmp_events_cmd); install_element (CONFIG_NODE, &debug_igmp_packets_cmd); install_element (CONFIG_NODE, &no_debug_igmp_packets_cmd); install_element (CONFIG_NODE, &undebug_igmp_packets_cmd); install_element (CONFIG_NODE, &debug_igmp_trace_cmd); install_element (CONFIG_NODE, &no_debug_igmp_trace_cmd); install_element (CONFIG_NODE, &undebug_igmp_trace_cmd); install_element (CONFIG_NODE, &debug_mroute_cmd); install_element (CONFIG_NODE, &no_debug_mroute_cmd); install_element (CONFIG_NODE, &debug_static_cmd); install_element (CONFIG_NODE, &no_debug_static_cmd); install_element (CONFIG_NODE, &debug_pim_cmd); install_element (CONFIG_NODE, &no_debug_pim_cmd); install_element (CONFIG_NODE, &undebug_pim_cmd); install_element (CONFIG_NODE, &debug_pim_events_cmd); install_element (CONFIG_NODE, &no_debug_pim_events_cmd); install_element (CONFIG_NODE, &undebug_pim_events_cmd); install_element (CONFIG_NODE, &debug_pim_packets_cmd); install_element (CONFIG_NODE, &debug_pim_packets_filter_cmd); install_element (CONFIG_NODE, &no_debug_pim_packets_cmd); install_element (CONFIG_NODE, &no_debug_pim_packets_filter_cmd); install_element (CONFIG_NODE, &undebug_pim_packets_cmd); install_element (CONFIG_NODE, &debug_pim_trace_cmd); install_element (CONFIG_NODE, &no_debug_pim_trace_cmd); install_element (CONFIG_NODE, &undebug_pim_trace_cmd); install_element (CONFIG_NODE, &debug_ssmpingd_cmd); install_element (CONFIG_NODE, &no_debug_ssmpingd_cmd); install_element (CONFIG_NODE, &undebug_ssmpingd_cmd); install_element (CONFIG_NODE, &debug_pim_zebra_cmd); install_element (CONFIG_NODE, &no_debug_pim_zebra_cmd); install_element (CONFIG_NODE, &undebug_pim_zebra_cmd); } quagga-1.2.4/pimd/pim_cmd.h000066400000000000000000000077731325323223500155130ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_CMD_H #define PIM_CMD_H #define PIM_STR "PIM information\n" #define IGMP_STR "IGMP information\n" #define IGMP_GROUP_STR "IGMP groups information\n" #define IGMP_SOURCE_STR "IGMP sources information\n" #define CONF_SSMPINGD_STR "Enable ssmpingd operation\n" #define SHOW_SSMPINGD_STR "ssmpingd operation\n" #define IFACE_PIM_STR "Enable PIM SSM operation\n" #define IFACE_PIM_HELLO_STR "Hello Interval\n" #define IFACE_PIM_HELLO_TIME_STR "Time in seconds for Hello Interval\n" #define IFACE_PIM_HELLO_HOLD_STR "Time in seconds for Hold Interval\n" #define IFACE_IGMP_STR "Enable IGMP operation\n" #define IFACE_IGMP_QUERY_INTERVAL_STR "IGMP host query interval\n" #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR "IGMP max query response value (seconds)\n" #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "IGMP max query response value (deciseconds)\n" #define DEBUG_IGMP_STR "IGMP protocol activity\n" #define DEBUG_IGMP_EVENTS_STR "IGMP protocol events\n" #define DEBUG_IGMP_PACKETS_STR "IGMP protocol packets\n" #define DEBUG_IGMP_TRACE_STR "IGMP internal daemon activity\n" #define DEBUG_MROUTE_STR "PIM interaction with kernel MFC cache\n" #define DEBUG_STATIC_STR "PIM Static Multicast Route activity\n" #define DEBUG_PIM_STR "PIM protocol activity\n" #define DEBUG_PIM_EVENTS_STR "PIM protocol events\n" #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" #define DEBUG_PIM_HELLO_PACKETS_STR "PIM Hello protocol packets\n" #define DEBUG_PIM_J_P_PACKETS_STR "PIM Join/Prune protocol packets\n" #define DEBUG_PIM_PACKETDUMP_STR "PIM packet dump\n" #define DEBUG_PIM_PACKETDUMP_SEND_STR "Dump sent packets\n" #define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n" #define DEBUG_PIM_TRACE_STR "PIM internal daemon activity\n" #define DEBUG_PIM_ZEBRA_STR "ZEBRA protocol activity\n" #define DEBUG_SSMPINGD_STR "ssmpingd activity\n" #define CLEAR_IP_IGMP_STR "IGMP clear commands\n" #define CLEAR_IP_PIM_STR "PIM clear commands\n" #define MROUTE_STR "IP multicast routing table\n" #define RIB_STR "IP unicast routing table\n" #define PIM_CMD_NO "no" #define PIM_CMD_IP_MULTICAST_ROUTING "ip multicast-routing" #define PIM_CMD_IP_IGMP_QUERY_INTERVAL "ip igmp query-interval" #define PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME "ip igmp query-max-response-time" #define PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC "ip igmp query-max-response-time-dsec" void pim_cmd_init(void); #endif /* PIM_CMD_H */ quagga-1.2.4/pimd/pim_hello.c000066400000000000000000000365101325323223500160350ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "pimd.h" #include "pim_pim.h" #include "pim_str.h" #include "pim_tlv.h" #include "pim_util.h" #include "pim_hello.h" #include "pim_iface.h" #include "pim_neighbor.h" #include "pim_upstream.h" static void on_trace(const char *label, struct interface *ifp, struct in_addr src) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src, src_str, sizeof(src_str)); zlog_debug("%s: from %s on %s", label, src_str, ifp->name); } } static void tlv_trace_bool(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, int value) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d", label, src_str, ifname, tlv_name, value); } } static void tlv_trace_uint16(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, uint16_t value) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u", label, src_str, ifname, tlv_name, value); } } static void tlv_trace_uint32(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, uint32_t value) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u", label, src_str, ifname, tlv_name, value); } } static void tlv_trace_uint32_hex(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, uint32_t value) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x", label, src_str, ifname, tlv_name, value); } } #if 0 static void tlv_trace(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s", label, src_str, ifname, tlv_name); } } #endif static void tlv_trace_list(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, struct list *addr_list) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p", label, src_str, ifname, tlv_name, addr_list ? ((int) listcount(addr_list)) : -1, (void *) addr_list); } } #define FREE_ADDR_LIST \ if (hello_option_addr_list) { \ list_delete(hello_option_addr_list); \ } #define FREE_ADDR_LIST_THEN_RETURN(code) \ { \ FREE_ADDR_LIST \ return (code); \ } int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; uint8_t *tlv_curr; uint8_t *tlv_pastend; pim_hello_options hello_options = 0; /* bit array recording options found */ uint16_t hello_option_holdtime = 0; uint16_t hello_option_propagation_delay = 0; uint16_t hello_option_override_interval = 0; uint32_t hello_option_dr_priority = 0; uint32_t hello_option_generation_id = 0; struct list *hello_option_addr_list = 0; if (PIM_DEBUG_PIM_HELLO) on_trace(__PRETTY_FUNCTION__, ifp, src_addr); pim_ifp = ifp->info; zassert(pim_ifp); ++pim_ifp->pim_ifstat_hello_recv; /* Parse PIM hello TLVs */ zassert(tlv_buf_size >= 0); tlv_curr = tlv_buf; tlv_pastend = tlv_buf + tlv_buf_size; while (tlv_curr < tlv_pastend) { uint16_t option_type; uint16_t option_len; int remain = tlv_pastend - tlv_curr; if (remain < PIM_TLV_MIN_SIZE) { if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s", __PRETTY_FUNCTION__, remain, PIM_TLV_MIN_SIZE, src_str, ifp->name); } FREE_ADDR_LIST_THEN_RETURN(-1); } option_type = PIM_TLV_GET_TYPE(tlv_curr); tlv_curr += PIM_TLV_TYPE_SIZE; option_len = PIM_TLV_GET_LENGTH(tlv_curr); tlv_curr += PIM_TLV_LENGTH_SIZE; if ((tlv_curr + option_len) > tlv_pastend) { if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s", __PRETTY_FUNCTION__, option_type, option_len, tlv_pastend - tlv_curr, src_str, ifp->name); } FREE_ADDR_LIST_THEN_RETURN(-2); } if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s", __PRETTY_FUNCTION__, remain, option_type, option_len, src_str, ifp->name); } switch (option_type) { case PIM_MSG_OPTION_TYPE_HOLDTIME: if (pim_tlv_parse_holdtime(ifp->name, src_addr, &hello_options, &hello_option_holdtime, option_len, tlv_curr)) { FREE_ADDR_LIST_THEN_RETURN(-3); } break; case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY: if (pim_tlv_parse_lan_prune_delay(ifp->name, src_addr, &hello_options, &hello_option_propagation_delay, &hello_option_override_interval, option_len, tlv_curr)) { FREE_ADDR_LIST_THEN_RETURN(-4); } break; case PIM_MSG_OPTION_TYPE_DR_PRIORITY: if (pim_tlv_parse_dr_priority(ifp->name, src_addr, &hello_options, &hello_option_dr_priority, option_len, tlv_curr)) { FREE_ADDR_LIST_THEN_RETURN(-5); } break; case PIM_MSG_OPTION_TYPE_GENERATION_ID: if (pim_tlv_parse_generation_id(ifp->name, src_addr, &hello_options, &hello_option_generation_id, option_len, tlv_curr)) { FREE_ADDR_LIST_THEN_RETURN(-6); } break; case PIM_MSG_OPTION_TYPE_ADDRESS_LIST: if (pim_tlv_parse_addr_list(ifp->name, src_addr, &hello_options, &hello_option_addr_list, option_len, tlv_curr)) { return -7; } break; case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH: if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s", __PRETTY_FUNCTION__, option_type, option_len, src_str, ifp->name); } break; default: if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s", __PRETTY_FUNCTION__, option_type, option_len, src_str, ifp->name); } } tlv_curr += option_len; } /* Check received PIM hello options */ if (PIM_DEBUG_PIM_HELLO) { tlv_trace_uint16(__PRETTY_FUNCTION__, "holdtime", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME), hello_option_holdtime); tlv_trace_uint16(__PRETTY_FUNCTION__, "propagation_delay", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), hello_option_propagation_delay); tlv_trace_uint16(__PRETTY_FUNCTION__, "override_interval", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), hello_option_override_interval); tlv_trace_bool(__PRETTY_FUNCTION__, "can_disable_join_suppression", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION)); tlv_trace_uint32(__PRETTY_FUNCTION__, "dr_priority", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY), hello_option_dr_priority); tlv_trace_uint32_hex(__PRETTY_FUNCTION__, "generation_id", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID), hello_option_generation_id); tlv_trace_list(__PRETTY_FUNCTION__, "address_list", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_ADDRESS_LIST), hello_option_addr_list); } if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello missing holdtime from %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } } /* New neighbor? */ neigh = pim_neighbor_find(ifp, src_addr); if (!neigh) { /* Add as new neighbor */ neigh = pim_neighbor_add(ifp, src_addr, hello_options, hello_option_holdtime, hello_option_propagation_delay, hello_option_override_interval, hello_option_dr_priority, hello_option_generation_id, hello_option_addr_list); if (!neigh) { if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: failure creating PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } FREE_ADDR_LIST_THEN_RETURN(-8); } /* actual addr list has been saved under neighbor */ return 0; } /* Received generation ID ? */ if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID)) { /* GenID mismatch ? */ if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) || (hello_option_generation_id != neigh->generation_id)) { /* GenID changed */ pim_upstream_rpf_genid_changed(neigh->source_addr); /* GenID mismatch, then replace neighbor */ if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s", __PRETTY_FUNCTION__, hello_option_generation_id, neigh->generation_id, src_str, ifp->name); } pim_upstream_rpf_genid_changed(neigh->source_addr); pim_neighbor_delete(ifp, neigh, "GenID mismatch"); neigh = pim_neighbor_add(ifp, src_addr, hello_options, hello_option_holdtime, hello_option_propagation_delay, hello_option_override_interval, hello_option_dr_priority, hello_option_generation_id, hello_option_addr_list); if (!neigh) { if (PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } FREE_ADDR_LIST_THEN_RETURN(-9); } /* actual addr list is saved under neighbor */ return 0; } /* GenId mismatch: replace neighbor */ } /* GenId received */ /* Update existing neighbor */ pim_neighbor_update(neigh, hello_options, hello_option_holdtime, hello_option_dr_priority, hello_option_addr_list); /* actual addr list is saved under neighbor */ return 0; } int pim_hello_build_tlv(const char *ifname, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, uint16_t propagation_delay, uint16_t override_interval, int can_disable_join_suppression, struct list *ifconnected) { uint8_t *curr = tlv_buf; uint8_t *pastend = tlv_buf + tlv_buf_size; uint8_t *tmp; /* * Append options */ /* Holdtime */ curr = pim_tlv_append_uint16(curr, pastend, PIM_MSG_OPTION_TYPE_HOLDTIME, holdtime); if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello Holdtime option for interface %s", __PRETTY_FUNCTION__, ifname); } return -1; } /* LAN Prune Delay */ tmp = pim_tlv_append_2uint16(curr, pastend, PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY, propagation_delay, override_interval); if (!tmp) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s", __PRETTY_FUNCTION__, ifname); } return -1; } if (can_disable_join_suppression) { *((uint8_t*)(curr) + 4) |= 0x80; /* enable T bit */ } curr = tmp; /* DR Priority */ curr = pim_tlv_append_uint32(curr, pastend, PIM_MSG_OPTION_TYPE_DR_PRIORITY, dr_priority); if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello DR Priority option for interface %s", __PRETTY_FUNCTION__, ifname); } return -2; } /* Generation ID */ curr = pim_tlv_append_uint32(curr, pastend, PIM_MSG_OPTION_TYPE_GENERATION_ID, generation_id); if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello Generation ID option for interface %s", __PRETTY_FUNCTION__, ifname); } return -3; } /* Secondary Address List */ if (ifconnected) { curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifconnected); if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s", __PRETTY_FUNCTION__, ifname); } return -4; } } return curr - tlv_buf; } /* RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ void pim_hello_require(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); if (pim_ifp->pim_ifstat_hello_sent) return; pim_hello_restart_now(ifp); /* Send hello and restart timer */ } quagga-1.2.4/pimd/pim_hello.h000066400000000000000000000025541325323223500160430ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_HELLO_H #define PIM_HELLO_H #include #include "if.h" int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); int pim_hello_build_tlv(const char *ifname, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, uint16_t propagation_delay, uint16_t override_interval, int can_disable_join_suppression, struct list *ifconnected); void pim_hello_require(struct interface *ifp); #endif /* PIM_HELLO_H */ quagga-1.2.4/pimd/pim_iface.c000066400000000000000000000727041325323223500160060ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "if.h" #include "log.h" #include "vty.h" #include "memory.h" #include "prefix.h" #include "pimd.h" #include "pim_iface.h" #include "pim_igmp.h" #include "pim_mroute.h" #include "pim_oil.h" #include "pim_str.h" #include "pim_pim.h" #include "pim_neighbor.h" #include "pim_ifchannel.h" #include "pim_sock.h" #include "pim_time.h" #include "pim_ssmpingd.h" static void pim_if_igmp_join_del_all(struct interface *ifp); static void *if_list_clean(struct pim_interface *pim_ifp) { if (pim_ifp->igmp_join_list) { list_delete(pim_ifp->igmp_join_list); } if (pim_ifp->igmp_socket_list) { list_delete(pim_ifp->igmp_socket_list); } if (pim_ifp->pim_neighbor_list) { list_delete(pim_ifp->pim_neighbor_list); } if (pim_ifp->pim_ifchannel_list) { list_delete(pim_ifp->pim_ifchannel_list); } XFREE(MTYPE_PIM_INTERFACE, pim_ifp); return 0; } struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) { struct pim_interface *pim_ifp; zassert(ifp); zassert(!ifp->info); pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp)); if (!pim_ifp) { zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp)); return 0; } pim_ifp->options = 0; pim_ifp->mroute_vif_index = -1; pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC; /* RFC 3376: 8.3. Query Response Interval The number of seconds represented by the [Query Response Interval] must be less than the [Query Interval]. */ zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval); if (pim) PIM_IF_DO_PIM(pim_ifp->options); if (igmp) PIM_IF_DO_IGMP(pim_ifp->options); #if 0 /* FIXME: Should join? */ PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options); #endif pim_ifp->igmp_join_list = 0; pim_ifp->igmp_socket_list = 0; pim_ifp->pim_neighbor_list = 0; pim_ifp->pim_ifchannel_list = 0; pim_ifp->pim_generation_id = 0; /* list of struct igmp_sock */ pim_ifp->igmp_socket_list = list_new(); if (!pim_ifp->igmp_socket_list) { zlog_err("%s %s: failure: igmp_socket_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free; /* list of struct pim_neighbor */ pim_ifp->pim_neighbor_list = list_new(); if (!pim_ifp->pim_neighbor_list) { zlog_err("%s %s: failure: pim_neighbor_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free; /* list of struct pim_ifchannel */ pim_ifp->pim_ifchannel_list = list_new(); if (!pim_ifp->pim_ifchannel_list) { zlog_err("%s %s: failure: pim_ifchannel_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free; ifp->info = pim_ifp; pim_sock_reset(ifp); zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options)); if (PIM_MROUTE_IS_ENABLED) { pim_if_add_vif(ifp); } return pim_ifp; } void pim_if_delete(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); if (pim_ifp->igmp_join_list) { pim_if_igmp_join_del_all(ifp); } zassert(!pim_ifp->igmp_join_list); zassert(pim_ifp->igmp_socket_list); zassert(!listcount(pim_ifp->igmp_socket_list)); zassert(pim_ifp->pim_neighbor_list); zassert(!listcount(pim_ifp->pim_neighbor_list)); zassert(pim_ifp->pim_ifchannel_list); zassert(!listcount(pim_ifp->pim_ifchannel_list)); if (PIM_MROUTE_IS_ENABLED) { pim_if_del_vif(ifp); } list_delete(pim_ifp->igmp_socket_list); list_delete(pim_ifp->pim_neighbor_list); list_delete(pim_ifp->pim_ifchannel_list); XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = 0; } void pim_if_update_could_assert(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { pim_ifchannel_update_could_assert(ch); } } static void pim_if_update_my_assert_metric(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { pim_ifchannel_update_my_assert_metric(ch); } } static void pim_addr_change(struct interface *ifp) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(pim_ifp); pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */ pim_if_update_join_desired(pim_ifp); /* depends on DR */ pim_if_update_could_assert(ifp); /* depends on DR */ pim_if_update_my_assert_metric(ifp); /* depends on could_assert */ pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */ /* RFC 4601: 4.3.1. Sending Hello Messages 1) Before an interface goes down or changes primary IP address, a Hello message with a zero HoldTime should be sent immediately (with the old IP address if the IP address changed). -- FIXME See CAVEAT C13 2) After an interface has changed its IP address, it MUST send a Hello message with its new IP address. -- DONE below 3) If an interface changes one of its secondary IP addresses, a Hello message with an updated Address_List option and a non-zero HoldTime should be sent immediately. -- FIXME See TODO T31 */ pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */ if (pim_ifp->pim_sock_fd < 0) return; pim_hello_restart_now(ifp); /* send hello and restart timer */ } static int detect_primary_address_change(struct interface *ifp, int force_prim_as_any, const char *caller) { struct pim_interface *pim_ifp; struct in_addr new_prim_addr; int changed; pim_ifp = ifp->info; if (!pim_ifp) return 0; if (force_prim_as_any) new_prim_addr = qpim_inaddr_any; else new_prim_addr = pim_find_primary_addr(ifp); changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr; if (PIM_DEBUG_ZEBRA) { char new_prim_str[100]; char old_prim_str[100]; pim_inet4_dump("", new_prim_addr, new_prim_str, sizeof(new_prim_str)); pim_inet4_dump("", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str)); zlog_debug("%s: old=%s new=%s on interface %s: %s", __PRETTY_FUNCTION__, old_prim_str, new_prim_str, ifp->name, changed ? "changed" : "unchanged"); } if (changed) { pim_ifp->primary_address = new_prim_addr; if (!PIM_IF_TEST_PIM(pim_ifp->options)) { return changed; } pim_addr_change(ifp); } return changed; } static void detect_secondary_address_change(struct interface *ifp, const char *caller) { struct pim_interface *pim_ifp; int changed; pim_ifp = ifp->info; if (!pim_ifp) return; changed = 1; /* true */ if (PIM_DEBUG_ZEBRA) zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change", __PRETTY_FUNCTION__, ifp->name); if (!changed) { return; } if (!PIM_IF_TEST_PIM(pim_ifp->options)) { return; } pim_addr_change(ifp); } static void detect_address_change(struct interface *ifp, int force_prim_as_any, const char *caller) { int prim_changed; prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller); if (prim_changed) { /* no need to detect secondary change because the reaction would be the same */ return; } detect_secondary_address_change(ifp, caller); } void pim_if_addr_add(struct connected *ifc) { struct pim_interface *pim_ifp; struct interface *ifp; struct in_addr ifaddr; zassert(ifc); ifp = ifc->ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) return; if (!if_is_operative(ifp)) return; if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d connected IP address %s %s", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, buf, CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } ifaddr = ifc->address->u.prefix4; detect_address_change(ifp, 0, __PRETTY_FUNCTION__); if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct igmp_sock *igmp; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr); if (!igmp) { /* if addr new, add IGMP socket */ pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp); } } /* igmp */ if (PIM_IF_TEST_PIM(pim_ifp->options)) { /* Interface has a valid primary address ? */ if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { /* Interface has a valid socket ? */ if (pim_ifp->pim_sock_fd < 0) { if (pim_sock_add(ifp)) { zlog_warn("Failure creating PIM socket for interface %s", ifp->name); } } } } /* pim */ if (PIM_MROUTE_IS_ENABLED) { /* PIM or IGMP is enabled on interface, and there is at least one address assigned, then try to create a vif_index. */ if (pim_ifp->mroute_vif_index < 0) { pim_if_add_vif(ifp); } } } static void pim_if_addr_del_igmp(struct connected *ifc) { struct pim_interface *pim_ifp = ifc->ifp->info; struct igmp_sock *igmp; struct in_addr ifaddr; if (ifc->address->family != AF_INET) { /* non-IPv4 address */ return; } if (!pim_ifp) { /* IGMP not enabled on interface */ return; } ifaddr = ifc->address->u.prefix4; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr); if (igmp) { /* if addr found, del IGMP socket */ igmp_sock_delete(igmp); } } static void pim_if_addr_del_pim(struct connected *ifc) { struct pim_interface *pim_ifp = ifc->ifp->info; if (ifc->address->family != AF_INET) { /* non-IPv4 address */ return; } if (!pim_ifp) { /* PIM not enabled on interface */ return; } if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { /* Interface keeps a valid primary address */ return; } if (pim_ifp->pim_sock_fd < 0) { /* Interface does not hold a valid socket any longer */ return; } /* pim_sock_delete() closes the socket, stops read and timer threads, and kills all neighbors. */ pim_sock_delete(ifc->ifp, "last address has been removed from interface"); } void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) { struct interface *ifp; zassert(ifc); ifp = ifc->ifp; zassert(ifp); if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, buf, CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__); pim_if_addr_del_igmp(ifc); pim_if_addr_del_pim(ifc); } void pim_if_addr_add_all(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; pim_if_addr_add(ifc); } } void pim_if_addr_del_all(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */); } } void pim_if_addr_del_all_igmp(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; pim_if_addr_del_igmp(ifc); } } void pim_if_addr_del_all_pim(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; pim_if_addr_del_pim(ifc); } } static struct in_addr find_first_nonsec_addr(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct in_addr addr; for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; if (PIM_INADDR_IS_ANY(p->u.prefix4)) { zlog_warn("%s: null IPv4 address connected to interface %s", __PRETTY_FUNCTION__, ifp->name); continue; } if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) continue; return p->u.prefix4; } addr.s_addr = PIM_NET_INADDR_ANY; return addr; } struct in_addr pim_find_primary_addr(struct interface *ifp) { return find_first_nonsec_addr(ifp); } /* pim_if_add_vif() uses ifindex as vif_index see also pim_if_find_vifindex_by_ifindex() */ int pim_if_add_vif(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct in_addr ifaddr; zassert(pim_ifp); if (pim_ifp->mroute_vif_index > 0) { zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d", __PRETTY_FUNCTION__, pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex); return -1; } if (ifp->ifindex < 1) { zlog_warn("%s: ifindex=%d < 1 on interface %s", __PRETTY_FUNCTION__, ifp->ifindex, ifp->name); return -2; } if (ifp->ifindex >= MAXVIFS) { zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s", __PRETTY_FUNCTION__, ifp->ifindex, MAXVIFS, ifp->name); return -3; } ifaddr = pim_ifp->primary_address; if (PIM_INADDR_IS_ANY(ifaddr)) { zlog_warn("%s: could not get address for interface %s ifindex=%d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex); return -4; } if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) { /* pim_mroute_add_vif reported error */ return -5; } pim_ifp->mroute_vif_index = ifp->ifindex; /* Update highest vif_index */ if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) { qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index; } return 0; } static int iflist_find_highest_vif_index() { struct listnode *ifnode; struct interface *ifp; struct pim_interface *pim_ifp; int highest_vif_index = -1; for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->mroute_vif_index > highest_vif_index) { highest_vif_index = pim_ifp->mroute_vif_index; } } return highest_vif_index; } int pim_if_del_vif(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; int old_vif_index; if (pim_ifp->mroute_vif_index < 1) { zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d", __PRETTY_FUNCTION__, pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex); return -1; } if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) { /* pim_mroute_del_vif reported error */ return -2; } /* Update highest vif_index */ /* save old vif_index in order to compare with highest below */ old_vif_index = pim_ifp->mroute_vif_index; pim_ifp->mroute_vif_index = -1; if (old_vif_index == qpim_mroute_oif_highest_vif_index) { qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index(); } return 0; } void pim_if_add_vif_all() { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { if (!ifp->info) continue; pim_if_add_vif(ifp); } } void pim_if_del_vif_all() { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { if (!ifp->info) continue; pim_if_del_vif(ifp); } } struct interface *pim_if_find_by_vif_index(int vif_index) { struct listnode *ifnode; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { if (ifp->info) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; if (vif_index == pim_ifp->mroute_vif_index) return ifp; } } return 0; } /* pim_if_add_vif() uses ifindex as vif_index */ int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex) { return ifindex; } int pim_if_lan_delay_enabled(struct interface *ifp) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(pim_ifp); zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0); return pim_ifp->pim_number_of_nonlandelay_neighbors == 0; } uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp) { if (pim_if_lan_delay_enabled(ifp)) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; return pim_ifp->pim_neighbors_highest_propagation_delay_msec; } else { return PIM_DEFAULT_PROPAGATION_DELAY_MSEC; } } uint16_t pim_if_effective_override_interval_msec(struct interface *ifp) { if (pim_if_lan_delay_enabled(ifp)) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; return pim_ifp->pim_neighbors_highest_override_interval_msec; } else { return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC; } } int pim_if_t_override_msec(struct interface *ifp) { int effective_override_interval_msec; int t_override_msec; effective_override_interval_msec = pim_if_effective_override_interval_msec(ifp); t_override_msec = random() % (effective_override_interval_msec + 1); return t_override_msec; } uint16_t pim_if_jp_override_interval_msec(struct interface *ifp) { return pim_if_effective_propagation_delay_msec(ifp) + pim_if_effective_override_interval_msec(ifp); } /* RFC 4601: 4.1.6. State Summarization Macros The function NBR( I, A ) uses information gathered through PIM Hello messages to map the IP address A of a directly connected PIM neighbor router on interface I to the primary IP address of the same router (Section 4.3.4). The primary IP address of a neighbor is the address that it uses as the source of its PIM Hello messages. */ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, struct in_addr addr) { struct listnode *neighnode; struct pim_neighbor *neigh; struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return 0; } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { /* primary address ? */ if (neigh->source_addr.s_addr == addr.s_addr) return neigh; /* secondary address ? */ if (pim_neighbor_find_secondary(neigh, addr)) return neigh; } if (PIM_DEBUG_PIM_TRACE) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: neighbor not found for address %s on interface %s", __PRETTY_FUNCTION__, addr_str, ifp->name); } return 0; } long pim_if_t_suppressed_msec(struct interface *ifp) { struct pim_interface *pim_ifp; long t_suppressed_msec; uint32_t ramount = 0; pim_ifp = ifp->info; zassert(pim_ifp); /* join suppression disabled ? */ if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)) return 0; /* t_suppressed = t_periodic * rand(1.1, 1.4) */ ramount = 1100 + (random() % (1400 - 1100 + 1)); t_suppressed_msec = qpim_t_periodic * ramount; return t_suppressed_msec; } static void igmp_join_free(struct igmp_join *ij) { XFREE(MTYPE_PIM_IGMP_JOIN, ij); } static struct igmp_join *igmp_join_find(struct list *join_list, struct in_addr group_addr, struct in_addr source_addr) { struct listnode *node; struct igmp_join *ij; zassert(join_list); for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) { if ((group_addr.s_addr == ij->group_addr.s_addr) && (source_addr.s_addr == ij->source_addr.s_addr)) return ij; } return 0; } static int igmp_join_sock(const char *ifname, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr) { int join_fd; join_fd = pim_socket_raw(IPPROTO_IGMP); if (join_fd < 0) { return -1; } if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) { close(join_fd); return -2; } return join_fd; } static struct igmp_join *igmp_join_new(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct igmp_join *ij; int join_fd; pim_ifp = ifp->info; zassert(pim_ifp); join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr); if (join_fd < 0) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return 0; } ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij)); if (!ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, sizeof(*ij), group_str, source_str, ifp->name); close(join_fd); return 0; } ij->sock_fd = join_fd; ij->group_addr = group_addr; ij->source_addr = source_addr; ij->sock_creation = pim_time_monotonic_sec(); listnode_add(pim_ifp->igmp_join_list, ij); return ij; } int pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct igmp_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (!pim_ifp->igmp_join_list) { pim_ifp->igmp_join_list = list_new(); if (!pim_ifp->igmp_join_list) { zlog_err("%s %s: failure: igmp_join_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return -2; } pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free; } ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); if (ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return -3; } ij = igmp_join_new(ifp, group_addr, source_addr); if (!ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return -4; } if (PIM_DEBUG_IGMP_EVENTS) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ifp->name); } return 0; } int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct igmp_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (!pim_ifp->igmp_join_list) { zlog_warn("%s: no IGMP join on interface %s", __PRETTY_FUNCTION__, ifp->name); return -2; } ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); if (!ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: could not find IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return -3; } if (close(ij->sock_fd)) { int e = errno; char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s", __PRETTY_FUNCTION__, ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e)); /* warning only */ } listnode_delete(pim_ifp->igmp_join_list, ij); igmp_join_free(ij); if (listcount(pim_ifp->igmp_join_list) < 1) { list_delete(pim_ifp->igmp_join_list); pim_ifp->igmp_join_list = 0; } return 0; } static void pim_if_igmp_join_del_all(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *nextnode; struct igmp_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return; } if (!pim_ifp->igmp_join_list) return; for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij)) pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr); } /* RFC 4601 Transitions from "I am Assert Loser" State Current Winner's GenID Changes or NLT Expires The Neighbor Liveness Timer associated with the current winner expires or we receive a Hello message from the current winner reporting a different GenID from the one it previously reported. This indicates that the current winner's interface or router has gone down (and may have come back up), and so we must assume it no longer knows it was the winner. */ void pim_if_assert_on_neighbor_down(struct interface *ifp, struct in_addr neigh_addr) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { /* Is (S,G,I) assert loser ? */ if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) continue; /* Dead neighbor was winner ? */ if (ch->ifassert_winner.s_addr != neigh_addr.s_addr) continue; assert_action_a5(ch); } } void pim_if_update_join_desired(struct pim_interface *pim_ifp) { struct listnode *ch_node; struct pim_ifchannel *ch; /* clear off flag from interface's upstreams */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags); } /* scan per-interface (S,G,I) state on this I interface */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { struct pim_upstream *up = ch->upstream; if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags)) continue; /* update join_desired for the global (S,G) state */ pim_upstream_update_join_desired(up); PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags); } } void pim_if_update_assert_tracking_desired(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) return; for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { pim_ifchannel_update_assert_tracking_desired(ch); } } quagga-1.2.4/pimd/pim_iface.h000066400000000000000000000151431325323223500160050ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IFACE_H #define PIM_IFACE_H #include #include "if.h" #include "vty.h" #include "pim_igmp.h" #include "pim_upstream.h" #define PIM_IF_MASK_PIM (1 << 0) #define PIM_IF_MASK_IGMP (1 << 1) #define PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS (1 << 2) #define PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION (1 << 3) #define PIM_IF_IS_DELETED(ifp) ((ifp)->ifindex == IFINDEX_INTERNAL) #define PIM_IF_TEST_PIM(options) (PIM_IF_MASK_PIM & (options)) #define PIM_IF_TEST_IGMP(options) (PIM_IF_MASK_IGMP & (options)) #define PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(options) (PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS & (options)) #define PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) (PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION & (options)) #define PIM_IF_DO_PIM(options) ((options) |= PIM_IF_MASK_PIM) #define PIM_IF_DO_IGMP(options) ((options) |= PIM_IF_MASK_IGMP) #define PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(options) ((options) |= PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS) #define PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) ((options) |= PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION) #define PIM_IF_DONT_PIM(options) ((options) &= ~PIM_IF_MASK_PIM) #define PIM_IF_DONT_IGMP(options) ((options) &= ~PIM_IF_MASK_IGMP) #define PIM_IF_DONT_IGMP_LISTEN_ALLROUTERS(options) ((options) &= ~PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS) #define PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) ((options) &= ~PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION) struct pim_interface { uint32_t options; /* bit vector */ int mroute_vif_index; struct in_addr primary_address; /* remember addr to detect change */ int igmp_default_robustness_variable; /* IGMPv3 QRV */ int igmp_default_query_interval; /* IGMPv3 secs between general queries */ int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for general queries */ int igmp_specific_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for specific queries */ struct list *igmp_socket_list; /* list of struct igmp_sock */ struct list *igmp_join_list; /* list of struct igmp_join */ int pim_sock_fd; /* PIM socket file descriptor */ struct thread *t_pim_sock_read; /* thread for reading PIM socket */ int64_t pim_sock_creation; /* timestamp of PIM socket creation */ struct thread *t_pim_hello_timer; int pim_hello_period; int pim_default_holdtime; int pim_triggered_hello_delay; uint32_t pim_generation_id; uint16_t pim_propagation_delay_msec; /* config */ uint16_t pim_override_interval_msec; /* config */ struct list *pim_neighbor_list; /* list of struct pim_neighbor */ struct list *pim_ifchannel_list; /* list of struct pim_ifchannel */ /* neighbors without lan_delay */ int pim_number_of_nonlandelay_neighbors; uint16_t pim_neighbors_highest_propagation_delay_msec; uint16_t pim_neighbors_highest_override_interval_msec; /* DR Election */ int64_t pim_dr_election_last; /* timestamp */ int pim_dr_election_count; int pim_dr_election_changes; struct in_addr pim_dr_addr; uint32_t pim_dr_priority; /* config */ int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ int64_t pim_ifstat_start; /* start timestamp for stats */ uint32_t pim_ifstat_hello_sent; uint32_t pim_ifstat_hello_sendfail; uint32_t pim_ifstat_hello_recv; uint32_t pim_ifstat_hello_recvfail; }; /* if default_holdtime is set (>= 0), use it; otherwise default_holdtime is 3.5 * hello_period */ #define PIM_IF_DEFAULT_HOLDTIME(pim_ifp) \ (((pim_ifp)->pim_default_holdtime < 0) ? \ ((pim_ifp)->pim_hello_period * 7 / 2) : \ ((pim_ifp)->pim_default_holdtime)) struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim); void pim_if_delete(struct interface *ifp); void pim_if_addr_add(struct connected *ifc); void pim_if_addr_del(struct connected *ifc, int force_prim_as_any); void pim_if_addr_add_all(struct interface *ifp); void pim_if_addr_del_all(struct interface *ifp); void pim_if_addr_del_all_igmp(struct interface *ifp); void pim_if_addr_del_all_pim(struct interface *ifp); int pim_if_add_vif(struct interface *ifp); int pim_if_del_vif(struct interface *ifp); void pim_if_add_vif_all(void); void pim_if_del_vif_all(void); struct interface *pim_if_find_by_vif_index(ifindex_t vif_index); int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex); int pim_if_lan_delay_enabled(struct interface *ifp); uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp); uint16_t pim_if_effective_override_interval_msec(struct interface *ifp); uint16_t pim_if_jp_override_interval_msec(struct interface *ifp); struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, struct in_addr addr); long pim_if_t_suppressed_msec(struct interface *ifp); int pim_if_t_override_msec(struct interface *ifp); struct in_addr pim_find_primary_addr(struct interface *ifp); int pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr); int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr); void pim_if_update_could_assert(struct interface *ifp); void pim_if_assert_on_neighbor_down(struct interface *ifp, struct in_addr neigh_addr); void pim_if_rpf_interface_changed(struct interface *old_rpf_ifp, struct pim_upstream *up); void pim_if_update_join_desired(struct pim_interface *pim_ifp); void pim_if_update_assert_tracking_desired(struct interface *ifp); #endif /* PIM_IFACE_H */ quagga-1.2.4/pimd/pim_ifchannel.c000066400000000000000000000605561325323223500166700ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "linklist.h" #include "thread.h" #include "memory.h" #include "pimd.h" #include "pim_str.h" #include "pim_iface.h" #include "pim_ifchannel.h" #include "pim_zebra.h" #include "pim_time.h" #include "pim_msg.h" #include "pim_pim.h" #include "pim_join.h" #include "pim_rpf.h" #include "pim_macro.h" void pim_ifchannel_free(struct pim_ifchannel *ch) { zassert(!ch->t_ifjoin_expiry_timer); zassert(!ch->t_ifjoin_prune_pending_timer); zassert(!ch->t_ifassert_timer); XFREE(MTYPE_PIM_IFCHANNEL, ch); } void pim_ifchannel_delete(struct pim_ifchannel *ch) { struct pim_interface *pim_ifp; pim_ifp = ch->interface->info; zassert(pim_ifp); if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) { pim_upstream_update_join_desired(ch->upstream); } pim_upstream_del(ch->upstream); THREAD_OFF(ch->t_ifjoin_expiry_timer); THREAD_OFF(ch->t_ifjoin_prune_pending_timer); THREAD_OFF(ch->t_ifassert_timer); /* notice that listnode_delete() can't be moved into pim_ifchannel_free() because the later is called by list_delete_all_node() */ listnode_delete(pim_ifp->pim_ifchannel_list, ch); pim_ifchannel_free(ch); } #define IFCHANNEL_NOINFO(ch) \ ( \ ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \ && \ ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \ && \ ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \ ) static void delete_on_noinfo(struct pim_ifchannel *ch) { if (IFCHANNEL_NOINFO(ch)) { /* In NOINFO state, timers should have been cleared */ zassert(!ch->t_ifjoin_expiry_timer); zassert(!ch->t_ifjoin_prune_pending_timer); zassert(!ch->t_ifassert_timer); pim_ifchannel_delete(ch); } } void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, enum pim_ifjoin_state new_state) { enum pim_ifjoin_state old_state = ch->ifjoin_state; if (old_state == new_state) { if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("%s calledby %s: non-transition on state %d (%s)", __PRETTY_FUNCTION__, caller, new_state, pim_ifchannel_ifjoin_name(new_state)); } return; } zassert(old_state != new_state); ch->ifjoin_state = new_state; /* Transition to/from NOINFO ? */ if ( (old_state == PIM_IFJOIN_NOINFO) || (new_state == PIM_IFJOIN_NOINFO) ) { if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s", ((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"), src_str, grp_str, ch->interface->name); } /* Record uptime of state transition to/from NOINFO */ ch->ifjoin_creation = pim_time_monotonic_sec(); pim_upstream_update_join_desired(ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } } const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state) { switch (ifjoin_state) { case PIM_IFJOIN_NOINFO: return "NOINFO"; case PIM_IFJOIN_JOIN: return "JOIN"; case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP"; } return "ifjoin_bad_state"; } const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state) { switch (ifassert_state) { case PIM_IFASSERT_NOINFO: return "NOINFO"; case PIM_IFASSERT_I_AM_WINNER: return "WINNER"; case PIM_IFASSERT_I_AM_LOSER: return "LOSER"; } return "ifassert_bad_state"; } /* RFC 4601: 4.6.5. Assert State Macros AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I) defaults to Infinity when in the NoInfo state. */ void reset_ifassert_state(struct pim_ifchannel *ch) { THREAD_OFF(ch->t_ifassert_timer); pim_ifassert_winner_set(ch, PIM_IFASSERT_NOINFO, qpim_inaddr_any, qpim_infinite_assert_metric); } static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; struct pim_upstream *up; pim_ifp = ifp->info; zassert(pim_ifp); up = pim_upstream_add(source_addr, group_addr); if (!up) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return 0; } ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch)); if (!ch) { zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*ch)); return 0; } ch->flags = 0; ch->upstream = up; ch->interface = ifp; ch->source_addr = source_addr; ch->group_addr = group_addr; ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO; ch->ifjoin_state = PIM_IFJOIN_NOINFO; ch->t_ifjoin_expiry_timer = 0; ch->t_ifjoin_prune_pending_timer = 0; ch->ifjoin_creation = 0; ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch); ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval (ch); ch->ifassert_winner.s_addr = 0; /* Assert state */ ch->t_ifassert_timer = 0; reset_ifassert_state(ch); if (pim_macro_ch_could_assert_eval(ch)) PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags); else PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags); if (pim_macro_assert_tracking_desired_eval(ch)) PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags); else PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags); /* Attach to list */ listnode_add(pim_ifp->pim_ifchannel_list, ch); zassert(IFCHANNEL_NOINFO(ch)); return ch; } struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_interface *pim_ifp; struct listnode *ch_node; struct pim_ifchannel *ch; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return 0; } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { if ( (source_addr.s_addr == ch->source_addr.s_addr) && (group_addr.s_addr == ch->group_addr.s_addr) ) { return ch; } } return 0; } static void ifmembership_set(struct pim_ifchannel *ch, enum pim_ifmembership membership) { if (ch->local_ifmembership == membership) return; if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO", ch->interface->name); } ch->local_ifmembership = membership; pim_upstream_update_join_desired(ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } void pim_ifchannel_membership_clear(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); } } void pim_ifchannel_delete_on_noinfo(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { delete_on_noinfo(ch); } } struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_ifchannel *ch; char src_str[100]; char grp_str[100]; ch = pim_ifchannel_find(ifp, source_addr, group_addr); if (ch) return ch; ch = pim_ifchannel_new(ifp, source_addr, group_addr); if (ch) return ch; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return 0; } static void ifjoin_to_noinfo(struct pim_ifchannel *ch) { pim_forward_stop(ch); pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO); delete_on_noinfo(ch); } static int on_ifjoin_expiry_timer(struct thread *t) { struct pim_ifchannel *ch; zassert(t); ch = THREAD_ARG(t); zassert(ch); ch->t_ifjoin_expiry_timer = 0; zassert(ch->ifjoin_state == PIM_IFJOIN_JOIN); ifjoin_to_noinfo(ch); /* ch may have been deleted */ return 0; } static void prune_echo(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_interface *pim_ifp; struct in_addr neigh_dst_addr; pim_ifp = ifp->info; zassert(pim_ifp); neigh_dst_addr = pim_ifp->primary_address; if (PIM_DEBUG_PIM_EVENTS) { char source_str[100]; char group_str[100]; char neigh_dst_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", neigh_dst_addr, neigh_dst_str, sizeof(neigh_dst_str)); zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s", __PRETTY_FUNCTION__, source_str, group_str, neigh_dst_str, ifp->name); } pim_joinprune_send(ifp, neigh_dst_addr, source_addr, group_addr, 0 /* boolean: send_join=false (prune) */); } static int on_ifjoin_prune_pending_timer(struct thread *t) { struct pim_ifchannel *ch; int send_prune_echo; /* boolean */ struct interface *ifp; struct pim_interface *pim_ifp; struct in_addr ch_source; struct in_addr ch_group; zassert(t); ch = THREAD_ARG(t); zassert(ch); ch->t_ifjoin_prune_pending_timer = 0; zassert(ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING); /* Send PruneEcho(S,G) ? */ ifp = ch->interface; pim_ifp = ifp->info; send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1); /* Save (S,G) */ ch_source = ch->source_addr; ch_group = ch->group_addr; ifjoin_to_noinfo(ch); /* from here ch may have been deleted */ if (send_prune_echo) prune_echo(ifp, ch_source, ch_group); return 0; } static void check_recv_upstream(int is_join, struct interface *recv_ifp, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, int holdtime) { struct pim_upstream *up; /* Upstream (S,G) in Joined state ? */ up = pim_upstream_find(source_addr, group_addr); if (!up) return; if (up->join_state != PIM_UPSTREAM_JOINED) return; /* Upstream (S,G) in Joined state */ if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) { /* RPF'(S,G) not found */ char src_str[100]; char grp_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s %s: RPF'(%s,%s) not found", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str); return; } /* upstream directed to RPF'(S,G) ? */ if (upstream.s_addr != up->rpf.rpf_addr.s_addr) { char src_str[100]; char grp_str[100]; char up_str[100]; char rpf_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", upstream, up_str, sizeof(up_str)); pim_inet4_dump("", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, up_str, rpf_str, recv_ifp->name); return; } /* upstream directed to RPF'(S,G) */ if (is_join) { /* Join(S,G) to RPF'(S,G) */ pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime); return; } /* Prune to RPF'(S,G) */ if (source_flags & PIM_RPT_BIT_MASK) { if (source_flags & PIM_WILDCARD_BIT_MASK) { /* Prune(*,G) to RPF'(S,G) */ pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)", up, up->rpf.rpf_addr); return; } /* Prune(S,G,rpt) to RPF'(S,G) */ pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)", up, up->rpf.rpf_addr); return; } /* Prune(S,G) to RPF'(S,G) */ pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up, up->rpf.rpf_addr); } static int nonlocal_upstream(int is_join, struct interface *recv_ifp, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *recv_pim_ifp; int is_local; /* boolean */ recv_pim_ifp = recv_ifp->info; zassert(recv_pim_ifp); is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr); if (PIM_DEBUG_PIM_TRACE) { char up_str[100]; char src_str[100]; char grp_str[100]; pim_inet4_dump("", upstream, up_str, sizeof(up_str)); pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s", __PRETTY_FUNCTION__, is_join ? "join" : "prune", src_str, grp_str, is_local ? "local" : "non-local", up_str, recv_ifp->name); } if (is_local) return 0; /* Since recv upstream addr was not directed to our primary address, check if we should react to it in any way. */ check_recv_upstream(is_join, recv_ifp, upstream, source_addr, group_addr, source_flags, holdtime); return 1; /* non-local */ } void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; if (nonlocal_upstream(1 /* join */, ifp, upstream, source_addr, group_addr, source_flags, holdtime)) { return; } ch = pim_ifchannel_add(ifp, source_addr, group_addr); if (!ch) return; /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine Transitions from "I am Assert Loser" State Receive Join(S,G) on Interface I We receive a Join(S,G) that has the Upstream Neighbor Address field set to my primary IP address on interface I. The action is to transition to NoInfo state, delete this (S,G) assert state (Actions A5 below), and allow the normal PIM Join/Prune mechanisms to operate. Notice: The nonlocal_upstream() test above ensures the upstream address of the join message is our primary address. */ if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { char src_str[100]; char grp_str[100]; char neigh_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", neigh_addr, neigh_str, sizeof(neigh_str)); zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s", __PRETTY_FUNCTION__, src_str, grp_str, neigh_str, ifp->name); assert_action_a5(ch); } pim_ifp = ifp->info; zassert(pim_ifp); switch (ch->ifjoin_state) { case PIM_IFJOIN_NOINFO: pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN); if (pim_macro_chisin_oiflist(ch)) { pim_forward_start(ch); } break; case PIM_IFJOIN_JOIN: zassert(!ch->t_ifjoin_prune_pending_timer); /* In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a previously received join message with holdtime=0xFFFF. */ if (ch->t_ifjoin_expiry_timer) { unsigned long remain = thread_timer_remain_second(ch->t_ifjoin_expiry_timer); if (remain > holdtime) { /* RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages Transitions from Join State The (S,G) downstream state machine on interface I remains in Join state, and the Expiry Timer (ET) is restarted, set to maximum of its current value and the HoldTime from the triggering Join/Prune message. Conclusion: Do not change the ET if the current value is higher than the received join holdtime. */ return; } } THREAD_OFF(ch->t_ifjoin_expiry_timer); break; case PIM_IFJOIN_PRUNE_PENDING: zassert(!ch->t_ifjoin_expiry_timer); zassert(ch->t_ifjoin_prune_pending_timer); THREAD_OFF(ch->t_ifjoin_prune_pending_timer); pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN); break; } zassert(!IFCHANNEL_NOINFO(ch)); if (holdtime != 0xFFFF) { THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer, on_ifjoin_expiry_timer, ch, holdtime); } } void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime) { struct pim_ifchannel *ch; int jp_override_interval_msec; if (nonlocal_upstream(0 /* prune */, ifp, upstream, source_addr, group_addr, source_flags, holdtime)) { return; } ch = pim_ifchannel_add(ifp, source_addr, group_addr); if (!ch) return; switch (ch->ifjoin_state) { case PIM_IFJOIN_NOINFO: case PIM_IFJOIN_PRUNE_PENDING: /* nothing to do */ break; case PIM_IFJOIN_JOIN: { struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(ch->t_ifjoin_expiry_timer); zassert(!ch->t_ifjoin_prune_pending_timer); THREAD_OFF(ch->t_ifjoin_expiry_timer); pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING); if (listcount(pim_ifp->pim_neighbor_list) > 1) { jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp); } else { jp_override_interval_msec = 0; /* schedule to expire immediately */ /* If we called ifjoin_prune() directly instead, care should be taken not to use "ch" afterwards since it would be deleted. */ } THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer, on_ifjoin_prune_pending_timer, ch, jp_override_interval_msec); zassert(!ch->t_ifjoin_expiry_timer); zassert(ch->t_ifjoin_prune_pending_timer); } break; } } void pim_ifchannel_local_membership_add(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; /* PIM enabled on interface? */ pim_ifp = ifp->info; if (!pim_ifp) return; if (!PIM_IF_TEST_PIM(pim_ifp->options)) return; ch = pim_ifchannel_add(ifp, source_addr, group_addr); if (!ch) { return; } ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE); zassert(!IFCHANNEL_NOINFO(ch)); } void pim_ifchannel_local_membership_del(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; /* PIM enabled on interface? */ pim_ifp = ifp->info; if (!pim_ifp) return; if (!PIM_IF_TEST_PIM(pim_ifp->options)) return; ch = pim_ifchannel_find(ifp, source_addr, group_addr); if (!ch) return; ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); delete_on_noinfo(ch); } void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch) { int old_couldassert = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)); int new_couldassert = PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch)); if (new_couldassert == old_couldassert) return; if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name, old_couldassert, new_couldassert); } if (new_couldassert) { /* CouldAssert(S,G,I) switched from FALSE to TRUE */ PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags); } else { /* CouldAssert(S,G,I) switched from TRUE to FALSE */ PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags); if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) { assert_action_a4(ch); } } pim_ifchannel_update_my_assert_metric(ch); } /* my_assert_metric may be affected by: CouldAssert(S,G) pim_ifp->primary_address rpf->source_nexthop.mrib_metric_preference; rpf->source_nexthop.mrib_route_metric; */ void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch) { struct pim_assert_metric my_metric_new = pim_macro_ch_my_assert_metric_eval(ch); if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric)) return; if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; char old_addr_str[100]; char new_addr_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str)); pim_inet4_dump("", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str)); zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name, ch->ifassert_my_metric.rpt_bit_flag, ch->ifassert_my_metric.metric_preference, ch->ifassert_my_metric.route_metric, old_addr_str, my_metric_new.rpt_bit_flag, my_metric_new.metric_preference, my_metric_new.route_metric, new_addr_str); } ch->ifassert_my_metric = my_metric_new; if (pim_assert_metric_better(&ch->ifassert_my_metric, &ch->ifassert_winner_metric)) { assert_action_a5(ch); } } void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch) { int old_atd = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)); int new_atd = PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch)); if (new_atd == old_atd) return; if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name, old_atd, new_atd); } if (new_atd) { /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */ PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags); } else { /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */ PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags); if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { assert_action_a5(ch); } } } quagga-1.2.4/pimd/pim_ifchannel.h000066400000000000000000000121721325323223500166640ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IFCHANNEL_H #define PIM_IFCHANNEL_H #include #include "if.h" #include "pim_upstream.h" enum pim_ifmembership { PIM_IFMEMBERSHIP_NOINFO, PIM_IFMEMBERSHIP_INCLUDE }; enum pim_ifjoin_state { PIM_IFJOIN_NOINFO, PIM_IFJOIN_JOIN, PIM_IFJOIN_PRUNE_PENDING }; enum pim_ifassert_state { PIM_IFASSERT_NOINFO, PIM_IFASSERT_I_AM_WINNER, PIM_IFASSERT_I_AM_LOSER }; struct pim_assert_metric { uint32_t rpt_bit_flag; uint32_t metric_preference; uint32_t route_metric; struct in_addr ip_address; /* neighbor router that sourced the Assert message */ }; /* Flag to detect change in CouldAssert(S,G,I) */ #define PIM_IF_FLAG_MASK_COULD_ASSERT (1 << 0) #define PIM_IF_FLAG_TEST_COULD_ASSERT(flags) ((flags) & PIM_IF_FLAG_MASK_COULD_ASSERT) #define PIM_IF_FLAG_SET_COULD_ASSERT(flags) ((flags) |= PIM_IF_FLAG_MASK_COULD_ASSERT) #define PIM_IF_FLAG_UNSET_COULD_ASSERT(flags) ((flags) &= ~PIM_IF_FLAG_MASK_COULD_ASSERT) /* Flag to detect change in AssertTrackingDesired(S,G,I) */ #define PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED (1 << 1) #define PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(flags) ((flags) & PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) #define PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(flags) ((flags) |= PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) #define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) ((flags) &= ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) /* Per-interface (S,G) state */ struct pim_ifchannel { struct in_addr source_addr; /* (S,G) source key */ struct in_addr group_addr; /* (S,G) group key */ struct interface *interface; /* backpointer to interface */ uint32_t flags; /* IGMPv3 determined interface has local members for (S,G) ? */ enum pim_ifmembership local_ifmembership; /* Per-interface (S,G) Join/Prune State (Section 4.1.4 of RFC4601) */ enum pim_ifjoin_state ifjoin_state; struct thread *t_ifjoin_expiry_timer; struct thread *t_ifjoin_prune_pending_timer; int64_t ifjoin_creation; /* Record uptime of ifjoin state */ /* Per-interface (S,G) Assert State (Section 4.6.1 of RFC4601) */ enum pim_ifassert_state ifassert_state; struct thread *t_ifassert_timer; struct in_addr ifassert_winner; struct pim_assert_metric ifassert_winner_metric; int64_t ifassert_creation; /* Record uptime of ifassert state */ struct pim_assert_metric ifassert_my_metric; /* Upstream (S,G) state */ struct pim_upstream *upstream; }; void pim_ifchannel_free(struct pim_ifchannel *ch); void pim_ifchannel_delete(struct pim_ifchannel *ch); void pim_ifchannel_membership_clear(struct interface *ifp); void pim_ifchannel_delete_on_noinfo(struct interface *ifp); struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr); struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr); void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime); void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime); void pim_ifchannel_local_membership_add(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr); void pim_ifchannel_local_membership_del(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr); void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, enum pim_ifjoin_state new_state); const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state); const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state); int pim_ifchannel_isin_oiflist(struct pim_ifchannel *ch); void reset_ifassert_state(struct pim_ifchannel *ch); void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch); void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch); void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch); #endif /* PIM_IFCHANNEL_H */ quagga-1.2.4/pimd/pim_igmp.c000066400000000000000000001217561325323223500156750ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "memory.h" #include "pimd.h" #include "pim_igmp.h" #include "pim_igmpv3.h" #include "pim_iface.h" #include "pim_sock.h" #include "pim_mroute.h" #include "pim_str.h" #include "pim_util.h" #include "pim_time.h" #include "pim_zebra.h" #define IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE (1) #define IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE (2) #define IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE (3) #define IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE (4) #define IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES (5) #define IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES (6) static void group_timer_off(struct igmp_group *group); static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr); static int igmp_sock_open(struct in_addr ifaddr, ifindex_t ifindex, uint32_t pim_options) { int fd; int join = 0; struct in_addr group; fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, 1 /* loop=true */); if (fd < 0) return -1; if (PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(pim_options)) { if (inet_aton(PIM_ALL_ROUTERS, &group)) { if (!pim_socket_join(fd, group, ifaddr, ifindex)) ++join; } else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), PIM_ALL_ROUTERS, errno, safe_strerror(errno)); } } /* IGMP routers periodically send IGMP general queries to AllSystems=224.0.0.1 IGMP routers must receive general queries for querier election. */ if (inet_aton(PIM_ALL_SYSTEMS, &group)) { if (!pim_socket_join(fd, group, ifaddr, ifindex)) ++join; } else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), PIM_ALL_SYSTEMS, errno, safe_strerror(errno)); } if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) { if (!pim_socket_join(fd, group, ifaddr, ifindex)) { ++join; } } else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), PIM_ALL_IGMP_ROUTERS, errno, safe_strerror(errno)); } if (!join) { zlog_err("IGMP socket fd=%d could not join any group on interface address %s", fd, inet_ntoa(ifaddr)); close(fd); fd = -1; } return fd; } #undef IGMP_SOCK_DUMP #ifdef IGMP_SOCK_DUMP static void igmp_sock_dump(array_t *igmp_sock_array) { int size = array_size(igmp_sock_array); int i; for (i = 0; i < size; ++i) { struct igmp_sock *igmp = array_get(igmp_sock_array, i); zlog_debug("%s %s: [%d/%d] igmp_addr=%s fd=%d", __FILE__, __PRETTY_FUNCTION__, i, size, inet_ntoa(igmp->ifaddr), igmp->fd); } } #endif struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, struct in_addr ifaddr) { struct listnode *sock_node; struct igmp_sock *igmp; #ifdef IGMP_SOCK_DUMP igmp_sock_dump(igmp_sock_list); #endif for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp)) if (ifaddr.s_addr == igmp->ifaddr.s_addr) return igmp; return 0; } struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd) { struct listnode *sock_node; struct igmp_sock *igmp; for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp)) if (fd == igmp->fd) return igmp; return 0; } static int pim_igmp_other_querier_expire(struct thread *t) { struct igmp_sock *igmp; zassert(t); igmp = THREAD_ARG(t); zassert(igmp); zassert(igmp->t_other_querier_timer); zassert(!igmp->t_igmp_query_timer); if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("%s: Querier %s resuming", __PRETTY_FUNCTION__, ifaddr_str); } igmp->t_other_querier_timer = 0; /* We are the current querier, then re-start sending general queries. */ pim_igmp_general_query_on(igmp); return 0; } void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp) { long other_querier_present_interval_msec; struct pim_interface *pim_ifp; zassert(igmp); zassert(igmp->interface); zassert(igmp->interface->info); pim_ifp = igmp->interface->info; if (igmp->t_other_querier_timer) { /* There is other querier present already, then reset the other-querier-present timer. */ if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("Querier %s resetting TIMER event for Other-Querier-Present", ifaddr_str); } THREAD_OFF(igmp->t_other_querier_timer); zassert(!igmp->t_other_querier_timer); } else { /* We are the current querier, then stop sending general queries: igmp->t_igmp_query_timer = 0; */ pim_igmp_general_query_off(igmp); } /* Since this socket is starting the other-querier-present timer, there should not be periodic query timer for this socket. */ zassert(!igmp->t_igmp_query_timer); /* RFC 3376: 8.5. Other Querier Present Interval The Other Querier Present Interval is the length of time that must pass before a multicast router decides that there is no longer another multicast router which should be the querier. This value MUST be ((the Robustness Variable) times (the Query Interval)) plus (one half of one Query Response Interval). other_querier_present_interval_msec = \ igmp->querier_robustness_variable * \ 1000 * igmp->querier_query_interval + \ 100 * (pim_ifp->query_max_response_time_dsec >> 1); */ other_querier_present_interval_msec = PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("Querier %s scheduling %ld.%03ld sec TIMER event for Other-Querier-Present", ifaddr_str, other_querier_present_interval_msec / 1000, other_querier_present_interval_msec % 1000); } THREAD_TIMER_MSEC_ON(master, igmp->t_other_querier_timer, pim_igmp_other_querier_expire, igmp, other_querier_present_interval_msec); } void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp) { zassert(igmp); if (PIM_DEBUG_IGMP_TRACE) { if (igmp->t_other_querier_timer) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("IGMP querier %s fd=%d cancelling other-querier-present TIMER event on %s", ifaddr_str, igmp->fd, igmp->interface->name); } } THREAD_OFF(igmp->t_other_querier_timer); zassert(!igmp->t_other_querier_timer); } static int recv_igmp_query(struct igmp_sock *igmp, int query_version, int max_resp_code, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp; struct pim_interface *pim_ifp; uint8_t resv_s_qrv = 0; uint8_t s_flag = 0; uint8_t qrv = 0; struct in_addr group_addr; uint16_t recv_checksum; uint16_t checksum; int i; //group_addr = *(struct in_addr *)(igmp_msg + 4); memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); ifp = igmp->interface; pim_ifp = ifp->info; recv_checksum = *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET); /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; checksum = in_cksum(igmp_msg, igmp_msg_len); if (checksum != recv_checksum) { zlog_warn("Recv IGMP query v%d from %s on %s: checksum mismatch: received=%x computed=%x", query_version, from_str, ifp->name, recv_checksum, checksum); return -1; } if (PIM_DEBUG_IGMP_PACKETS) { char group_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_debug("Recv IGMP query v%d from %s on %s: size=%d checksum=%x group=%s", query_version, from_str, ifp->name, igmp_msg_len, checksum, group_str); } /* RFC 3376: 6.6.2. Querier Election When a router receives a query with a lower IP address, it sets the Other-Querier-Present timer to Other Querier Present Interval and ceases to send queries on the network if it was the previously elected querier. */ if (ntohl(from.s_addr) < ntohl(igmp->ifaddr.s_addr)) { if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("%s: local address %s (%u) lost querier election to %s (%u)", ifp->name, ifaddr_str, ntohl(igmp->ifaddr.s_addr), from_str, ntohl(from.s_addr)); } pim_igmp_other_querier_timer_on(igmp); } if (query_version == 3) { /* RFC 3376: 4.1.6. QRV (Querier's Robustness Variable) Routers adopt the QRV value from the most recently received Query as their own [Robustness Variable] value, unless that most recently received QRV was zero, in which case the receivers use the default [Robustness Variable] value specified in section 8.1 or a statically configured value. */ resv_s_qrv = igmp_msg[8]; qrv = 7 & resv_s_qrv; igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable; } /* RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) Multicast routers that are not the current querier adopt the QQI value from the most recently received Query as their own [Query Interval] value, unless that most recently received QQI was zero, in which case the receiving routers use the default. */ if (igmp->t_other_querier_timer && query_version == 3) { /* other querier present */ uint8_t qqic; uint16_t qqi; qqic = igmp_msg[9]; qqi = igmp_msg_decode8to16(qqic); igmp->querier_query_interval = qqi ? qqi : pim_ifp->igmp_default_query_interval; if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("Querier %s new query interval is %s QQI=%u sec (recv QQIC=%02x from %s)", ifaddr_str, qqi ? "recv-non-default" : "default", igmp->querier_query_interval, qqic, from_str); } } /* RFC 3376: 6.6.1. Timer Updates When a router sends or receives a query with a clear Suppress Router-Side Processing flag, it must update its timers to reflect the correct timeout values for the group or sources being queried. General queries don't trigger timer update. */ if (query_version == 3) { s_flag = (1 << 3) & resv_s_qrv; } else { /* Neither V1 nor V2 have this field. Pimd should really go into * a compatibility mode here and run as V2 (or V1) but it doesn't * so for now, lets just set the flag to suppress these timer updates. */ s_flag = 1; } if (!s_flag) { /* s_flag is clear */ if (PIM_INADDR_IS_ANY(group_addr)) { /* this is a general query */ /* log that general query should have the s_flag set */ zlog_warn("General IGMP query v%d from %s on %s: Suppress Router-Side Processing flag is clear", query_version, from_str, ifp->name); } else { struct igmp_group *group; /* this is a non-general query: perform timer updates */ group = find_group_by_addr(igmp, group_addr); if (group) { int recv_num_sources = ntohs(*(uint16_t *)(igmp_msg + IGMP_V3_NUMSOURCES_OFFSET)); /* RFC 3376: 6.6.1. Timer Updates Query Q(G,A): Source Timer for sources in A are lowered to LMQT Query Q(G): Group Timer is lowered to LMQT */ if (recv_num_sources < 1) { /* Query Q(G): Group Timer is lowered to LMQT */ igmp_group_timer_lower_to_lmqt(group); } else { /* Query Q(G,A): Source Timer for sources in A are lowered to LMQT */ /* Scan sources in query and lower their timers to LMQT */ struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET); for (i = 0; i < recv_num_sources; ++i) { //struct in_addr src_addr = sources[i]; //struct igmp_source *src = igmp_find_source_by_addr(group, src_addr); struct in_addr src_addr; struct igmp_source *src; memcpy(&src_addr, sources + i, sizeof(struct in_addr)); src = igmp_find_source_by_addr(group, src_addr); if (src) { igmp_source_timer_lower_to_lmqt(src); } } } } else { char group_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("IGMP query v%d from %s on %s: could not find group %s for timer update", query_version, from_str, ifp->name, group_str); } } } /* s_flag is clear: timer updates */ return 0; } static int igmp_v3_report(struct igmp_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { uint16_t recv_checksum; uint16_t checksum; int num_groups; uint8_t *group_record; uint8_t *report_pastend = (uint8_t *) igmp_msg + igmp_msg_len; struct interface *ifp = igmp->interface; int i; if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) { zlog_warn("Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d", from_str, ifp->name, igmp_msg_len, IGMP_V3_MSG_MIN_SIZE); return -1; } recv_checksum = *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET); /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; checksum = in_cksum(igmp_msg, igmp_msg_len); if (checksum != recv_checksum) { zlog_warn("Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x", from_str, ifp->name, recv_checksum, checksum); return -1; } num_groups = ntohs(*(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET)); if (num_groups < 1) { zlog_warn("Recv IGMP report v3 from %s on %s: missing group records", from_str, ifp->name); return -1; } if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d", from_str, ifp->name, igmp_msg_len, checksum, num_groups); } group_record = (uint8_t *) igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET; /* Scan groups */ for (i = 0; i < num_groups; ++i) { struct in_addr rec_group; uint8_t *sources; uint8_t *src; int rec_type; int rec_auxdatalen; int rec_num_sources; int j; if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE) > report_pastend) { zlog_warn("Recv IGMP report v3 from %s on %s: group record beyond report end", from_str, ifp->name); return -1; } rec_type = group_record[IGMP_V3_GROUP_RECORD_TYPE_OFFSET]; rec_auxdatalen = group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET]; rec_num_sources = ntohs(* (uint16_t *) (group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET)); //rec_group = *(struct in_addr *)(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET); memcpy(&rec_group, group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, sizeof(struct in_addr)); if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s", from_str, ifp->name, i, rec_type, rec_auxdatalen, rec_num_sources, inet_ntoa(rec_group)); } /* Scan sources */ sources = group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET; for (j = 0, src = sources; j < rec_num_sources; ++j, src += 4) { if ((src + 4) > report_pastend) { zlog_warn("Recv IGMP report v3 from %s on %s: group source beyond report end", from_str, ifp->name); return -1; } if (PIM_DEBUG_IGMP_PACKETS) { char src_str[200]; if (!inet_ntop(AF_INET, src, src_str , sizeof(src_str))) sprintf(src_str, ""); zlog_debug("Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s", from_str, ifp->name, i, inet_ntoa(rec_group), src_str); } } /* for (sources) */ switch (rec_type) { case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE: igmpv3_report_isin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE: igmpv3_report_isex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE: igmpv3_report_toin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE: igmpv3_report_toex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES: igmpv3_report_allow(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES: igmpv3_report_block(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; default: zlog_warn("Recv IGMP report v3 from %s on %s: unknown record type: type=%d", from_str, ifp->name, rec_type); } group_record += 8 + (rec_num_sources << 2) + (rec_auxdatalen << 2); } /* for (group records) */ return 0; } static void on_trace(const char *label, struct interface *ifp, struct in_addr from) { if (PIM_DEBUG_IGMP_TRACE) { char from_str[100]; pim_inet4_dump("", from, from_str, sizeof(from_str)); zlog_debug("%s: from %s on %s", label, from_str, ifp->name); } } static int igmp_v2_report(struct igmp_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; struct igmp_group *group; struct in_addr group_addr; on_trace(__PRETTY_FUNCTION__, igmp->interface, from); if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn("Recv IGMP report v2 from %s on %s: size=%d other than correct=%d", from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); return -1; } if (PIM_DEBUG_IGMP_TRACE) { zlog_warn("%s %s: FIXME WRITEME", __FILE__, __PRETTY_FUNCTION__); } //group_addr = *(struct in_addr *)(igmp_msg + 4); memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return -1; } group->last_igmp_v2_report_dsec = pim_time_monotonic_dsec(); return 0; } static int igmp_v2_leave(struct igmp_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; on_trace(__PRETTY_FUNCTION__, igmp->interface, from); if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn("Recv IGMP leave v2 from %s on %s: size=%d other than correct=%d", from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); return -1; } if (PIM_DEBUG_IGMP_TRACE) { zlog_warn("%s %s: FIXME WRITEME", __FILE__, __PRETTY_FUNCTION__); } return 0; } static int igmp_v1_report(struct igmp_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; struct igmp_group *group; struct in_addr group_addr; on_trace(__PRETTY_FUNCTION__, igmp->interface, from); if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn("Recv IGMP report v1 from %s on %s: size=%d other than correct=%d", from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); return -1; } if (PIM_DEBUG_IGMP_TRACE) { zlog_warn("%s %s: FIXME WRITEME", __FILE__, __PRETTY_FUNCTION__); } //group_addr = *(struct in_addr *)(igmp_msg + 4); memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return -1; } group->last_igmp_v1_report_dsec = pim_time_monotonic_dsec(); return 0; } int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) { struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ char *igmp_msg; int igmp_msg_len; int msg_type; char from_str[100]; char to_str[100]; if (len < sizeof(*ip_hdr)) { zlog_warn("IGMP packet size=%zu shorter than minimum=%zu", len, sizeof(*ip_hdr)); return -1; } ip_hdr = (struct ip *) buf; pim_inet4_dump("", ip_hdr->ip_src, from_str , sizeof(from_str)); pim_inet4_dump("", ip_hdr->ip_dst, to_str , sizeof(to_str)); ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d", from_str, to_str, igmp->interface->name, len, ip_hlen, ip_hdr->ip_p); } if (ip_hdr->ip_p != PIM_IP_PROTO_IGMP) { zlog_warn("IP packet protocol=%d is not IGMP=%d", ip_hdr->ip_p, PIM_IP_PROTO_IGMP); return -1; } if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { zlog_warn("IP packet header size=%zu shorter than minimum=%d", ip_hlen, PIM_IP_HEADER_MIN_LEN); return -1; } if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { zlog_warn("IP packet header size=%zu greater than maximum=%d", ip_hlen, PIM_IP_HEADER_MAX_LEN); return -1; } igmp_msg = buf + ip_hlen; msg_type = *igmp_msg; igmp_msg_len = len - ip_hlen; if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IGMP packet from %s to %s on %s: ttl=%d msg_type=%d msg_size=%d", from_str, to_str, igmp->interface->name, ip_hdr->ip_ttl, msg_type, igmp_msg_len); } if (igmp_msg_len < PIM_IGMP_MIN_LEN) { zlog_warn("IGMP message size=%d shorter than minimum=%d", igmp_msg_len, PIM_IGMP_MIN_LEN); return -1; } switch (msg_type) { case PIM_IGMP_MEMBERSHIP_QUERY: { int max_resp_code = igmp_msg[1]; int query_version; /* RFC 3376: 7.1. Query Version Distinctions IGMPv1 Query: length = 8 octets AND Max Resp Code field is zero IGMPv2 Query: length = 8 octets AND Max Resp Code field is non-zero IGMPv3 Query: length >= 12 octets */ if (igmp_msg_len == 8) { query_version = max_resp_code ? 2 : 1; } else if (igmp_msg_len >= 12) { query_version = 3; } else { zlog_warn("Unknown IGMP query version"); return -1; } return recv_igmp_query(igmp, query_version, max_resp_code, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); } case PIM_IGMP_V3_MEMBERSHIP_REPORT: return igmp_v3_report(igmp, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); case PIM_IGMP_V2_MEMBERSHIP_REPORT: return igmp_v2_report(igmp, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); case PIM_IGMP_V1_MEMBERSHIP_REPORT: return igmp_v1_report(igmp, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); case PIM_IGMP_V2_LEAVE_GROUP: return igmp_v2_leave(igmp, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); } zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type); return -1; } static int pim_igmp_general_query(struct thread *t); void pim_igmp_general_query_on(struct igmp_sock *igmp) { struct pim_interface *pim_ifp; int startup_mode; int query_interval; zassert(igmp); zassert(igmp->interface); /* Since this socket is starting as querier, there should not exist a timer for other-querier-present. */ zassert(!igmp->t_other_querier_timer); pim_ifp = igmp->interface->info; zassert(pim_ifp); /* RFC 3376: 8.6. Startup Query Interval The Startup Query Interval is the interval between General Queries sent by a Querier on startup. Default: 1/4 the Query Interval. */ startup_mode = igmp->startup_query_count > 0; if (startup_mode) { --igmp->startup_query_count; /* query_interval = pim_ifp->igmp_default_query_interval >> 2; */ query_interval = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval); } else { query_interval = igmp->querier_query_interval; } if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("Querier %s scheduling %d-second (%s) TIMER event for IGMP query on fd=%d", ifaddr_str, query_interval, startup_mode ? "startup" : "non-startup", igmp->fd); } igmp->t_igmp_query_timer = 0; zassert(!igmp->t_igmp_query_timer); THREAD_TIMER_ON(master, igmp->t_igmp_query_timer, pim_igmp_general_query, igmp, query_interval); } void pim_igmp_general_query_off(struct igmp_sock *igmp) { zassert(igmp); if (PIM_DEBUG_IGMP_TRACE) { if (igmp->t_igmp_query_timer) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("IGMP querier %s fd=%d cancelling query TIMER event on %s", ifaddr_str, igmp->fd, igmp->interface->name); } } THREAD_OFF(igmp->t_igmp_query_timer); zassert(!igmp->t_igmp_query_timer); } /* Issue IGMP general query */ static int pim_igmp_general_query(struct thread *t) { char query_buf[PIM_IGMP_BUFSIZE_WRITE]; struct igmp_sock *igmp; struct in_addr dst_addr; struct in_addr group_addr; struct pim_interface *pim_ifp; zassert(t); igmp = THREAD_ARG(t); zassert(igmp); zassert(igmp->interface); zassert(igmp->interface->info); pim_ifp = igmp->interface->info; /* RFC3376: 4.1.12. IP Destination Addresses for Queries In IGMPv3, General Queries are sent with an IP destination address of 224.0.0.1, the all-systems multicast address. Group-Specific and Group-and-Source-Specific Queries are sent with an IP destination address equal to the multicast address of interest. */ dst_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); group_addr.s_addr = PIM_NET_INADDR_ANY; if (PIM_DEBUG_IGMP_TRACE) { char querier_str[100]; char dst_str[100]; pim_inet4_dump("", igmp->ifaddr, querier_str, sizeof(querier_str)); pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); zlog_debug("Querier %s issuing IGMP general query to %s on %s", querier_str, dst_str, igmp->interface->name); } pim_igmp_send_membership_query(0 /* igmp_group */, igmp->fd, igmp->interface->name, query_buf, sizeof(query_buf), 0 /* num_sources */, dst_addr, group_addr, pim_ifp->igmp_query_max_response_time_dsec, 1 /* s_flag: always set for general queries */, igmp->querier_robustness_variable, igmp->querier_query_interval); pim_igmp_general_query_on(igmp); return 0; } static int pim_igmp_read(struct thread *t); static void igmp_read_on(struct igmp_sock *igmp) { zassert(igmp); if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("Scheduling READ event on IGMP socket fd=%d", igmp->fd); } igmp->t_igmp_read = 0; zassert(!igmp->t_igmp_read); THREAD_READ_ON(master, igmp->t_igmp_read, pim_igmp_read, igmp, igmp->fd); } static int pim_igmp_read(struct thread *t) { struct igmp_sock *igmp; int fd; struct sockaddr_in from; struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); uint8_t buf[PIM_IGMP_BUFSIZE_READ]; int len; ifindex_t ifindex = -1; int result = -1; /* defaults to bad */ zassert(t); igmp = THREAD_ARG(t); zassert(igmp); fd = THREAD_FD(t); zassert(fd == igmp->fd); len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from, &fromlen, &to, &tolen, &ifindex); if (len < 0) { zlog_warn("Failure receiving IP IGMP packet on fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); goto done; } if (PIM_DEBUG_IGMP_PACKETS) { char from_str[100]; char to_str[100]; if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str))) sprintf(from_str, ""); if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str))) sprintf(to_str, ""); zlog_debug("Recv IP IGMP pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)", len, from_str, to_str, fd, ifindex, igmp->interface->ifindex); } #ifdef PIM_CHECK_RECV_IFINDEX_SANITY /* ifindex sanity check */ if (ifindex != (int) igmp->interface->ifindex) { char from_str[100]; char to_str[100]; struct interface *ifp; if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str))) sprintf(from_str, ""); if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str))) sprintf(to_str, ""); ifp = if_lookup_by_index(ifindex); if (ifp) { zassert(ifindex == (int) ifp->ifindex); } #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH zlog_warn("Interface mismatch: recv IGMP pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)", from_str, to_str, fd, ifindex, ifp ? ifp->name : "", igmp->interface->ifindex, igmp->interface->name); #endif goto done; } #endif if (pim_igmp_packet(igmp, (char *)buf, len)) { goto done; } result = 0; /* good */ done: igmp_read_on(igmp); return result; } static void sock_close(struct igmp_sock *igmp) { pim_igmp_other_querier_timer_off(igmp); pim_igmp_general_query_off(igmp); if (PIM_DEBUG_IGMP_TRACE) { if (igmp->t_igmp_read) { zlog_debug("Cancelling READ event on IGMP socket %s fd=%d on interface %s", inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name); } } THREAD_OFF(igmp->t_igmp_read); zassert(!igmp->t_igmp_read); if (close(igmp->fd)) { zlog_err("Failure closing IGMP socket %s fd=%d on interface %s: errno=%d: %s", inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name, errno, safe_strerror(errno)); } if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("Deleted IGMP socket %s fd=%d on interface %s", inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name); } } void igmp_startup_mode_on(struct igmp_sock *igmp) { struct pim_interface *pim_ifp; pim_ifp = igmp->interface->info; /* RFC 3376: 8.7. Startup Query Count The Startup Query Count is the number of Queries sent out on startup, separated by the Startup Query Interval. Default: the Robustness Variable. */ igmp->startup_query_count = igmp->querier_robustness_variable; /* Since we're (re)starting, reset QQI to default Query Interval */ igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; } static void igmp_group_free(struct igmp_group *group) { zassert(!group->t_group_query_retransmit_timer); zassert(!group->t_group_timer); zassert(group->group_source_list); zassert(!listcount(group->group_source_list)); list_free(group->group_source_list); XFREE(MTYPE_PIM_IGMP_GROUP, group); } static void igmp_group_delete(struct igmp_group *group) { struct listnode *src_node; struct listnode *src_nextnode; struct igmp_source *src; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Deleting IGMP group %s from socket %d interface %s", group_str, group->group_igmp_sock->fd, group->group_igmp_sock->interface->name); } for (ALL_LIST_ELEMENTS(group->group_source_list, src_node, src_nextnode, src)) { igmp_source_delete(src); } if (group->t_group_query_retransmit_timer) { THREAD_OFF(group->t_group_query_retransmit_timer); zassert(!group->t_group_query_retransmit_timer); } group_timer_off(group); listnode_delete(group->group_igmp_sock->igmp_group_list, group); igmp_group_free(group); } void igmp_group_delete_empty_include(struct igmp_group *group) { zassert(!group->group_filtermode_isexcl); zassert(!listcount(group->group_source_list)); igmp_group_delete(group); } void igmp_sock_free(struct igmp_sock *igmp) { zassert(!igmp->t_igmp_read); zassert(!igmp->t_igmp_query_timer); zassert(!igmp->t_other_querier_timer); zassert(igmp->igmp_group_list); zassert(!listcount(igmp->igmp_group_list)); list_free(igmp->igmp_group_list); XFREE(MTYPE_PIM_IGMP_SOCKET, igmp); } void igmp_sock_delete(struct igmp_sock *igmp) { struct pim_interface *pim_ifp; struct listnode *grp_node; struct listnode *grp_nextnode; struct igmp_group *grp; for (ALL_LIST_ELEMENTS(igmp->igmp_group_list, grp_node, grp_nextnode, grp)) { igmp_group_delete(grp); } sock_close(igmp); pim_ifp = igmp->interface->info; listnode_delete(pim_ifp->igmp_socket_list, igmp); igmp_sock_free(igmp); } static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, struct interface *ifp) { struct pim_interface *pim_ifp; struct igmp_sock *igmp; pim_ifp = ifp->info; if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("Creating IGMP socket fd=%d for address %s on interface %s", fd, inet_ntoa(ifaddr), ifp->name); } igmp = XMALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp)); if (!igmp) { zlog_warn("%s %s: XMALLOC() failure", __FILE__, __PRETTY_FUNCTION__); return 0; } igmp->igmp_group_list = list_new(); if (!igmp->igmp_group_list) { zlog_err("%s %s: failure: igmp_group_list = list_new()", __FILE__, __PRETTY_FUNCTION__); return 0; } igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free; igmp->fd = fd; igmp->interface = ifp; igmp->ifaddr = ifaddr; igmp->t_igmp_read = 0; igmp->t_igmp_query_timer = 0; igmp->t_other_querier_timer = 0; /* no other querier present */ igmp->querier_robustness_variable = pim_ifp->igmp_default_robustness_variable; igmp->sock_creation = pim_time_monotonic_sec(); /* igmp_startup_mode_on() will reset QQI: igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; */ igmp_startup_mode_on(igmp); igmp_read_on(igmp); pim_igmp_general_query_on(igmp); return igmp; } struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, struct in_addr ifaddr, struct interface *ifp) { struct pim_interface *pim_ifp; struct igmp_sock *igmp; int fd; pim_ifp = ifp->info; fd = igmp_sock_open(ifaddr, ifp->ifindex, pim_ifp->options); if (fd < 0) { zlog_warn("Could not open IGMP socket for %s on %s", inet_ntoa(ifaddr), ifp->name); return 0; } igmp = igmp_sock_new(fd, ifaddr, ifp); if (!igmp) { zlog_err("%s %s: igmp_sock_new() failure", __FILE__, __PRETTY_FUNCTION__); close(fd); return 0; } listnode_add(igmp_sock_list, igmp); #ifdef IGMP_SOCK_DUMP igmp_sock_dump(igmp_sock_array); #endif return igmp; } /* RFC 3376: 6.5. Switching Router Filter-Modes When a router's filter-mode for a group is EXCLUDE and the group timer expires, the router filter-mode for the group transitions to INCLUDE. A router uses source records with running source timers as its state for the switch to a filter-mode of INCLUDE. If there are any source records with source timers greater than zero (i.e., requested to be forwarded), a router switches to filter-mode of INCLUDE using those source records. Source records whose timers are zero (from the previous EXCLUDE mode) are deleted. */ static int igmp_group_timer(struct thread *t) { struct igmp_group *group; zassert(t); group = THREAD_ARG(t); zassert(group); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: Timer for group %s on interface %s", __PRETTY_FUNCTION__, group_str, group->group_igmp_sock->interface->name); } zassert(group->group_filtermode_isexcl); group->t_group_timer = 0; group->group_filtermode_isexcl = 0; /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ igmp_anysource_forward_stop(group); igmp_source_delete_expired(group->group_source_list); zassert(!group->t_group_timer); zassert(!group->group_filtermode_isexcl); /* RFC 3376: 6.2.2. Definition of Group Timers If there are no more source records for the group, delete group record. */ if (listcount(group->group_source_list) < 1) { igmp_group_delete_empty_include(group); } return 0; } static void group_timer_off(struct igmp_group *group) { if (!group->t_group_timer) return; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Cancelling TIMER event for group %s on %s", group_str, group->group_igmp_sock->interface->name); } THREAD_OFF(group->t_group_timer); zassert(!group->t_group_timer); } void igmp_group_timer_on(struct igmp_group *group, long interval_msec, const char *ifname) { group_timer_off(group); if (PIM_DEBUG_IGMP_EVENTS) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s on %s", interval_msec / 1000, interval_msec % 1000, group_str, ifname); } /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ zassert(group->group_filtermode_isexcl); THREAD_TIMER_MSEC_ON(master, group->t_group_timer, igmp_group_timer, group, interval_msec); } static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr) { struct igmp_group *group; struct listnode *node; for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, node, group)) if (group_addr.s_addr == group->group_addr.s_addr) return group; return 0; } struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr) { struct igmp_group *group; group = find_group_by_addr(igmp, group_addr); if (group) { return group; } /* Non-existant group is created as INCLUDE {empty}: RFC 3376 - 5.1. Action on Change of Interface State If no interface state existed for that multicast address before the change (i.e., the change consisted of creating a new per-interface record), or if no state exists after the change (i.e., the change consisted of deleting a per-interface record), then the "non-existent" state is considered to have a filter mode of INCLUDE and an empty source list. */ group = XMALLOC(MTYPE_PIM_IGMP_GROUP, sizeof(*group)); if (!group) { zlog_warn("%s %s: XMALLOC() failure", __FILE__, __PRETTY_FUNCTION__); return 0; /* error, not found, could not create */ } group->group_source_list = list_new(); if (!group->group_source_list) { zlog_warn("%s %s: list_new() failure", __FILE__, __PRETTY_FUNCTION__); XFREE(MTYPE_PIM_IGMP_GROUP, group); /* discard group */ return 0; /* error, not found, could not initialize */ } group->group_source_list->del = (void (*)(void *)) igmp_source_free; group->t_group_timer = NULL; group->t_group_query_retransmit_timer = NULL; group->group_specific_query_retransmit_count = 0; group->group_addr = group_addr; group->group_igmp_sock = igmp; group->last_igmp_v1_report_dsec = -1; group->last_igmp_v2_report_dsec = -1; group->group_creation = pim_time_monotonic_sec(); /* initialize new group as INCLUDE {empty} */ group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */ listnode_add(igmp->igmp_group_list, group); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Creating new IGMP group %s on socket %d interface %s", group_str, igmp->fd, igmp->interface->name); } /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ zassert(!group->group_filtermode_isexcl); /* INCLUDE mode */ zassert(!group->t_group_timer); /* group timer == 0 */ /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ igmp_anysource_forward_stop(group); return group; } quagga-1.2.4/pimd/pim_igmp.h000066400000000000000000000146611325323223500156760ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IGMP_H #define PIM_IGMP_H #include #include #include "vty.h" #include "linklist.h" /* The following sizes are likely to support any message sent within local MTU. */ #define PIM_IGMP_BUFSIZE_READ (20000) #define PIM_IGMP_BUFSIZE_WRITE (20000) #define PIM_IGMP_MEMBERSHIP_QUERY (0x11) #define PIM_IGMP_V1_MEMBERSHIP_REPORT (0x12) #define PIM_IGMP_V2_MEMBERSHIP_REPORT (0x16) #define PIM_IGMP_V2_LEAVE_GROUP (0x17) #define PIM_IGMP_V3_MEMBERSHIP_REPORT (0x22) #define IGMP_V3_REPORT_HEADER_SIZE (8) #define IGMP_V3_GROUP_RECORD_MIN_SIZE (8) #define IGMP_V3_MSG_MIN_SIZE (IGMP_V3_REPORT_HEADER_SIZE + \ IGMP_V3_GROUP_RECORD_MIN_SIZE) #define IGMP_V12_MSG_SIZE (8) #define IGMP_V3_GROUP_RECORD_TYPE_OFFSET (0) #define IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET (1) #define IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET (2) #define IGMP_V3_GROUP_RECORD_GROUP_OFFSET (4) #define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8) /* RFC 3376: 8.1. Robustness Variable - Default: 2 */ #define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2) /* RFC 3376: 8.2. Query Interval - Default: 125 seconds */ #define IGMP_GENERAL_QUERY_INTERVAL (125) /* RFC 3376: 8.3. Query Response Interval - Default: 100 deciseconds */ #define IGMP_QUERY_MAX_RESPONSE_TIME_DSEC (100) /* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */ #define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10) struct igmp_join { struct in_addr group_addr; struct in_addr source_addr; int sock_fd; time_t sock_creation; }; struct igmp_sock { int fd; struct interface *interface; struct in_addr ifaddr; time_t sock_creation; struct thread *t_igmp_read; /* read: IGMP sockets */ struct thread *t_igmp_query_timer; /* timer: issue IGMP general queries */ struct thread *t_other_querier_timer; /* timer: other querier present */ int querier_query_interval; /* QQI */ int querier_robustness_variable; /* QRV */ int startup_query_count; struct list *igmp_group_list; /* list of struct igmp_group */ }; struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, struct in_addr ifaddr); struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd); struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, struct in_addr ifaddr, struct interface *ifp); void igmp_sock_delete(struct igmp_sock *igmp); void igmp_sock_free(struct igmp_sock *igmp); int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len); void pim_igmp_general_query_on(struct igmp_sock *igmp); void pim_igmp_general_query_off(struct igmp_sock *igmp); void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp); void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp); #define IGMP_SOURCE_MASK_FORWARDING (1 << 0) #define IGMP_SOURCE_MASK_DELETE (1 << 1) #define IGMP_SOURCE_MASK_SEND (1 << 2) #define IGMP_SOURCE_TEST_FORWARDING(flags) ((flags) & IGMP_SOURCE_MASK_FORWARDING) #define IGMP_SOURCE_TEST_DELETE(flags) ((flags) & IGMP_SOURCE_MASK_DELETE) #define IGMP_SOURCE_TEST_SEND(flags) ((flags) & IGMP_SOURCE_MASK_SEND) #define IGMP_SOURCE_DO_FORWARDING(flags) ((flags) |= IGMP_SOURCE_MASK_FORWARDING) #define IGMP_SOURCE_DO_DELETE(flags) ((flags) |= IGMP_SOURCE_MASK_DELETE) #define IGMP_SOURCE_DO_SEND(flags) ((flags) |= IGMP_SOURCE_MASK_SEND) #define IGMP_SOURCE_DONT_FORWARDING(flags) ((flags) &= ~IGMP_SOURCE_MASK_FORWARDING) #define IGMP_SOURCE_DONT_DELETE(flags) ((flags) &= ~IGMP_SOURCE_MASK_DELETE) #define IGMP_SOURCE_DONT_SEND(flags) ((flags) &= ~IGMP_SOURCE_MASK_SEND) struct igmp_source { struct in_addr source_addr; struct thread *t_source_timer; struct igmp_group *source_group; /* back pointer */ time_t source_creation; uint32_t source_flags; struct channel_oil *source_channel_oil; /* RFC 3376: 6.6.3.2. Building and Sending Group and Source Specific Queries */ int source_query_retransmit_count; }; struct igmp_group { /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ struct thread *t_group_timer; /* Shared between group-specific and group-and-source-specific retransmissions */ struct thread *t_group_query_retransmit_timer; /* Counter exclusive for group-specific retransmissions (not used by group-and-source-specific retransmissions, since sources have their counters) */ int group_specific_query_retransmit_count; struct in_addr group_addr; int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */ struct list *group_source_list; /* list of struct igmp_source */ time_t group_creation; struct igmp_sock *group_igmp_sock; /* back pointer */ int64_t last_igmp_v1_report_dsec; int64_t last_igmp_v2_report_dsec; }; struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr); void igmp_group_delete_empty_include(struct igmp_group *group); void igmp_startup_mode_on(struct igmp_sock *igmp); void igmp_group_timer_on(struct igmp_group *group, long interval_msec, const char *ifname); struct igmp_source * source_new (struct igmp_group *group, struct in_addr src_addr); #endif /* PIM_IGMP_H */ quagga-1.2.4/pimd/pim_igmp_join.c000066400000000000000000000036321325323223500167040ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include #include "zebra.h" #include "pim_igmp_join.h" #ifndef SOL_IP #define SOL_IP IPPROTO_IP #endif #ifndef MCAST_JOIN_SOURCE_GROUP #define MCAST_JOIN_SOURCE_GROUP 46 struct group_source_req { uint32_t gsr_interface; struct sockaddr_storage gsr_group; struct sockaddr_storage gsr_source; }; #endif int pim_igmp_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr) { struct group_source_req req; struct sockaddr_in group; struct sockaddr_in source; memset(&group, 0, sizeof(group)); group.sin_family = AF_INET; group.sin_addr = group_addr; group.sin_port = htons(0); memcpy(&req.gsr_group, &group, sizeof(struct sockaddr_in)); memset(&source, 0, sizeof(source)); source.sin_family = AF_INET; source.sin_addr = source_addr; source.sin_port = htons(0); memcpy(&req.gsr_source, &source, sizeof(struct sockaddr_in)); req.gsr_interface = ifindex; return setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)); return 0; } quagga-1.2.4/pimd/pim_igmp_join.h000066400000000000000000000020571325323223500167110ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IGMP_JOIN_H #define PIM_IGMP_JOIN_H #include #include "if.h" int pim_igmp_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr); #endif /* PIM_IGMP_JOIN_H */ quagga-1.2.4/pimd/pim_igmpv3.c000066400000000000000000001447571325323223500161540ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "memory.h" #include "pimd.h" #include "pim_iface.h" #include "pim_igmp.h" #include "pim_igmpv3.h" #include "pim_str.h" #include "pim_util.h" #include "pim_time.h" #include "pim_zebra.h" #include "pim_oil.h" static void group_retransmit_timer_on(struct igmp_group *group); static long igmp_group_timer_remain_msec(struct igmp_group *group); static long igmp_source_timer_remain_msec(struct igmp_source *source); static void group_query_send(struct igmp_group *group); static void source_query_send_by_flag(struct igmp_group *group, int num_sources_tosend); static void on_trace(const char *label, struct interface *ifp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { if (PIM_DEBUG_IGMP_TRACE) { char from_str[100]; char group_str[100]; pim_inet4_dump("", from, from_str, sizeof(from_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_debug("%s: from %s on %s: group=%s sources=%d", label, from_str, ifp->name, group_str, num_sources); } } int igmp_group_compat_mode(const struct igmp_sock *igmp, const struct igmp_group *group) { struct pim_interface *pim_ifp; int64_t now_dsec; long older_host_present_interval_dsec; zassert(igmp); zassert(igmp->interface); zassert(igmp->interface->info); pim_ifp = igmp->interface->info; /* RFC 3376: 8.13. Older Host Present Interval This value MUST be ((the Robustness Variable) times (the Query Interval)) plus (one Query Response Interval). older_host_present_interval_dsec = \ igmp->querier_robustness_variable * \ 10 * igmp->querier_query_interval + \ pim_ifp->query_max_response_time_dsec; */ older_host_present_interval_dsec = PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); now_dsec = pim_time_monotonic_dsec(); if (now_dsec < 1) { /* broken timer logged by pim_time_monotonic_dsec() */ return 3; } if ((now_dsec - group->last_igmp_v1_report_dsec) < older_host_present_interval_dsec) return 1; /* IGMPv1 */ if ((now_dsec - group->last_igmp_v2_report_dsec) < older_host_present_interval_dsec) return 2; /* IGMPv2 */ return 3; /* IGMPv3 */ } void igmp_group_reset_gmi(struct igmp_group *group) { long group_membership_interval_msec; struct pim_interface *pim_ifp; struct igmp_sock *igmp; struct interface *ifp; igmp = group->group_igmp_sock; ifp = igmp->interface; pim_ifp = ifp->info; /* RFC 3376: 8.4. Group Membership Interval The Group Membership Interval is the amount of time that must pass before a multicast router decides there are no more members of a group or a particular source on a network. This value MUST be ((the Robustness Variable) times (the Query Interval)) plus (one Query Response Interval). group_membership_interval_msec = querier_robustness_variable * (1000 * querier_query_interval) + 100 * query_response_interval_dsec; */ group_membership_interval_msec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Resetting group %s timer to GMI=%ld.%03ld sec on %s", group_str, group_membership_interval_msec / 1000, group_membership_interval_msec % 1000, ifp->name); } /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ zassert(group->group_filtermode_isexcl); igmp_group_timer_on(group, group_membership_interval_msec, ifp->name); } static int igmp_source_timer(struct thread *t) { struct igmp_source *source; struct igmp_group *group; zassert(t); source = THREAD_ARG(t); zassert(source); group = source->source_group; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("%s: Source timer expired for group %s source %s on %s", __PRETTY_FUNCTION__, group_str, source_str, group->group_igmp_sock->interface->name); } zassert(source->t_source_timer); source->t_source_timer = 0; /* RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules Group Filter-Mode Source Timer Value Action ----------- ------------------ ------ INCLUDE TIMER == 0 Suggest to stop forwarding traffic from source and remove source record. If there are no more source records for the group, delete group record. EXCLUDE TIMER == 0 Suggest to not forward traffic from source (DO NOT remove record) Source timer switched from (T > 0) to (T == 0): disable forwarding. */ zassert(!source->t_source_timer); if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ igmp_source_forward_stop(source); } else { /* INCLUDE mode */ /* igmp_source_delete() will stop forwarding source */ igmp_source_delete(source); /* If there are no more source records for the group, delete group record. */ if (!listcount(group->group_source_list)) { igmp_group_delete_empty_include(group); } } return 0; } static void source_timer_off(struct igmp_group *group, struct igmp_source *source) { if (!source->t_source_timer) return; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("Cancelling TIMER event for group %s source %s on %s", group_str, source_str, group->group_igmp_sock->interface->name); } THREAD_OFF(source->t_source_timer); zassert(!source->t_source_timer); } static void igmp_source_timer_on(struct igmp_group *group, struct igmp_source *source, long interval_msec) { source_timer_off(group, source); if (PIM_DEBUG_IGMP_EVENTS) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s", interval_msec / 1000, interval_msec % 1000, group_str, source_str, group->group_igmp_sock->interface->name); } THREAD_TIMER_MSEC_ON(master, source->t_source_timer, igmp_source_timer, source, interval_msec); zassert(source->t_source_timer); /* RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules Source timer switched from (T == 0) to (T > 0): enable forwarding. */ igmp_source_forward_start(source); } void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group, struct igmp_source *source) { long group_membership_interval_msec; struct pim_interface *pim_ifp; struct interface *ifp; ifp = igmp->interface; pim_ifp = ifp->info; group_membership_interval_msec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("Resetting source %s timer to GMI=%ld.%03ld sec for group %s on %s", source_str, group_membership_interval_msec / 1000, group_membership_interval_msec % 1000, group_str, ifp->name); } igmp_source_timer_on(group, source, group_membership_interval_msec); } static void source_mark_delete_flag(struct list *source_list) { struct listnode *src_node; struct igmp_source *src; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { IGMP_SOURCE_DO_DELETE(src->source_flags); } } static void source_mark_send_flag(struct list *source_list) { struct listnode *src_node; struct igmp_source *src; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { IGMP_SOURCE_DO_SEND(src->source_flags); } } static int source_mark_send_flag_by_timer(struct list *source_list) { struct listnode *src_node; struct igmp_source *src; int num_marked_sources = 0; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { /* Is source timer running? */ if (src->t_source_timer) { IGMP_SOURCE_DO_SEND(src->source_flags); ++num_marked_sources; } else { IGMP_SOURCE_DONT_SEND(src->source_flags); } } return num_marked_sources; } static void source_clear_send_flag(struct list *source_list) { struct listnode *src_node; struct igmp_source *src; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { IGMP_SOURCE_DONT_SEND(src->source_flags); } } /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group) { zassert(group->group_filtermode_isexcl); if (listcount(group->group_source_list) < 1) { igmp_anysource_forward_start(group); } } void igmp_source_free(struct igmp_source *source) { /* make sure there is no source timer running */ zassert(!source->t_source_timer); XFREE(MTYPE_PIM_IGMP_GROUP_SOURCE, source); } static void source_channel_oil_detach(struct igmp_source *source) { if (source->source_channel_oil) { pim_channel_oil_del(source->source_channel_oil); source->source_channel_oil = 0; } } /* igmp_source_delete: stop fowarding, and delete the source igmp_source_forward_stop: stop fowarding, but keep the source */ void igmp_source_delete(struct igmp_source *source) { struct igmp_group *group; group = source->source_group; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("Deleting IGMP source %s for group %s from socket %d interface %s", source_str, group_str, group->group_igmp_sock->fd, group->group_igmp_sock->interface->name); } source_timer_off(group, source); igmp_source_forward_stop(source); /* sanity check that forwarding has been disabled */ if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_warn("%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s", __PRETTY_FUNCTION__, source_str, group_str, group->group_igmp_sock->fd, group->group_igmp_sock->interface->name); /* warning only */ } source_channel_oil_detach(source); /* notice that listnode_delete() can't be moved into igmp_source_free() because the later is called by list_delete_all_node() */ listnode_delete(group->group_source_list, source); igmp_source_free(source); if (group->group_filtermode_isexcl) { group_exclude_fwd_anysrc_ifempty(group); } } static void source_delete_by_flag(struct list *source_list) { struct listnode *src_node; struct listnode *src_nextnode; struct igmp_source *src; for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src)) if (IGMP_SOURCE_TEST_DELETE(src->source_flags)) igmp_source_delete(src); } void igmp_source_delete_expired(struct list *source_list) { struct listnode *src_node; struct listnode *src_nextnode; struct igmp_source *src; for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src)) if (!src->t_source_timer) igmp_source_delete(src); } struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, struct in_addr src_addr) { struct listnode *src_node; struct igmp_source *src; for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) if (src_addr.s_addr == src->source_addr.s_addr) return src; return 0; } struct igmp_source * source_new (struct igmp_group *group, struct in_addr src_addr) { struct igmp_source *src; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", src_addr, source_str, sizeof(source_str)); zlog_debug("Creating new IGMP source %s for group %s on socket %d interface %s", source_str, group_str, group->group_igmp_sock->fd, group->group_igmp_sock->interface->name); } src = XMALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src)); if (!src) { zlog_warn("%s %s: XMALLOC() failure", __FILE__, __PRETTY_FUNCTION__); return 0; /* error, not found, could not create */ } src->t_source_timer = NULL; src->source_group = group; /* back pointer */ src->source_addr = src_addr; src->source_creation = pim_time_monotonic_sec(); src->source_flags = 0; src->source_query_retransmit_count = 0; src->source_channel_oil = NULL; listnode_add(group->group_source_list, src); zassert(!src->t_source_timer); /* source timer == 0 */ /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ igmp_anysource_forward_stop(group); return src; } static struct igmp_source *add_source_by_addr(struct igmp_sock *igmp, struct igmp_group *group, struct in_addr src_addr) { struct igmp_source *src; src = igmp_find_source_by_addr(group, src_addr); if (src) { return src; } src = source_new(group, src_addr); if (!src) { return 0; } return src; } static void allow(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct igmp_group *group; int i; /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } /* scan received sources */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; source = add_source_by_addr(igmp, group, *src_addr); if (!source) { continue; } /* RFC 3376: 6.4.1. Reception of Current-State Records When receiving IS_IN reports for groups in EXCLUDE mode is sources should be moved from set with (timers = 0) to set with (timers > 0). igmp_source_reset_gmi() below, resetting the source timers to GMI, accomplishes this. */ igmp_source_reset_gmi(igmp, group, source); } /* scan received sources */ } void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { on_trace(__PRETTY_FUNCTION__, igmp->interface, from, group_addr, num_sources, sources); allow(igmp, from, group_addr, num_sources, sources); } static void isex_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int i; /* EXCLUDE mode */ zassert(group->group_filtermode_isexcl); /* E.1: set deletion flag for known sources (X,Y) */ source_mark_delete_flag(group->group_source_list); /* scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* E.2: lookup reported source from (A) in (X,Y) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* E.3: if found, clear deletion flag: (X*A) or (Y*A) */ IGMP_SOURCE_DONT_DELETE(source->source_flags); } else { /* E.4: if not found, create source with timer=GMI: (A-X-Y) */ source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* timer == 0 */ igmp_source_reset_gmi(group->group_igmp_sock, group, source); zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ } } /* scan received sources */ /* E.5: delete all sources marked with deletion flag: (X-A) and (Y-A) */ source_delete_by_flag(group->group_source_list); } static void isex_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int i; /* INCLUDE mode */ zassert(!group->group_filtermode_isexcl); /* I.1: set deletion flag for known sources (A) */ source_mark_delete_flag(group->group_source_list); /* scan received sources (B) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* I.2: lookup reported source (B) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* I.3: if found, clear deletion flag (A*B) */ IGMP_SOURCE_DONT_DELETE(source->source_flags); } else { /* I.4: if not found, create source with timer=0 (B-A) */ source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* (B-A) timer=0 */ } } /* scan received sources */ /* I.5: delete all sources marked with deletion flag (A-B) */ source_delete_by_flag(group->group_source_list); group->group_filtermode_isexcl = 1; /* boolean=true */ zassert(group->group_filtermode_isexcl); group_exclude_fwd_anysrc_ifempty(group); } void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ isex_excl(group, num_sources, sources); } else { /* INCLUDE mode */ isex_incl(group, num_sources, sources); zassert(group->group_filtermode_isexcl); } zassert(group->group_filtermode_isexcl); igmp_group_reset_gmi(group); } static void toin_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { struct igmp_sock *igmp = group->group_igmp_sock; int num_sources_tosend = listcount(group->group_source_list); int i; /* Set SEND flag for all known sources (A) */ source_mark_send_flag(group->group_source_list); /* Scan received sources (B) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* Lookup reported source (B) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* If found, clear SEND flag (A*B) */ IGMP_SOURCE_DONT_SEND(source->source_flags); --num_sources_tosend; } else { /* If not found, create new source */ source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } } /* (B)=GMI */ igmp_source_reset_gmi(igmp, group, source); } /* Send sources marked with SEND flag: Q(G,A-B) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } } static void toin_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { struct igmp_sock *igmp = group->group_igmp_sock; int num_sources_tosend; int i; /* Set SEND flag for X (sources with timer > 0) */ num_sources_tosend = source_mark_send_flag_by_timer(group->group_source_list); /* Scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* Lookup reported source (A) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { if (source->t_source_timer) { /* If found and timer running, clear SEND flag (X*A) */ IGMP_SOURCE_DONT_SEND(source->source_flags); --num_sources_tosend; } } else { /* If not found, create new source */ source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } } /* (A)=GMI */ igmp_source_reset_gmi(igmp, group, source); } /* Send sources marked with SEND flag: Q(G,X-A) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } /* Send Q(G) */ group_query_send(group); } void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ toin_excl(group, num_sources, sources); } else { /* INCLUDE mode */ toin_incl(group, num_sources, sources); } } static void toex_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; int i; zassert(!group->group_filtermode_isexcl); /* Set DELETE flag for all known sources (A) */ source_mark_delete_flag(group->group_source_list); /* Clear off SEND flag from all known sources (A) */ source_clear_send_flag(group->group_source_list); /* Scan received sources (B) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* Lookup reported source (B) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* If found, clear deletion flag: (A*B) */ IGMP_SOURCE_DONT_DELETE(source->source_flags); /* and set SEND flag (A*B) */ IGMP_SOURCE_DO_SEND(source->source_flags); ++num_sources_tosend; } else { /* If source not found, create source with timer=0: (B-A)=0 */ source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* (B-A) timer=0 */ } } /* Scan received sources (B) */ group->group_filtermode_isexcl = 1; /* boolean=true */ /* Delete all sources marked with DELETE flag (A-B) */ source_delete_by_flag(group->group_source_list); /* Send sources marked with SEND flag: Q(G,A*B) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } zassert(group->group_filtermode_isexcl); group_exclude_fwd_anysrc_ifempty(group); } static void toex_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; int i; /* set DELETE flag for all known sources (X,Y) */ source_mark_delete_flag(group->group_source_list); /* clear off SEND flag from all known sources (X,Y) */ source_clear_send_flag(group->group_source_list); /* scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* lookup reported source (A) in known sources (X,Y) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* if found, clear off DELETE flag from reported source (A) */ IGMP_SOURCE_DONT_DELETE(source->source_flags); } else { /* if not found, create source with Group Timer: (A-X-Y)=Group Timer */ long group_timer_msec; source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* timer == 0 */ group_timer_msec = igmp_group_timer_remain_msec(group); igmp_source_timer_on(group, source, group_timer_msec); zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ /* make sure source is created with DELETE flag unset */ zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags)); } /* make sure reported source has DELETE flag unset */ zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags)); if (source->t_source_timer) { /* if source timer>0 mark SEND flag: Q(G,A-Y) */ IGMP_SOURCE_DO_SEND(source->source_flags); ++num_sources_tosend; } } /* scan received sources (A) */ /* delete all sources marked with DELETE flag: Delete (X-A) Delete (Y-A) */ source_delete_by_flag(group->group_source_list); /* send sources marked with SEND flag: Q(G,A-Y) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } } void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ toex_excl(group, num_sources, sources); } else { /* INCLUDE mode */ toex_incl(group, num_sources, sources); zassert(group->group_filtermode_isexcl); } zassert(group->group_filtermode_isexcl); /* Group Timer=GMI */ igmp_group_reset_gmi(group); } void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { on_trace(__PRETTY_FUNCTION__, igmp->interface, from, group_addr, num_sources, sources); allow(igmp, from, group_addr, num_sources, sources); } /* RFC3376: 6.6.3.1. Building and Sending Group Specific Queries When transmitting a group specific query, if the group timer is larger than LMQT, the "Suppress Router-Side Processing" bit is set in the query message. */ static void group_retransmit_group(struct igmp_group *group) { char query_buf[PIM_IGMP_BUFSIZE_WRITE]; struct igmp_sock *igmp; struct pim_interface *pim_ifp; long lmqc; /* Last Member Query Count */ long lmqi_msec; /* Last Member Query Interval */ long lmqt_msec; /* Last Member Query Time */ int s_flag; igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* RFC3376: 6.6.3.1. Building and Sending Group Specific Queries When transmitting a group specific query, if the group timer is larger than LMQT, the "Suppress Router-Side Processing" bit is set in the query message. */ s_flag = igmp_group_timer_remain_msec(group) > lmqt_msec; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d", group_str, igmp->interface->name, s_flag, group->group_specific_query_retransmit_count); } /* RFC3376: 4.1.12. IP Destination Addresses for Queries Group-Specific and Group-and-Source-Specific Queries are sent with an IP destination address equal to the multicast address of interest. */ pim_igmp_send_membership_query(group, igmp->fd, igmp->interface->name, query_buf, sizeof(query_buf), 0 /* num_sources_tosend */, group->group_addr /* dst_addr */, group->group_addr /* group_addr */, pim_ifp->igmp_specific_query_max_response_time_dsec, s_flag, igmp->querier_robustness_variable, igmp->querier_query_interval); } /* RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries When building a group and source specific query for a group G, two separate query messages are sent for the group. The first one has the "Suppress Router-Side Processing" bit set and contains all the sources with retransmission state and timers greater than LMQT. The second has the "Suppress Router-Side Processing" bit clear and contains all the sources with retransmission state and timers lower or equal to LMQT. If either of the two calculated messages does not contain any sources, then its transmission is suppressed. */ static int group_retransmit_sources(struct igmp_group *group, int send_with_sflag_set) { struct igmp_sock *igmp; struct pim_interface *pim_ifp; long lmqc; /* Last Member Query Count */ long lmqi_msec; /* Last Member Query Interval */ long lmqt_msec; /* Last Member Query Time */ char query_buf1[PIM_IGMP_BUFSIZE_WRITE]; /* 1 = with s_flag set */ char query_buf2[PIM_IGMP_BUFSIZE_WRITE]; /* 2 = with s_flag clear */ int query_buf1_max_sources; int query_buf2_max_sources; struct in_addr *source_addr1; struct in_addr *source_addr2; int num_sources_tosend1; int num_sources_tosend2; struct listnode *src_node; struct igmp_source *src; int num_retransmit_sources_left = 0; query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2; query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2; source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET); source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET); igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* Scan all group sources */ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { /* Source has retransmission state? */ if (src->source_query_retransmit_count < 1) continue; if (--src->source_query_retransmit_count > 0) { ++num_retransmit_sources_left; } /* Copy source address into appropriate query buffer */ if (igmp_source_timer_remain_msec(src) > lmqt_msec) { *source_addr1 = src->source_addr; ++source_addr1; } else { *source_addr2 = src->source_addr; ++source_addr2; } } num_sources_tosend1 = source_addr1 - (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET); num_sources_tosend2 = source_addr2 - (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d", group_str, igmp->interface->name, num_sources_tosend1, num_sources_tosend2, send_with_sflag_set, num_retransmit_sources_left); } if (num_sources_tosend1 > 0) { /* Send group-and-source-specific query with s_flag set and all sources with timers greater than LMQT. */ if (send_with_sflag_set) { query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2; if (num_sources_tosend1 > query_buf1_max_sources) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)", __PRETTY_FUNCTION__, group_str, igmp->interface->name, num_sources_tosend1, sizeof(query_buf1), query_buf1_max_sources); } else { /* RFC3376: 4.1.12. IP Destination Addresses for Queries Group-Specific and Group-and-Source-Specific Queries are sent with an IP destination address equal to the multicast address of interest. */ pim_igmp_send_membership_query(group, igmp->fd, igmp->interface->name, query_buf1, sizeof(query_buf1), num_sources_tosend1, group->group_addr, group->group_addr, pim_ifp->igmp_specific_query_max_response_time_dsec, 1 /* s_flag */, igmp->querier_robustness_variable, igmp->querier_query_interval); } } /* send_with_sflag_set */ } if (num_sources_tosend2 > 0) { /* Send group-and-source-specific query with s_flag clear and all sources with timers lower or equal to LMQT. */ query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2; if (num_sources_tosend2 > query_buf2_max_sources) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)", __PRETTY_FUNCTION__, group_str, igmp->interface->name, num_sources_tosend2, sizeof(query_buf2), query_buf2_max_sources); } else { /* RFC3376: 4.1.12. IP Destination Addresses for Queries Group-Specific and Group-and-Source-Specific Queries are sent with an IP destination address equal to the multicast address of interest. */ pim_igmp_send_membership_query(group, igmp->fd, igmp->interface->name, query_buf2, sizeof(query_buf2), num_sources_tosend2, group->group_addr, group->group_addr, pim_ifp->igmp_specific_query_max_response_time_dsec, 0 /* s_flag */, igmp->querier_robustness_variable, igmp->querier_query_interval); } } return num_retransmit_sources_left; } static int igmp_group_retransmit(struct thread *t) { struct igmp_group *group; int num_retransmit_sources_left; int send_with_sflag_set; /* boolean */ zassert(t); group = THREAD_ARG(t); zassert(group); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("group_retransmit_timer: group %s on %s", group_str, group->group_igmp_sock->interface->name); } /* Retransmit group-specific queries? (RFC3376: 6.6.3.1) */ if (group->group_specific_query_retransmit_count > 0) { /* Retransmit group-specific queries (RFC3376: 6.6.3.1) */ group_retransmit_group(group); --group->group_specific_query_retransmit_count; /* RFC3376: 6.6.3.2 If a group specific query is scheduled to be transmitted at the same time as a group and source specific query for the same group, then transmission of the group and source specific message with the "Suppress Router-Side Processing" bit set may be suppressed. */ send_with_sflag_set = 0; /* boolean=false */ } else { send_with_sflag_set = 1; /* boolean=true */ } /* Retransmit group-and-source-specific queries (RFC3376: 6.6.3.2) */ num_retransmit_sources_left = group_retransmit_sources(group, send_with_sflag_set); group->t_group_query_retransmit_timer = 0; /* Keep group retransmit timer running if there is any retransmit counter pending */ if ((num_retransmit_sources_left > 0) || (group->group_specific_query_retransmit_count > 0)) { group_retransmit_timer_on(group); } return 0; } /* group_retransmit_timer_on: if group retransmit timer isn't running, starts it; otherwise, do nothing */ static void group_retransmit_timer_on(struct igmp_group *group) { struct igmp_sock *igmp; struct pim_interface *pim_ifp; long lmqi_msec; /* Last Member Query Interval */ /* if group retransmit timer is running, do nothing */ if (group->t_group_query_retransmit_timer) { return; } igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Scheduling %ld.%03ld sec retransmit timer for group %s on %s", lmqi_msec / 1000, lmqi_msec % 1000, group_str, igmp->interface->name); } THREAD_TIMER_MSEC_ON(master, group->t_group_query_retransmit_timer, igmp_group_retransmit, group, lmqi_msec); } static long igmp_group_timer_remain_msec(struct igmp_group *group) { return pim_time_timer_remain_msec(group->t_group_timer); } static long igmp_source_timer_remain_msec(struct igmp_source *source) { return pim_time_timer_remain_msec(source->t_source_timer); } /* RFC3376: 6.6.3.1. Building and Sending Group Specific Queries */ static void group_query_send(struct igmp_group *group) { long lmqc; /* Last Member Query Count */ lmqc = group->group_igmp_sock->querier_robustness_variable; /* lower group timer to lmqt */ igmp_group_timer_lower_to_lmqt(group); /* reset retransmission counter */ group->group_specific_query_retransmit_count = lmqc; /* immediately send group specific query (decrease retransmit counter by 1)*/ group_retransmit_group(group); /* make sure group retransmit timer is running */ group_retransmit_timer_on(group); } /* RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries */ static void source_query_send_by_flag(struct igmp_group *group, int num_sources_tosend) { struct igmp_sock *igmp; struct pim_interface *pim_ifp; struct listnode *src_node; struct igmp_source *src; long lmqc; /* Last Member Query Count */ long lmqi_msec; /* Last Member Query Interval */ long lmqt_msec; /* Last Member Query Time */ zassert(num_sources_tosend > 0); igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries (...) for each of the sources in X of group G, with source timer larger than LMQT: o Set number of retransmissions for each source to [Last Member Query Count]. o Lower source timer to LMQT. */ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { if (IGMP_SOURCE_TEST_SEND(src->source_flags)) { /* source "src" in X of group G */ if (igmp_source_timer_remain_msec(src) > lmqt_msec) { src->source_query_retransmit_count = lmqc; igmp_source_timer_lower_to_lmqt(src); } } } /* send group-and-source specific queries */ group_retransmit_sources(group, 1 /* send_with_sflag_set=true */); /* make sure group retransmit timer is running */ group_retransmit_timer_on(group); } static void block_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; int i; /* 1. clear off SEND flag from all known sources (X,Y) */ source_clear_send_flag(group->group_source_list); /* 2. scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* lookup reported source (A) in known sources (X,Y) */ source = igmp_find_source_by_addr(group, *src_addr); if (!source) { /* 3: if not found, create source with Group Timer: (A-X-Y)=Group Timer */ long group_timer_msec; source = source_new(group, *src_addr); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* timer == 0 */ group_timer_msec = igmp_group_timer_remain_msec(group); igmp_source_timer_on(group, source, group_timer_msec); zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ } if (source->t_source_timer) { /* 4. if source timer>0 mark SEND flag: Q(G,A-Y) */ IGMP_SOURCE_DO_SEND(source->source_flags); ++num_sources_tosend; } } /* 5. send sources marked with SEND flag: Q(G,A-Y) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } } static void block_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; int i; /* 1. clear off SEND flag from all known sources (B) */ source_clear_send_flag(group->group_source_list); /* 2. scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* lookup reported source (A) in known sources (B) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* 3. if found (A*B), mark SEND flag: Q(G,A*B) */ IGMP_SOURCE_DO_SEND(source->source_flags); ++num_sources_tosend; } } /* 4. send sources marked with SEND flag: Q(G,A*B) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } } void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr); if (!group) { return; } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ block_excl(group, num_sources, sources); } else { /* INCLUDE mode */ block_incl(group, num_sources, sources); } } void igmp_group_timer_lower_to_lmqt(struct igmp_group *group) { struct igmp_sock *igmp; struct interface *ifp; struct pim_interface *pim_ifp; char *ifname; int lmqi_dsec; /* Last Member Query Interval */ int lmqc; /* Last Member Query Count */ int lmqt_msec; /* Last Member Query Time */ /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ if (!group->group_filtermode_isexcl) { return; } igmp = group->group_igmp_sock; ifp = igmp->interface; pim_ifp = ifp->info; ifname = ifp->name; lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec; lmqc = igmp->querier_robustness_variable; lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec", __PRETTY_FUNCTION__, group_str, ifname, lmqc, lmqi_dsec, lmqt_msec); } zassert(group->group_filtermode_isexcl); igmp_group_timer_on(group, lmqt_msec, ifname); } void igmp_source_timer_lower_to_lmqt(struct igmp_source *source) { struct igmp_group *group; struct igmp_sock *igmp; struct interface *ifp; struct pim_interface *pim_ifp; char *ifname; int lmqi_dsec; /* Last Member Query Interval */ int lmqc; /* Last Member Query Count */ int lmqt_msec; /* Last Member Query Time */ group = source->source_group; igmp = group->group_igmp_sock; ifp = igmp->interface; pim_ifp = ifp->info; ifname = ifp->name; lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec; lmqc = igmp->querier_robustness_variable; lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("%s: group %s source %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec", __PRETTY_FUNCTION__, group_str, source_str, ifname, lmqc, lmqi_dsec, lmqt_msec); } igmp_source_timer_on(group, source, lmqt_msec); } /* Copy sources to message: struct in_addr *sources = (struct in_addr *)(query_buf + IGMP_V3_SOURCES_OFFSET); if (num_sources > 0) { struct listnode *node; struct igmp_source *src; int i = 0; for (ALL_LIST_ELEMENTS_RO(source_list, node, src)) { sources[i++] = src->source_addr; } } */ void pim_igmp_send_membership_query(struct igmp_group *group, int fd, const char *ifname, char *query_buf, int query_buf_size, int num_sources, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec, uint8_t s_flag, uint8_t querier_robustness_variable, uint16_t querier_query_interval) { ssize_t msg_size; uint8_t max_resp_code; uint8_t qqic; ssize_t sent; struct sockaddr_in to; socklen_t tolen; uint16_t checksum; zassert(num_sources >= 0); msg_size = IGMP_V3_SOURCES_OFFSET + (num_sources << 2); if (msg_size > query_buf_size) { zlog_err("%s %s: unable to send: msg_size=%zd larger than query_buf_size=%d", __FILE__, __PRETTY_FUNCTION__, msg_size, query_buf_size); return; } s_flag = PIM_FORCE_BOOLEAN(s_flag); zassert((s_flag == 0) || (s_flag == 1)); max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec); qqic = igmp_msg_encode16to8(querier_query_interval); /* RFC 3376: 4.1.6. QRV (Querier's Robustness Variable) If non-zero, the QRV field contains the [Robustness Variable] value used by the querier, i.e., the sender of the Query. If the querier's [Robustness Variable] exceeds 7, the maximum value of the QRV field, the QRV is set to zero. */ if (querier_robustness_variable > 7) { querier_robustness_variable = 0; } query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY; query_buf[1] = max_resp_code; *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ memcpy(query_buf+4, &group_addr, sizeof(struct in_addr)); query_buf[8] = (s_flag << 3) | querier_robustness_variable; query_buf[9] = qqic; *(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources); checksum = in_cksum(query_buf, msg_size); *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = checksum; if (PIM_DEBUG_IGMP_PACKETS) { char dst_str[100]; char group_str[100]; pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_debug("%s: to %s on %s: group=%s sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x checksum=%x", __PRETTY_FUNCTION__, dst_str, ifname, group_str, num_sources, msg_size, s_flag, querier_robustness_variable, querier_query_interval, qqic, checksum); } memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; to.sin_addr = dst_addr; tolen = sizeof(to); sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT, (struct sockaddr *)&to, tolen); if (sent != (ssize_t) msg_size) { int e = errno; char dst_str[100]; char group_str[100]; pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); if (sent < 0) { zlog_warn("%s: sendto() failure to %s on %s: group=%s msg_size=%zd: errno=%d: %s", __PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, e, safe_strerror(e)); } else { zlog_warn("%s: sendto() partial to %s on %s: group=%s msg_size=%zd: sent=%zd", __PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, sent); } return; } /* s_flag sanity test: s_flag must be set for general queries RFC 3376: 6.6.1. Timer Updates When a router sends or receives a query with a clear Suppress Router-Side Processing flag, it must update its timers to reflect the correct timeout values for the group or sources being queried. General queries don't trigger timer update. */ if (!s_flag) { /* general query? */ if (PIM_INADDR_IS_ANY(group_addr)) { char dst_str[100]; char group_str[100]; pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: to %s on %s: group=%s sources=%d: s_flag is clear for general query!", __PRETTY_FUNCTION__, dst_str, ifname, group_str, num_sources); } } } quagga-1.2.4/pimd/pim_igmpv3.h000066400000000000000000000072121325323223500161410ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IGMPV3_H #define PIM_IGMPV3_H #include #include "if.h" #define IGMP_V3_CHECKSUM_OFFSET (2) #define IGMP_V3_REPORT_NUMGROUPS_OFFSET (6) #define IGMP_V3_REPORT_GROUPPRECORD_OFFSET (8) #define IGMP_V3_NUMSOURCES_OFFSET (10) #define IGMP_V3_SOURCES_OFFSET (12) /* GMI: Group Membership Interval */ #define PIM_IGMP_GMI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * (qri_dsec)) /* OQPI: Other Querier Present Interval */ #define PIM_IGMP_OQPI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * ((qri_dsec) >> 1)) /* SQI: Startup Query Interval */ #define PIM_IGMP_SQI(qi) (((qi) < 4) ? 1 : ((qi) >> 2)) /* LMQT: Last Member Query Time */ #define PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc) ((lmqc) * (100 * (lmqi_dsec))) /* OHPI: Older Host Present Interval */ #define PIM_IGMP_OHPI_DSEC(qrv,qqi,qri_dsec) ((qrv) * (10 * (qqi)) + (qri_dsec)) void igmp_group_reset_gmi(struct igmp_group *group); void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group, struct igmp_source *source); void igmp_source_free(struct igmp_source *source); void igmp_source_delete(struct igmp_source *source); void igmp_source_delete_expired(struct list *source_list); int igmp_group_compat_mode(const struct igmp_sock *igmp, const struct igmp_group *group); void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmp_group_timer_lower_to_lmqt(struct igmp_group *group); void igmp_source_timer_lower_to_lmqt(struct igmp_source *source); struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, struct in_addr src_addr); void pim_igmp_send_membership_query(struct igmp_group *group, int fd, const char *ifname, char *query_buf, int query_buf_size, int num_sources, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec, uint8_t s_flag, uint8_t querier_robustness_variable, uint16_t querier_query_interval); #endif /* PIM_IGMPV3_H */ quagga-1.2.4/pimd/pim_int.c000066400000000000000000000024721325323223500155240ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include #include "pim_int.h" uint32_t pim_read_uint32_host(const uint8_t *buf) { uint32_t val; memcpy(&val, buf, sizeof(val)); /* val is in netorder */ val = ntohl(val); /* val is in hostorder */ return val; } void pim_write_uint32(uint8_t *buf, uint32_t val_host) { /* val_host is in host order */ val_host = htonl(val_host); /* val_host is in netorder */ memcpy(buf, &val_host, sizeof(val_host)); } quagga-1.2.4/pimd/pim_int.h000066400000000000000000000020001325323223500155140ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_INT_H #define PIM_INT_H #include uint32_t pim_read_uint32_host(const uint8_t *buf); void pim_write_uint32(uint8_t *buf, uint32_t val_host); #endif /* PIM_INT_H */ quagga-1.2.4/pimd/pim_join.c000066400000000000000000000316511325323223500156720ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "pimd.h" #include "pim_str.h" #include "pim_tlv.h" #include "pim_msg.h" #include "pim_pim.h" #include "pim_join.h" #include "pim_iface.h" #include "pim_hello.h" #include "pim_ifchannel.h" static void on_trace(const char *label, struct interface *ifp, struct in_addr src) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src, src_str, sizeof(src_str)); zlog_debug("%s: from %s on %s", label, src_str, ifp->name); } } static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, uint16_t holdtime, struct in_addr upstream, struct in_addr group, struct in_addr source, uint8_t source_flags) { if (PIM_DEBUG_PIM_TRACE) { char up_str[100]; char src_str[100]; char grp_str[100]; char neigh_str[100]; pim_inet4_dump("", upstream, up_str, sizeof(up_str)); pim_inet4_dump("", source, src_str, sizeof(src_str)); pim_inet4_dump("", group, grp_str, sizeof(grp_str)); pim_inet4_dump("", neigh->source_addr, neigh_str, sizeof(neigh_str)); zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", __PRETTY_FUNCTION__, src_str, grp_str, source_flags & PIM_RPT_BIT_MASK, source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime, neigh_str, ifp->name); } /* Restart join expiry timer */ pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, source, group, source_flags, holdtime); } static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, uint16_t holdtime, struct in_addr upstream, struct in_addr group, struct in_addr source, uint8_t source_flags) { if (PIM_DEBUG_PIM_TRACE) { char up_str[100]; char src_str[100]; char grp_str[100]; char neigh_str[100]; pim_inet4_dump("", upstream, up_str, sizeof(up_str)); pim_inet4_dump("", source, src_str, sizeof(src_str)); pim_inet4_dump("", group, grp_str, sizeof(grp_str)); pim_inet4_dump("", neigh->source_addr, neigh_str, sizeof(neigh_str)); zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", __PRETTY_FUNCTION__, src_str, grp_str, source_flags & PIM_RPT_BIT_MASK, source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime, neigh_str, ifp->name); } pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime); } int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) { struct prefix msg_upstream_addr; uint8_t msg_num_groups; uint16_t msg_holdtime; int addr_offset; uint8_t *buf; uint8_t *pastend; int remain; int group; on_trace(__PRETTY_FUNCTION__, ifp, src_addr); buf = tlv_buf; pastend = tlv_buf + tlv_buf_size; /* Parse ucast addr */ addr_offset = pim_parse_addr_ucast(ifp->name, src_addr, &msg_upstream_addr, buf, pastend - buf); #if 0 zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d", __PRETTY_FUNCTION__, addr_offset); #endif if (addr_offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", __PRETTY_FUNCTION__, src_str, ifp->name); return -1; } buf += addr_offset; /* Check upstream address family */ if (msg_upstream_addr.family != AF_INET) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", __PRETTY_FUNCTION__, msg_upstream_addr.family, src_str, ifp->name); } return -2; } remain = pastend - buf; if (remain < 4) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s", __PRETTY_FUNCTION__, remain, 4, src_str, ifp->name); return -4; } ++buf; /* skip reserved byte */ msg_num_groups = *(const uint8_t *) buf; ++buf; msg_holdtime = ntohs(*(const uint16_t *) buf); ++buf; ++buf; if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char upstream_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("", msg_upstream_addr.u.prefix4, upstream_str, sizeof(upstream_str)); zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s", __PRETTY_FUNCTION__, upstream_str, msg_num_groups, msg_holdtime, src_str, ifp->name); } /* Scan groups */ for (group = 0; group < msg_num_groups; ++group) { struct prefix msg_group_addr; struct prefix msg_source_addr; uint8_t msg_source_flags; uint16_t msg_num_joined_sources; uint16_t msg_num_pruned_sources; int source; addr_offset = pim_parse_addr_group(ifp->name, src_addr, &msg_group_addr, buf, pastend - buf); #if 0 zlog_warn("%s: pim_parse_addr_group addr_offset=%d", __PRETTY_FUNCTION__, addr_offset); #endif if (addr_offset < 1) { return -5; } buf += addr_offset; remain = pastend - buf; if (remain < 4) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s", __PRETTY_FUNCTION__, remain, 4, src_str, ifp->name); return -6; } msg_num_joined_sources = ntohs(*(const uint16_t *) buf); buf += 2; msg_num_pruned_sources = ntohs(*(const uint16_t *) buf); buf += 2; if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char upstream_str[100]; char group_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("", msg_upstream_addr.u.prefix4, upstream_str, sizeof(upstream_str)); pim_inet4_dump("", msg_group_addr.u.prefix4, group_str, sizeof(group_str)); zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s", __PRETTY_FUNCTION__, upstream_str, group_str, msg_group_addr.prefixlen, msg_num_joined_sources, msg_num_pruned_sources, src_str, ifp->name); } /* Scan joined sources */ for (source = 0; source < msg_num_joined_sources; ++source) { addr_offset = pim_parse_addr_source(ifp->name, src_addr, &msg_source_addr, &msg_source_flags, buf, pastend - buf); #if 0 zlog_warn("%s: pim_parse_addr_source addr_offset=%d", __PRETTY_FUNCTION__, addr_offset); #endif if (addr_offset < 1) { return -7; } buf += addr_offset; recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr.u.prefix4, msg_group_addr.u.prefix4, msg_source_addr.u.prefix4, msg_source_flags); } /* Scan pruned sources */ for (source = 0; source < msg_num_pruned_sources; ++source) { addr_offset = pim_parse_addr_source(ifp->name, src_addr, &msg_source_addr, &msg_source_flags, buf, pastend - buf); if (addr_offset < 1) { return -8; } buf += addr_offset; recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr.u.prefix4, msg_group_addr.u.prefix4, msg_source_addr.u.prefix4, msg_source_flags); } } /* scan groups */ return 0; } int pim_joinprune_send(struct interface *ifp, struct in_addr upstream_addr, struct in_addr source_addr, struct in_addr group_addr, int send_join) { struct pim_interface *pim_ifp; uint8_t pim_msg[1000]; const uint8_t *pastend = pim_msg + sizeof(pim_msg); uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */ int pim_msg_size; int remain; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; char dst_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s", __PRETTY_FUNCTION__, send_join ? "Join" : "Prune", source_str, group_str, dst_str, ifp->name); } if (PIM_INADDR_IS_ANY(upstream_addr)) { if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; char dst_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s", __PRETTY_FUNCTION__, send_join ? "Join" : "Prune", source_str, group_str, dst_str, ifp->name); } return 0; } /* RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ pim_hello_require(ifp); /* Build PIM message */ remain = pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, remain, upstream_addr); if (!pim_msg_curr) { char dst_str[100]; pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); zlog_warn("%s: failure encoding destination address %s: space left=%d", __PRETTY_FUNCTION__, dst_str, remain); return -3; } remain = pastend - pim_msg_curr; if (remain < 4) { zlog_warn("%s: group will not fit: space left=%d", __PRETTY_FUNCTION__, remain); return -4; } *pim_msg_curr = 0; /* reserved */ ++pim_msg_curr; *pim_msg_curr = 1; /* number of groups */ ++pim_msg_curr; *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME); ++pim_msg_curr; ++pim_msg_curr; remain = pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, remain, group_addr); if (!pim_msg_curr) { char group_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: failure encoding group address %s: space left=%d", __PRETTY_FUNCTION__, group_str, remain); return -5; } remain = pastend - pim_msg_curr; if (remain < 4) { zlog_warn("%s: sources will not fit: space left=%d", __PRETTY_FUNCTION__, remain); return -6; } /* number of joined sources */ *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0); ++pim_msg_curr; ++pim_msg_curr; /* number of pruned sources */ *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1); ++pim_msg_curr; ++pim_msg_curr; remain = pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr, remain, source_addr); if (!pim_msg_curr) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure encoding source address %s: space left=%d", __PRETTY_FUNCTION__, source_str, remain); return -7; } /* Add PIM header */ pim_msg_size = pim_msg_curr - pim_msg; pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_JOIN_PRUNE); if (pim_msg_send(pim_ifp->pim_sock_fd, qpim_all_pim_routers_addr, pim_msg, pim_msg_size, ifp->name)) { zlog_warn("%s: could not send PIM message on interface %s", __PRETTY_FUNCTION__, ifp->name); return -8; } return 0; } quagga-1.2.4/pimd/pim_join.h000066400000000000000000000024361325323223500156760ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_JOIN_H #define PIM_JOIN_H #include #include "if.h" #include "pim_neighbor.h" int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); int pim_joinprune_send(struct interface *ifp, struct in_addr upstream_addr, struct in_addr source_addr, struct in_addr group_addr, int send_join); #endif /* PIM_JOIN_H */ quagga-1.2.4/pimd/pim_macro.c000066400000000000000000000306171325323223500160350ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "pim_macro.h" #include "pimd.h" #include "pim_str.h" #include "pim_iface.h" #include "pim_ifchannel.h" #define PIM_IFP_I_am_DR(pim_ifp) ((pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr) /* DownstreamJPState(S,G,I) is the per-interface state machine for receiving (S,G) Join/Prune messages. DownstreamJPState(S,G,I) is either Join or Prune-Pending ? */ static int downstream_jpstate_isjoined(const struct pim_ifchannel *ch) { return ch->ifjoin_state != PIM_IFJOIN_NOINFO; } /* The clause "local_receiver_include(S,G,I)" is true if the IGMP/MLD module or other local membership mechanism has determined that local members on interface I desire to receive traffic sent specifically by S to G. */ static int local_receiver_include(const struct pim_ifchannel *ch) { /* local_receiver_include(S,G,I) ? */ return ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE; } /* RFC 4601: 4.1.6. State Summarization Macros The set "joins(S,G)" is the set of all interfaces on which the router has received (S,G) Joins: joins(S,G) = { all interfaces I such that DownstreamJPState(S,G,I) is either Join or Prune-Pending } DownstreamJPState(S,G,I) is either Join or Prune-Pending ? */ int pim_macro_chisin_joins(const struct pim_ifchannel *ch) { return downstream_jpstate_isjoined(ch); } /* RFC 4601: 4.6.5. Assert State Macros The set "lost_assert(S,G)" is the set of all interfaces on which the router has received (S,G) joins but has lost an (S,G) assert. lost_assert(S,G) = { all interfaces I such that lost_assert(S,G,I) == TRUE } bool lost_assert(S,G,I) { if ( RPF_interface(S) == I ) { return FALSE } else { return ( AssertWinner(S,G,I) != NULL AND AssertWinner(S,G,I) != me AND (AssertWinnerMetric(S,G,I) is better than spt_assert_metric(S,I) ) } } AssertWinner(S,G,I) is the IP source address of the Assert(S,G) packet that won an Assert. */ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch) { struct interface *ifp; struct pim_interface *pim_ifp; struct pim_assert_metric spt_assert_metric; ifp = ch->interface; if (!ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): null interface", __PRETTY_FUNCTION__, src_str, grp_str); return 0; /* false */ } /* RPF_interface(S) == I ? */ if (ch->upstream->rpf.source_nexthop.interface == ifp) return 0; /* false */ pim_ifp = ifp->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return 0; /* false */ } if (PIM_INADDR_IS_ANY(ch->ifassert_winner)) return 0; /* false */ /* AssertWinner(S,G,I) == me ? */ if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) return 0; /* false */ spt_assert_metric = pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); return pim_assert_metric_better(&ch->ifassert_winner_metric, &spt_assert_metric); } /* RFC 4601: 4.1.6. State Summarization Macros pim_include(S,G) = { all interfaces I such that: ( (I_am_DR( I ) AND lost_assert(S,G,I) == FALSE ) OR AssertWinner(S,G,I) == me ) AND local_receiver_include(S,G,I) } AssertWinner(S,G,I) is the IP source address of the Assert(S,G) packet that won an Assert. */ int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch) { struct pim_interface *pim_ifp = ch->interface->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name); return 0; /* false */ } /* local_receiver_include(S,G,I) ? */ if (!local_receiver_include(ch)) return 0; /* false */ /* OR AssertWinner(S,G,I) == me ? */ if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) return 1; /* true */ return ( /* I_am_DR( I ) ? */ PIM_IFP_I_am_DR(pim_ifp) && /* lost_assert(S,G,I) == FALSE ? */ (!pim_macro_ch_lost_assert(ch)) ); } int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch) { if (pim_macro_chisin_joins(ch)) return 1; /* true */ return pim_macro_chisin_pim_include(ch); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine CouldAssert(S,G,I) = SPTbit(S,G)==TRUE AND (RPF_interface(S) != I) AND (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) ) (+) ( pim_include(*,G) (-) pim_exclude(S,G) ) (-) lost_assert(*,G) (+) joins(S,G) (+) pim_include(S,G) ) ) CouldAssert(S,G,I) is true for downstream interfaces that would be in the inherited_olist(S,G) if (S,G) assert information was not taken into account. CouldAssert(S,G,I) may be affected by changes in the following: pim_ifp->primary_address pim_ifp->pim_dr_addr ch->ifassert_winner_metric ch->ifassert_winner ch->local_ifmembership ch->ifjoin_state ch->upstream->rpf.source_nexthop.mrib_metric_preference ch->upstream->rpf.source_nexthop.mrib_route_metric ch->upstream->rpf.source_nexthop.interface */ int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch) { struct interface *ifp; /* SPTbit(S,G) is always true for PIM-SSM-Only Routers */ ifp = ch->interface; if (!ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): null interface", __PRETTY_FUNCTION__, src_str, grp_str); return 0; /* false */ } /* RPF_interface(S) != I ? */ if (ch->upstream->rpf.source_nexthop.interface == ifp) return 0; /* false */ /* I in joins(S,G) (+) pim_include(S,G) ? */ return pim_macro_chisin_joins_or_include(ch); } /* RFC 4601: 4.6.3. Assert Metrics spt_assert_metric(S,I) gives the assert metric we use if we're sending an assert based on active (S,G) forwarding state: assert_metric spt_assert_metric(S,I) { return {0,MRIB.pref(S),MRIB.metric(S),my_ip_address(I)} } */ struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf, struct in_addr ifaddr) { struct pim_assert_metric metric; metric.rpt_bit_flag = 0; metric.metric_preference = rpf->source_nexthop.mrib_metric_preference; metric.route_metric = rpf->source_nexthop.mrib_route_metric; metric.ip_address = ifaddr; return metric; } /* RFC 4601: 4.6.3. Assert Metrics An assert metric for (S,G) to include in (or compare against) an Assert message sent on interface I should be computed using the following pseudocode: assert_metric my_assert_metric(S,G,I) { if( CouldAssert(S,G,I) == TRUE ) { return spt_assert_metric(S,I) } else if( CouldAssert(*,G,I) == TRUE ) { return rpt_assert_metric(G,I) } else { return infinite_assert_metric() } } */ struct pim_assert_metric pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch) { struct pim_interface *pim_ifp; pim_ifp = ch->interface->info; if (pim_ifp) { if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { return pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); } } return qpim_infinite_assert_metric; } /* RFC 4601 4.2. Data Packet Forwarding Rules RFC 4601 4.8.2. PIM-SSM-Only Routers Macro: inherited_olist(S,G) = joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) */ static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel *ch) { if (pim_macro_ch_lost_assert(ch)) return 0; /* false */ return pim_macro_chisin_joins_or_include(ch); } /* RFC 4601 4.2. Data Packet Forwarding Rules RFC 4601 4.8.2. PIM-SSM-Only Routers Additionally, the Packet forwarding rules of Section 4.2 can be simplified in a PIM-SSM-only router: iif is the incoming interface of the packet. oiflist = NULL if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) { oiflist = inherited_olist(S,G) } else if (iif is in inherited_olist(S,G)) { send Assert(S,G) on iif } oiflist = oiflist (-) iif forward packet on all interfaces in oiflist Macro: inherited_olist(S,G) = joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) Note: - The following test is performed as response to WRONGVIF kernel upcall: if (iif is in inherited_olist(S,G)) { send Assert(S,G) on iif } See pim_mroute.c mroute_msg(). */ int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch) { if (ch->upstream->join_state != PIM_UPSTREAM_JOINED) { /* oiflist is NULL */ return 0; /* false */ } /* oiflist = oiflist (-) iif */ if (ch->interface == ch->upstream->rpf.source_nexthop.interface) return 0; /* false */ return pim_macro_chisin_inherited_olist(ch); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine AssertTrackingDesired(S,G,I) = (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) ) (+) ( pim_include(*,G) (-) pim_exclude(S,G) ) (-) lost_assert(*,G) (+) joins(S,G) ) ) OR (local_receiver_include(S,G,I) == TRUE AND (I_am_DR(I) OR (AssertWinner(S,G,I) == me))) OR ((RPF_interface(S) == I) AND (JoinDesired(S,G) == TRUE)) OR ((RPF_interface(RP(G)) == I) AND (JoinDesired(*,G) == TRUE) AND (SPTbit(S,G) == FALSE)) AssertTrackingDesired(S,G,I) is true on any interface in which an (S,G) assert might affect our behavior. */ int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch) { struct pim_interface *pim_ifp; struct interface *ifp; ifp = ch->interface; if (!ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): null interface", __PRETTY_FUNCTION__, src_str, grp_str); return 0; /* false */ } pim_ifp = ifp->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name); return 0; /* false */ } /* I in joins(S,G) ? */ if (pim_macro_chisin_joins(ch)) return 1; /* true */ /* local_receiver_include(S,G,I) ? */ if (local_receiver_include(ch)) { /* I_am_DR(I) ? */ if (PIM_IFP_I_am_DR(pim_ifp)) return 1; /* true */ /* AssertWinner(S,G,I) == me ? */ if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) return 1; /* true */ } /* RPF_interface(S) == I ? */ if (ch->upstream->rpf.source_nexthop.interface == ifp) { /* JoinDesired(S,G) ? */ if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags)) return 1; /* true */ } return 0; /* false */ } quagga-1.2.4/pimd/pim_macro.h000066400000000000000000000032021325323223500160300ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_MACRO_H #define PIM_MACRO_H #include #include "if.h" #include "pim_upstream.h" #include "pim_ifchannel.h" int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch); int pim_macro_chisin_joins(const struct pim_ifchannel *ch); int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch); int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch); int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch); struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf, struct in_addr ifaddr); struct pim_assert_metric pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch); int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch); int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch); #endif /* PIM_MACRO_H */ quagga-1.2.4/pimd/pim_main.c000066400000000000000000000151101325323223500156470ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "privs.h" #include "version.h" #include #include "command.h" #include "thread.h" #include #include "memory.h" #include "vrf.h" #include "filter.h" #include "vty.h" #include "sigevent.h" #include "version.h" #include "prefix.h" #include "plist.h" #include "pimd.h" #include "pim_version.h" #include "pim_signals.h" #include "pim_zebra.h" #ifdef PIM_ZCLIENT_DEBUG extern int zclient_debug; #endif extern struct host host; char config_default[] = SYSCONFDIR PIMD_DEFAULT_CONFIG; 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'}, { "debug_zclient", no_argument, NULL, 'Z'}, { "help", no_argument, NULL, 'h'}, { 0 } }; /* pimd privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, }; /* pimd privileges to run with */ struct zebra_privs_t pimd_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), .cap_num_i = 0 }; char* progname; const char *pid_file = PATH_PIMD_PID; static void usage(int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\ Daemon which manages PIM.\n\n\ -d, --daemon Run in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\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\ " #ifdef PIM_ZCLIENT_DEBUG "\ -Z, --debug_zclient Enable zclient debugging\n\ " #endif "\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, PIMD_BUG_ADDRESS); } exit (status); } int main(int argc, char** argv, char** envp) { char *p; char *vty_addr = NULL; int vty_port = -1; int daemon_mode = 0; char *config_file = NULL; char *zebra_sock_path = NULL; umask(0027); progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog(progname, ZLOG_PIM, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* this while just reads the options */ while (1) { int opt; opt = getopt_long (argc, argv, "df:i:z:A:P:vZh", 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 'z': zebra_sock_path = optarg; break; case 'A': vty_addr = optarg; break; case 'P': vty_port = atoi (optarg); break; case 'v': printf(PIMD_PROGNAME " version %s\n", PIMD_VERSION); print_version(QUAGGA_PROGNAME); exit (0); break; #ifdef PIM_ZCLIENT_DEBUG case 'Z': zclient_debug = 1; break; #endif case 'h': usage (0); break; default: usage (1); break; } } master = thread_master_create(); zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting", QUAGGA_VERSION, PIMD_VERSION); /* * Initializations */ zprivs_init (&pimd_privs); pim_signals_init(); cmd_init(1); vty_init(master); memory_init(); vrf_init(); access_list_init(); prefix_list_init (); pim_route_map_init (); pim_init(); /* * Initialize zclient "update" and "lookup" sockets */ pim_zebra_init (master, zebra_sock_path); zlog_notice("Loading configuration - begin"); /* Get configuration file. */ vty_read_config(config_file, config_default); /* Starting from here zlog_* functions will log according configuration */ zlog_notice("Loading configuration - end"); /* Change to the daemon program. */ if (daemon_mode) { if (daemon(0, 0)) { zlog_warn("failed to daemonize"); } } /* Process ID file creation. */ pid_output(pid_file); /* Create pimd VTY socket */ if (vty_port < 0) vty_port = PIMD_VTY_PORT; vty_serv_sock(vty_addr, vty_port, PIM_VTYSH_PATH); zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting, VTY interface at port TCP %d", QUAGGA_VERSION, PIMD_VERSION, vty_port); #ifdef PIM_DEBUG_BYDEFAULT zlog_notice("PIM_DEBUG_BYDEFAULT: Enabling all debug commands"); PIM_DO_DEBUG_PIM_EVENTS; PIM_DO_DEBUG_PIM_PACKETS; PIM_DO_DEBUG_PIM_TRACE; PIM_DO_DEBUG_IGMP_EVENTS; PIM_DO_DEBUG_IGMP_PACKETS; PIM_DO_DEBUG_IGMP_TRACE; PIM_DO_DEBUG_ZEBRA; #endif #ifdef PIM_ZCLIENT_DEBUG zlog_notice("PIM_ZCLIENT_DEBUG: zclient debugging is supported, mode is %s (see option -Z)", zclient_debug ? "ON" : "OFF"); #endif #ifdef PIM_CHECK_RECV_IFINDEX_SANITY zlog_notice("PIM_CHECK_RECV_IFINDEX_SANITY: will match sock/recv ifindex"); #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH zlog_notice("PIM_REPORT_RECV_IFINDEX_MISMATCH: will report sock/recv ifindex mismatch"); #endif #endif #ifdef PIM_UNEXPECTED_KERNEL_UPCALL zlog_notice("PIM_UNEXPECTED_KERNEL_UPCALL: report unexpected kernel upcall"); #endif #ifdef HAVE_CLOCK_MONOTONIC zlog_notice("HAVE_CLOCK_MONOTONIC"); #else zlog_notice("!HAVE_CLOCK_MONOTONIC"); #endif thread_main (master); zlog_err("%s %s: thread_fetch() returned NULL, exiting", __FILE__, __PRETTY_FUNCTION__); /* never reached */ return 0; } quagga-1.2.4/pimd/pim_mroute.c000066400000000000000000000262501325323223500162450ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "privs.h" #include "pimd.h" #include "pim_mroute.h" #include "pim_str.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_macro.h" /* GLOBAL VARS */ extern struct zebra_privs_t pimd_privs; static void mroute_read_on(void); static int pim_mroute_set(int fd, int enable) { int err; int opt = enable ? MRT_INIT : MRT_DONE; socklen_t opt_len = sizeof(opt); err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e)); errno = e; return -1; } #if 0 zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok", __FILE__, __PRETTY_FUNCTION__, fd, opt); #endif return 0; } int pim_mroute_msg(int fd, const char *buf, int buf_size) { struct interface *ifp; const struct ip *ip_hdr; const struct igmpmsg *msg; const char *upcall; char src_str[100]; char grp_str[100]; ip_hdr = (const struct ip *) buf; /* kernel upcall must have protocol=0 */ if (ip_hdr->ip_p) { /* this is not a kernel upcall */ #ifdef PIM_UNEXPECTED_KERNEL_UPCALL zlog_warn("%s: not a kernel upcall proto=%d msg_size=%d", __PRETTY_FUNCTION__, ip_hdr->ip_p, buf_size); #endif return 0; } msg = (const struct igmpmsg *) buf; switch (msg->im_msgtype) { case IGMPMSG_NOCACHE: upcall = "NOCACHE"; break; case IGMPMSG_WRONGVIF: upcall = "WRONGVIF"; break; case IGMPMSG_WHOLEPKT: upcall = "WHOLEPKT"; break; default: upcall = ""; } ifp = pim_if_find_by_vif_index(msg->im_vif); pim_inet4_dump("", msg->im_src, src_str, sizeof(src_str)); pim_inet4_dump("", msg->im_dst, grp_str, sizeof(grp_str)); if (msg->im_msgtype == IGMPMSG_WRONGVIF) { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; /* Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. RFC 4601 4.8.2. PIM-SSM-Only Routers iif is the incoming interface of the packet. if (iif is in inherited_olist(S,G)) { send Assert(S,G) on iif } */ if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: WRONGVIF from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", __PRETTY_FUNCTION__, fd, src_str, grp_str, ifp ? ifp->name : "", msg->im_vif); } if (!ifp) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d", __PRETTY_FUNCTION__, src_str, grp_str, msg->im_vif); return -1; } pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -2; } ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst); if (!ch) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -3; } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine Transitions from NoInfo State An (S,G) data packet arrives on interface I, AND CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an downstream interface that is in our (S,G) outgoing interface list. We optimistically assume that we will be the assert winner for this (S,G), and so we transition to the "I am Assert Winner" state and perform Actions A1 (below), which will initiate the assert negotiation for (S,G). */ if (ch->ifassert_state != PIM_IFASSERT_NOINFO) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -4; } if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -5; } if (assert_action_a1(ch)) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -6; } return 0; } /* IGMPMSG_WRONGVIF */ zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", __PRETTY_FUNCTION__, upcall, msg->im_msgtype, ip_hdr->ip_p, fd, src_str, grp_str, ifp ? ifp->name : "", msg->im_vif); return 0; } static int mroute_read_msg(int fd) { const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg)); char buf[1000]; int rd; if (((int) sizeof(buf)) < msg_min_size) { zlog_err("%s: fd=%d: buf size=%zu lower than msg_min=%d", __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size); return -1; } rd = read(fd, buf, sizeof(buf)); if (rd < 0) { zlog_warn("%s: failure reading fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); return -2; } if (rd < msg_min_size) { zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d", __PRETTY_FUNCTION__, fd, rd, msg_min_size); return -3; } return pim_mroute_msg(fd, buf, rd); } static int mroute_read(struct thread *t) { int fd; int result; zassert(t); zassert(!THREAD_ARG(t)); fd = THREAD_FD(t); zassert(fd == qpim_mroute_socket_fd); result = mroute_read_msg(fd); /* Keep reading */ qpim_mroute_socket_reader = 0; mroute_read_on(); return result; } static void mroute_read_on() { zassert(!qpim_mroute_socket_reader); zassert(PIM_MROUTE_IS_ENABLED); THREAD_READ_ON(master, qpim_mroute_socket_reader, mroute_read, 0, qpim_mroute_socket_fd); } static void mroute_read_off() { THREAD_OFF(qpim_mroute_socket_reader); } int pim_mroute_socket_enable() { int fd; if (PIM_MROUTE_IS_ENABLED) return -1; if ( pimd_privs.change (ZPRIVS_RAISE) ) zlog_err ("pim_mroute_socket_enable: could not raise privs, %s", safe_strerror (errno) ); fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); if ( pimd_privs.change (ZPRIVS_LOWER) ) zlog_err ("pim_mroute_socket_enable: could not lower privs, %s", safe_strerror (errno) ); if (fd < 0) { zlog_warn("Could not create mroute socket: errno=%d: %s", errno, safe_strerror(errno)); return -2; } if (pim_mroute_set(fd, 1)) { zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return -3; } qpim_mroute_socket_fd = fd; qpim_mroute_socket_creation = pim_time_monotonic_sec(); mroute_read_on(); zassert(PIM_MROUTE_IS_ENABLED); return 0; } int pim_mroute_socket_disable() { if (PIM_MROUTE_IS_DISABLED) return -1; if (pim_mroute_set(qpim_mroute_socket_fd, 0)) { zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s", qpim_mroute_socket_fd, errno, safe_strerror(errno)); return -2; } if (close(qpim_mroute_socket_fd)) { zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s", qpim_mroute_socket_fd, errno, safe_strerror(errno)); return -3; } mroute_read_off(); qpim_mroute_socket_fd = -1; zassert(PIM_MROUTE_IS_DISABLED); return 0; } /* For each network interface (e.g., physical or a virtual tunnel) that would be used for multicast forwarding, a corresponding multicast interface must be added to the kernel. */ int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) { struct vifctl vc; int err; if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); return -1; } memset(&vc, 0, sizeof(vc)); vc.vifc_vifi = vif_index; vc.vifc_flags = 0; vc.vifc_threshold = PIM_MROUTE_MIN_TTL; vc.vifc_rate_limit = 0; memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr)); #ifdef PIM_DVMRP_TUNNEL if (vc.vifc_flags & VIFF_TUNNEL) { memcpy(&vc.vifc_rmt_addr, &vif_remote_addr, sizeof(vc.vifc_rmt_addr)); } #endif err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc)); if (err) { char ifaddr_str[100]; int e = errno; pim_inet4_dump("", ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, vif_index, ifaddr_str, e, safe_strerror(e)); errno = e; return -2; } return 0; } int pim_mroute_del_vif(int vif_index) { struct vifctl vc; int err; if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); return -1; } memset(&vc, 0, sizeof(vc)); vc.vifc_vifi = vif_index; err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc)); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, vif_index, e, safe_strerror(e)); errno = e; return -2; } return 0; } int pim_mroute_add(struct mfcctl *mc) { int err; qpim_mroute_add_last = pim_time_monotonic_sec(); ++qpim_mroute_add_events; if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); return -1; } err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC, mc, sizeof(*mc)); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, e, safe_strerror(e)); errno = e; return -2; } return 0; } int pim_mroute_del(struct mfcctl *mc) { int err; qpim_mroute_del_last = pim_time_monotonic_sec(); ++qpim_mroute_del_events; if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); return -1; } err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, mc, sizeof(*mc)); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, e, safe_strerror(e)); errno = e; return -2; } return 0; } quagga-1.2.4/pimd/pim_mroute.h000066400000000000000000000120121325323223500162410ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_MROUTE_H #define PIM_MROUTE_H /* For msghdr.msg_control in Solaris 10 */ #ifndef _XPG4_2 #define _XPG4_2 #endif #ifndef __EXTENSIONS__ #define __EXTENSIONS__ #endif #include #ifdef HAVE_NETINET_IP_MROUTE_H #include #endif #define PIM_MROUTE_MIN_TTL (1) #if defined(HAVE_LINUX_MROUTE_H) #include #else /* Below: from */ #ifndef MAXVIFS #define MAXVIFS (32) #endif #ifndef SIOCGETVIFCNT #define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ #define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) #define SIOCGETRPF (SIOCPROTOPRIVATE+2) #endif #ifndef MRT_INIT #define MRT_BASE 200 #define MRT_INIT (MRT_BASE) /* Activate the kernel mroute code */ #define MRT_DONE (MRT_BASE+1) /* Shutdown the kernel mroute */ #define MRT_ADD_VIF (MRT_BASE+2) /* Add a virtual interface */ #define MRT_DEL_VIF (MRT_BASE+3) /* Delete a virtual interface */ #define MRT_ADD_MFC (MRT_BASE+4) /* Add a multicast forwarding entry */ #define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */ #define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */ #define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ #define MRT_PIM (MRT_BASE+8) /* enable PIM code */ #endif #ifndef HAVE_VIFI_T typedef unsigned short vifi_t; #endif #ifndef HAVE_STRUCT_VIFCTL struct vifctl { vifi_t vifc_vifi; /* Index of VIF */ unsigned char vifc_flags; /* VIFF_ flags */ unsigned char vifc_threshold; /* ttl limit */ unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ struct in_addr vifc_lcl_addr; /* Our address */ struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */ }; #endif #ifndef HAVE_STRUCT_MFCCTL struct mfcctl { struct in_addr mfcc_origin; /* Origin of mcast */ struct in_addr mfcc_mcastgrp; /* Group in question */ vifi_t mfcc_parent; /* Where it arrived */ unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going */ unsigned int mfcc_pkt_cnt; /* pkt count for src-grp */ unsigned int mfcc_byte_cnt; unsigned int mfcc_wrong_if; int mfcc_expire; }; #endif /* * Group count retrieval for mrouted */ /* struct sioc_sg_req sgreq; memset(&sgreq, 0, sizeof(sgreq)); memcpy(&sgreq.src, &source_addr, sizeof(sgreq.src)); memcpy(&sgreq.grp, &group_addr, sizeof(sgreq.grp)); ioctl(mrouter_s4, SIOCGETSGCNT, &sgreq); */ #ifndef HAVE_STRUCT_SIOC_SG_REQ struct sioc_sg_req { struct in_addr src; struct in_addr grp; unsigned long pktcnt; unsigned long bytecnt; unsigned long wrong_if; }; #endif /* * To get vif packet counts */ /* struct sioc_vif_req vreq; memset(&vreq, 0, sizeof(vreq)); vreq.vifi = vif_index; ioctl(mrouter_s4, SIOCGETVIFCNT, &vreq); */ #ifndef HAVE_STRUCT_SIOC_VIF_REQ struct sioc_vif_req { vifi_t vifi; /* Which iface */ unsigned long icount; /* In packets */ unsigned long ocount; /* Out packets */ unsigned long ibytes; /* In bytes */ unsigned long obytes; /* Out bytes */ }; #endif /* * Pseudo messages used by mrouted */ #ifndef IGMPMSG_NOCACHE #define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */ #define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */ #define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ #endif #ifndef HAVE_STRUCT_IGMPMSG struct igmpmsg { uint32_t unused1,unused2; unsigned char im_msgtype; /* What is this */ unsigned char im_mbz; /* Must be zero */ unsigned char im_vif; /* Interface (this ought to be a vifi_t!) */ unsigned char unused3; struct in_addr im_src,im_dst; }; #endif #endif /* Above: from */ int pim_mroute_socket_enable(void); int pim_mroute_socket_disable(void); int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr); int pim_mroute_del_vif(int vif_index); int pim_mroute_add(struct mfcctl *mc); int pim_mroute_del(struct mfcctl *mc); int pim_mroute_msg(int fd, const char *buf, int buf_size); #endif /* PIM_MROUTE_H */ quagga-1.2.4/pimd/pim_msg.c000066400000000000000000000054571325323223500155260ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "pimd.h" #include "pim_pim.h" #include "pim_msg.h" #include "pim_util.h" void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, uint8_t pim_msg_type) { uint16_t checksum; zassert(pim_msg_size >= PIM_PIM_MIN_LEN); /* * Write header */ *(uint8_t *) PIM_MSG_HDR_OFFSET_VERSION(pim_msg) = (PIM_PROTO_VERSION << 4) | pim_msg_type; *(uint8_t *) PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) = 0; /* * Compute checksum */ *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; checksum = in_cksum(pim_msg, pim_msg_size); *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum; } uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, int buf_size, struct in_addr addr) { const int ENCODED_IPV4_UCAST_SIZE = 6; if (buf_size < ENCODED_IPV4_UCAST_SIZE) { return 0; } buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ memcpy(buf+2, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_UCAST_SIZE; } uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, int buf_size, struct in_addr addr) { const int ENCODED_IPV4_GROUP_SIZE = 8; if (buf_size < ENCODED_IPV4_GROUP_SIZE) { return 0; } buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ buf[2] = '\0'; /* reserved */ buf[3] = 32; /* mask len */ memcpy(buf+4, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_GROUP_SIZE; } uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size, struct in_addr addr) { const int ENCODED_IPV4_SOURCE_SIZE = 8; if (buf_size < ENCODED_IPV4_SOURCE_SIZE) { return 0; } buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ buf[2] = 4; /* reserved = 0 | S bit = 1 | W bit = 0 | R bit = 0 */ buf[3] = 32; /* mask len */ memcpy(buf+4, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_SOURCE_SIZE; } quagga-1.2.4/pimd/pim_msg.h000066400000000000000000000030621325323223500155210ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_MSG_H #define PIM_MSG_H #include /* Number Description ---------- ------------------ 0 Reserved 1 IP (IP version 4) 2 IP6 (IP version 6) From: http://www.iana.org/assignments/address-family-numbers */ #define PIM_MSG_ADDRESS_FAMILY_IPV4 (1) void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, uint8_t pim_msg_type); uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, int buf_size, struct in_addr addr); uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, int buf_size, struct in_addr addr); uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size, struct in_addr addr); #endif /* PIM_MSG_H */ quagga-1.2.4/pimd/pim_neighbor.c000066400000000000000000000467771325323223500165470ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "memory.h" #include "pimd.h" #include "pim_neighbor.h" #include "pim_time.h" #include "pim_str.h" #include "pim_iface.h" #include "pim_pim.h" #include "pim_upstream.h" #include "pim_ifchannel.h" static void dr_election_by_addr(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct pim_neighbor *neigh; pim_ifp = ifp->info; zassert(pim_ifp); pim_ifp->pim_dr_addr = pim_ifp->primary_address; if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: on interface %s", __PRETTY_FUNCTION__, ifp->name); } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) { pim_ifp->pim_dr_addr = neigh->source_addr; } } } static void dr_election_by_pri(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct pim_neighbor *neigh; uint32_t dr_pri; pim_ifp = ifp->info; zassert(pim_ifp); pim_ifp->pim_dr_addr = pim_ifp->primary_address; dr_pri = pim_ifp->pim_dr_priority; if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: dr pri %u on interface %s", __PRETTY_FUNCTION__, dr_pri, ifp->name); } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (PIM_DEBUG_PIM_TRACE) { zlog_info("%s: neigh pri %u addr %x if dr addr %x", __PRETTY_FUNCTION__, neigh->dr_priority, ntohl(neigh->source_addr.s_addr), ntohl(pim_ifp->pim_dr_addr.s_addr)); } if ( (neigh->dr_priority > dr_pri) || ( (neigh->dr_priority == dr_pri) && (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) ) ) { pim_ifp->pim_dr_addr = neigh->source_addr; dr_pri = neigh->dr_priority; } } } /* RFC 4601: 4.3.2. DR Election A router's idea of the current DR on an interface can change when a PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ int pim_if_dr_election(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct in_addr old_dr_addr; ++pim_ifp->pim_dr_election_count; old_dr_addr = pim_ifp->pim_dr_addr; if (pim_ifp->pim_dr_num_nondrpri_neighbors) { dr_election_by_addr(ifp); } else { dr_election_by_pri(ifp); } /* DR changed ? */ if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { if (PIM_DEBUG_PIM_EVENTS) { char dr_old_str[100]; char dr_new_str[100]; pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); zlog_debug("%s: DR was %s now is %s on interface %s", __PRETTY_FUNCTION__, dr_old_str, dr_new_str, ifp->name); } pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ ++pim_ifp->pim_dr_election_changes; pim_if_update_join_desired(pim_ifp); pim_if_update_could_assert(ifp); pim_if_update_assert_tracking_desired(ifp); return 1; } return 0; } static void update_dr_priority(struct pim_neighbor *neigh, pim_hello_options hello_options, uint32_t dr_priority) { pim_hello_options will_set_pri; /* boolean */ pim_hello_options bit_flip; /* boolean */ pim_hello_options pri_change; /* boolean */ will_set_pri = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY); bit_flip = ( will_set_pri != PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY) ); if (bit_flip) { struct pim_interface *pim_ifp = neigh->interface->info; /* update num. of neighbors without dr_pri */ if (will_set_pri) { --pim_ifp->pim_dr_num_nondrpri_neighbors; } else { ++pim_ifp->pim_dr_num_nondrpri_neighbors; } } pri_change = ( bit_flip || (neigh->dr_priority != dr_priority) ); if (will_set_pri) { neigh->dr_priority = dr_priority; } else { neigh->dr_priority = 0; /* cosmetic unset */ } if (pri_change) { /* RFC 4601: 4.3.2. DR Election A router's idea of the current DR on an interface can change when a PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ pim_if_dr_election(neigh->interface); // router's own DR Priority changes } } static int on_neighbor_timer(struct thread *t) { struct pim_neighbor *neigh; struct interface *ifp; char msg[100]; zassert(t); neigh = THREAD_ARG(t); zassert(neigh); ifp = neigh->interface; if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s", neigh->holdtime, src_str, ifp->name); } neigh->t_expire_timer = 0; snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime); pim_neighbor_delete(ifp, neigh, msg); /* RFC 4601: 4.3.2. DR Election A router's idea of the current DR on an interface can change when a PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ pim_if_dr_election(ifp); // neighbor times out return 0; } static void neighbor_timer_off(struct pim_neighbor *neigh) { if (PIM_DEBUG_PIM_TRACE) { if (neigh->t_expire_timer) { char src_str[100]; pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); zlog_debug("%s: cancelling timer for neighbor %s on %s", __PRETTY_FUNCTION__, src_str, neigh->interface->name); } } THREAD_OFF(neigh->t_expire_timer); zassert(!neigh->t_expire_timer); } void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime) { neigh->holdtime = holdtime; neighbor_timer_off(neigh); /* 0xFFFF is request for no holdtime */ if (neigh->holdtime == 0xFFFF) { return; } if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); zlog_debug("%s: starting %u sec timer for neighbor %s on %s", __PRETTY_FUNCTION__, neigh->holdtime, src_str, neigh->interface->name); } THREAD_TIMER_ON(master, neigh->t_expire_timer, on_neighbor_timer, neigh, neigh->holdtime); } static struct pim_neighbor *pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, struct list *addr_list) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; char src_str[100]; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh)); if (!neigh) { zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*neigh)); return 0; } neigh->creation = pim_time_monotonic_sec(); neigh->source_addr = source_addr; neigh->hello_options = hello_options; neigh->propagation_delay_msec = propagation_delay; neigh->override_interval_msec = override_interval; neigh->dr_priority = dr_priority; neigh->generation_id = generation_id; neigh->prefix_list = addr_list; neigh->t_expire_timer = 0; neigh->interface = ifp; pim_neighbor_timer_reset(neigh, holdtime); pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("%s: creating PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s", src_str, ifp->name); if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) { pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec; } if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) { pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec; } if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { /* update num. of neighbors without hello option lan_delay */ ++pim_ifp->pim_number_of_nonlandelay_neighbors; } if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)) { /* update num. of neighbors without hello option dr_pri */ ++pim_ifp->pim_dr_num_nondrpri_neighbors; } return neigh; } static void delete_prefix_list(struct pim_neighbor *neigh) { if (neigh->prefix_list) { #ifdef DUMP_PREFIX_LIST struct listnode *p_node; struct prefix *p; char addr_str[10]; int list_size = neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1; int i = 0; for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) { pim_inet4_dump("", p->u.prefix4, addr_str, sizeof(addr_str)); zlog_debug("%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]", __PRETTY_FUNCTION__, (unsigned) neigh, (unsigned) neigh->prefix_list, (unsigned) p, addr_str, i, list_size); ++i; } #endif list_delete(neigh->prefix_list); neigh->prefix_list = 0; } } void pim_neighbor_free(struct pim_neighbor *neigh) { zassert(!neigh->t_expire_timer); delete_prefix_list(neigh); XFREE(MTYPE_PIM_NEIGHBOR, neigh); } struct pim_neighbor *pim_neighbor_find(struct interface *ifp, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct listnode *node; struct pim_neighbor *neigh; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (source_addr.s_addr == neigh->source_addr.s_addr) { return neigh; } } return 0; } struct pim_neighbor *pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, struct list *addr_list) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; neigh = pim_neighbor_new(ifp, source_addr, hello_options, holdtime, propagation_delay, override_interval, dr_priority, generation_id, addr_list); if (!neigh) { return 0; } pim_ifp = ifp->info; zassert(pim_ifp); listnode_add(pim_ifp->pim_neighbor_list, neigh); /* RFC 4601: 4.3.2. DR Election A router's idea of the current DR on an interface can change when a PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election... /* RFC 4601: 4.3.1. Sending Hello Messages To allow new or rebooting routers to learn of PIM neighbors quickly, when a Hello message is received from a new neighbor, or a Hello message with a new GenID is received from an existing neighbor, a new Hello message should be sent on this interface after a randomized delay between 0 and Triggered_Hello_Delay. */ pim_hello_restart_triggered(neigh->interface); return neigh; } static uint16_t find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp, struct pim_neighbor *highest_neigh) { struct pim_interface *pim_ifp; struct listnode *neigh_node; struct pim_neighbor *neigh; uint16_t next_highest_delay_msec; pim_ifp = ifp->info; zassert(pim_ifp); next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { if (neigh == highest_neigh) continue; if (neigh->propagation_delay_msec > next_highest_delay_msec) next_highest_delay_msec = neigh->propagation_delay_msec; } return next_highest_delay_msec; } static uint16_t find_neighbors_next_highest_override_interval_msec(struct interface *ifp, struct pim_neighbor *highest_neigh) { struct pim_interface *pim_ifp; struct listnode *neigh_node; struct pim_neighbor *neigh; uint16_t next_highest_interval_msec; pim_ifp = ifp->info; zassert(pim_ifp); next_highest_interval_msec = pim_ifp->pim_override_interval_msec; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { if (neigh == highest_neigh) continue; if (neigh->override_interval_msec > next_highest_interval_msec) next_highest_interval_msec = neigh->override_interval_msec; } return next_highest_interval_msec; } void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, const char *delete_message) { struct pim_interface *pim_ifp; char src_str[100]; pim_ifp = ifp->info; zassert(pim_ifp); pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", src_str, ifp->name, delete_message); neighbor_timer_off(neigh); pim_if_assert_on_neighbor_down(ifp, neigh->source_addr); if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { /* update num. of neighbors without hello option lan_delay */ --pim_ifp->pim_number_of_nonlandelay_neighbors; } if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)) { /* update num. of neighbors without dr_pri */ --pim_ifp->pim_dr_num_nondrpri_neighbors; } zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec); zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec); if (pim_if_lan_delay_enabled(ifp)) { /* will delete a neighbor with highest propagation delay? */ if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) { /* then find the next highest propagation delay */ pim_ifp->pim_neighbors_highest_propagation_delay_msec = find_neighbors_next_highest_propagation_delay_msec(ifp, neigh); } /* will delete a neighbor with highest override interval? */ if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) { /* then find the next highest propagation delay */ pim_ifp->pim_neighbors_highest_override_interval_msec = find_neighbors_next_highest_override_interval_msec(ifp, neigh); } } if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: deleting PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } listnode_delete(pim_ifp->pim_neighbor_list, neigh); pim_neighbor_free(neigh); } void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message) { struct pim_interface *pim_ifp; struct listnode *neigh_node; struct listnode *neigh_nextnode; struct pim_neighbor *neigh; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node, neigh_nextnode, neigh)) { pim_neighbor_delete(ifp, neigh, delete_message); } } struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, struct in_addr addr) { struct listnode *node; struct prefix *p; if (!neigh->prefix_list) return 0; for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) { if (p->family == AF_INET) { if (addr.s_addr == p->u.prefix4.s_addr) { return p; } } } return 0; } /* RFC 4601: 4.3.4. Maintaining Secondary Address Lists All the advertised secondary addresses in received Hello messages must be checked against those previously advertised by all other PIM neighbors on that interface. If there is a conflict and the same secondary address was previously advertised by another neighbor, then only the most recently received mapping MUST be maintained, and an error message SHOULD be logged to the administrator in a rate-limited manner. */ static void delete_from_neigh_addr(struct interface *ifp, struct list *addr_list, struct in_addr neigh_addr) { struct listnode *addr_node; struct prefix *addr; struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(pim_ifp); zassert(addr_list); /* Scan secondary address list */ for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, addr)) { struct listnode *neigh_node; struct pim_neighbor *neigh; if (addr->family != AF_INET) continue; /* Scan neighbors */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { { struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4); if (p) { char addr_str[100]; char this_neigh_str[100]; char other_neigh_str[100]; pim_inet4_dump("", addr->u.prefix4, addr_str, sizeof(addr_str)); pim_inet4_dump("", neigh_addr, this_neigh_str, sizeof(this_neigh_str)); pim_inet4_dump("", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str)); zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s", addr_str, this_neigh_str, other_neigh_str, ifp->name); listnode_delete(neigh->prefix_list, p); prefix_free(p); } } } /* scan neighbors */ } /* scan addr list */ } void pim_neighbor_update(struct pim_neighbor *neigh, pim_hello_options hello_options, uint16_t holdtime, uint32_t dr_priority, struct list *addr_list) { struct pim_interface *pim_ifp = neigh->interface->info; /* Received holdtime ? */ if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { pim_neighbor_timer_reset(neigh, holdtime); } else { pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); } #ifdef DUMP_PREFIX_LIST zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d", __PRETTY_FUNCTION__, (unsigned) neigh->prefix_list, neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1, (unsigned) addr_list, addr_list ? (int) listcount(addr_list) : -1); #endif if (neigh->prefix_list == addr_list) { if (addr_list) { zlog_err("%s: internal error: trying to replace same prefix list=%p", __PRETTY_FUNCTION__, (void *) addr_list); } } else { /* Delete existing secondary address list */ delete_prefix_list(neigh); } if (addr_list) { delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr); } /* Replace secondary address list */ neigh->prefix_list = addr_list; update_dr_priority(neigh, hello_options, dr_priority); /* Copy flags */ neigh->hello_options = hello_options; } quagga-1.2.4/pimd/pim_neighbor.h000066400000000000000000000050071325323223500165310ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_NEIGHBOR_H #define PIM_NEIGHBOR_H #include #include "if.h" #include "linklist.h" #include "pim_tlv.h" struct pim_neighbor { int64_t creation; /* timestamp of creation */ struct in_addr source_addr; pim_hello_options hello_options; uint16_t holdtime; uint16_t propagation_delay_msec; uint16_t override_interval_msec; uint32_t dr_priority; uint32_t generation_id; struct list *prefix_list; /* list of struct prefix */ struct thread *t_expire_timer; struct interface *interface; }; void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); void pim_neighbor_free(struct pim_neighbor *neigh); struct pim_neighbor *pim_neighbor_find(struct interface *ifp, struct in_addr source_addr); struct pim_neighbor *pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, struct list *addr_list); void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, const char *delete_message); void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message); void pim_neighbor_update(struct pim_neighbor *neigh, pim_hello_options hello_options, uint16_t holdtime, uint32_t dr_priority, struct list *addr_list); struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, struct in_addr addr); int pim_if_dr_election(struct interface *ifp); #endif /* PIM_NEIGHBOR_H */ quagga-1.2.4/pimd/pim_oil.c000066400000000000000000000072361325323223500155200ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "memory.h" #include "linklist.h" #include "pimd.h" #include "pim_oil.h" #include "pim_str.h" #include "pim_iface.h" void pim_channel_oil_free(struct channel_oil *c_oil) { XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil); } static void pim_channel_oil_delete(struct channel_oil *c_oil) { /* notice that listnode_delete() can't be moved into pim_channel_oil_free() because the later is called by list_delete_all_node() */ listnode_delete(qpim_channel_oil_list, c_oil); pim_channel_oil_free(c_oil); } static struct channel_oil *channel_oil_new(struct in_addr group_addr, struct in_addr source_addr, int input_vif_index) { struct channel_oil *c_oil; struct interface *ifp_in; ifp_in = pim_if_find_by_vif_index(input_vif_index); if (!ifp_in) { /* warning only */ char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: (S,G)=(%s,%s) could not find input interface for input_vif_index=%d", __PRETTY_FUNCTION__, source_str, group_str, input_vif_index); } c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); if (!c_oil) { zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil)); return 0; } c_oil->oil.mfcc_mcastgrp = group_addr; c_oil->oil.mfcc_origin = source_addr; c_oil->oil.mfcc_parent = input_vif_index; c_oil->oil_ref_count = 1; zassert(c_oil->oil_size == 0); return c_oil; } static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr, struct in_addr source_addr, int input_vif_index) { struct channel_oil *c_oil; c_oil = channel_oil_new(group_addr, source_addr, input_vif_index); if (!c_oil) { zlog_warn("PIM XCALLOC(%zu) failure", sizeof(*c_oil)); return 0; } listnode_add(qpim_channel_oil_list, c_oil); return c_oil; } static struct channel_oil *pim_find_channel_oil(struct in_addr group_addr, struct in_addr source_addr) { struct listnode *node; struct channel_oil *c_oil; for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { if ((group_addr.s_addr == c_oil->oil.mfcc_mcastgrp.s_addr) && (source_addr.s_addr == c_oil->oil.mfcc_origin.s_addr)) return c_oil; } return 0; } struct channel_oil *pim_channel_oil_add(struct in_addr group_addr, struct in_addr source_addr, int input_vif_index) { struct channel_oil *c_oil; c_oil = pim_find_channel_oil(group_addr, source_addr); if (c_oil) { ++c_oil->oil_ref_count; return c_oil; } return pim_add_channel_oil(group_addr, source_addr, input_vif_index); } void pim_channel_oil_del(struct channel_oil *c_oil) { --c_oil->oil_ref_count; if (c_oil->oil_ref_count < 1) { pim_channel_oil_delete(c_oil); } } quagga-1.2.4/pimd/pim_oil.h000066400000000000000000000032201325323223500155120ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_OIL_H #define PIM_OIL_H #include "pim_mroute.h" #define PIM_OIF_FLAG_PROTO_IGMP (1 << 0) /* bitmask 1 */ #define PIM_OIF_FLAG_PROTO_PIM (1 << 1) /* bitmask 2 */ #define PIM_OIF_FLAG_PROTO_ANY (3) /* bitmask (1 | 2) */ /* qpim_channel_oil_list holds a list of struct channel_oil. Each channel_oil.oil is used to control an (S,G) entry in the Kernel Multicast Forwarding Cache. */ struct channel_oil { struct mfcctl oil; int oil_size; int oil_ref_count; time_t oif_creation[MAXVIFS]; uint32_t oif_flags[MAXVIFS]; }; void pim_channel_oil_free(struct channel_oil *c_oil); struct channel_oil *pim_channel_oil_add(struct in_addr group_addr, struct in_addr source_addr, int input_vif_index); void pim_channel_oil_del(struct channel_oil *c_oil); #endif /* PIM_OIL_H */ quagga-1.2.4/pimd/pim_pim.c000066400000000000000000000477101325323223500155230ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "thread.h" #include "memory.h" #include "pimd.h" #include "pim_pim.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_sock.h" #include "pim_str.h" #include "pim_util.h" #include "pim_tlv.h" #include "pim_neighbor.h" #include "pim_hello.h" #include "pim_join.h" #include "pim_assert.h" #include "pim_msg.h" static int on_pim_hello_send(struct thread *t); static int pim_hello_send(struct interface *ifp, uint16_t holdtime); static void sock_close(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; if (PIM_DEBUG_PIM_TRACE) { if (pim_ifp->t_pim_sock_read) { zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s", pim_ifp->pim_sock_fd, ifp->name); } } THREAD_OFF(pim_ifp->t_pim_sock_read); if (PIM_DEBUG_PIM_TRACE) { if (pim_ifp->t_pim_hello_timer) { zlog_debug("Cancelling PIM hello timer for interface %s", ifp->name); } } THREAD_OFF(pim_ifp->t_pim_hello_timer); if (PIM_DEBUG_PIM_TRACE) { zlog_debug("Deleting PIM socket fd=%d on interface %s", pim_ifp->pim_sock_fd, ifp->name); } if (close(pim_ifp->pim_sock_fd)) { zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s", pim_ifp->pim_sock_fd, ifp->name, errno, safe_strerror(errno)); } pim_ifp->pim_sock_fd = -1; pim_ifp->pim_sock_creation = 0; zassert(pim_ifp->pim_sock_fd < 0); zassert(!pim_ifp->t_pim_sock_read); zassert(!pim_ifp->t_pim_hello_timer); zassert(!pim_ifp->pim_sock_creation); } void pim_sock_delete(struct interface *ifp, const char *delete_message) { zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name, delete_message); if (!ifp->info) { zlog_err("%s: %s: but PIM not enabled on interface %s (!)", __PRETTY_FUNCTION__, delete_message, ifp->name); return; } /* RFC 4601: 4.3.1. Sending Hello Messages Before an interface goes down or changes primary IP address, a Hello message with a zero HoldTime should be sent immediately (with the old IP address if the IP address changed). */ pim_hello_send(ifp, 0 /* zero-sec holdtime */); pim_neighbor_delete_all(ifp, delete_message); sock_close(ifp); } int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) { struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ char src_str[100]; char dst_str[100]; uint8_t *pim_msg; int pim_msg_len; uint8_t pim_version; uint8_t pim_type; uint16_t pim_checksum; /* received checksum */ uint16_t checksum; /* computed checksum */ struct pim_neighbor *neigh; if (!ifp->info) { zlog_warn("%s: PIM not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (len < sizeof(*ip_hdr)) { zlog_warn("PIM packet size=%zu shorter than minimum=%zu", len, sizeof(*ip_hdr)); return -1; } ip_hdr = (struct ip *) buf; pim_inet4_dump("", ip_hdr->ip_src, src_str, sizeof(src_str)); pim_inet4_dump("", ip_hdr->ip_dst, dst_str, sizeof(dst_str)); ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ if (PIM_DEBUG_PIM_PACKETS) { zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d", src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p); } if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) { zlog_warn("IP packet protocol=%d is not PIM=%d", ip_hdr->ip_p, PIM_IP_PROTO_PIM); return -1; } if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { zlog_warn("IP packet header size=%zu shorter than minimum=%d", ip_hlen, PIM_IP_HEADER_MIN_LEN); return -1; } if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { zlog_warn("IP packet header size=%zu greater than maximum=%d", ip_hlen, PIM_IP_HEADER_MAX_LEN); return -1; } pim_msg = buf + ip_hlen; pim_msg_len = len - ip_hlen; if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len); } if (pim_msg_len < PIM_PIM_MIN_LEN) { zlog_warn("PIM message size=%d shorter than minimum=%d", pim_msg_len, PIM_PIM_MIN_LEN); return -1; } pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg); pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg); if (pim_version != PIM_PROTO_VERSION) { zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d", ifp->name, pim_version); return -1; } /* save received checksum */ pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg); /* for computing checksum */ *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; checksum = in_cksum(pim_msg, pim_msg_len); if (checksum != pim_checksum) { zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x", ifp->name, pim_checksum, checksum); return -1; } if (PIM_DEBUG_PIM_PACKETS) { zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x", src_str, dst_str, ifp->name, ip_hdr->ip_ttl, pim_version, pim_type, pim_msg_len, checksum); } if (pim_type == PIM_MSG_TYPE_REGISTER || pim_type == PIM_MSG_TYPE_REG_STOP || pim_type == PIM_MSG_TYPE_BOOTSTRAP || pim_type == PIM_MSG_TYPE_GRAFT || pim_type == PIM_MSG_TYPE_GRAFT_ACK || pim_type == PIM_MSG_TYPE_CANDIDATE) { if (PIM_DEBUG_PIM_PACKETS) { zlog_debug("Recv PIM packet type %d which is not currently understood", pim_type); } return -1; } if (pim_type == PIM_MSG_TYPE_HELLO) { int result = pim_hello_recv(ifp, ip_hdr->ip_src, pim_msg + PIM_MSG_HEADER_LEN, pim_msg_len - PIM_MSG_HEADER_LEN); return result; } neigh = pim_neighbor_find(ifp, ip_hdr->ip_src); if (!neigh) { zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s", __FILE__, __PRETTY_FUNCTION__, pim_type, src_str, ifp->name); return -1; } switch (pim_type) { case PIM_MSG_TYPE_JOIN_PRUNE: return pim_joinprune_recv(ifp, neigh, ip_hdr->ip_src, pim_msg + PIM_MSG_HEADER_LEN, pim_msg_len - PIM_MSG_HEADER_LEN); case PIM_MSG_TYPE_ASSERT: return pim_assert_recv(ifp, neigh, ip_hdr->ip_src, pim_msg + PIM_MSG_HEADER_LEN, pim_msg_len - PIM_MSG_HEADER_LEN); default: zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s", __FILE__, __PRETTY_FUNCTION__, pim_type, src_str, ifp->name); } return -1; } static void pim_sock_read_on(struct interface *ifp); static int pim_sock_read(struct thread *t) { struct interface *ifp; struct pim_interface *pim_ifp; int fd; struct sockaddr_in from; struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); uint8_t buf[PIM_PIM_BUFSIZE_READ]; int len; ifindex_t ifindex = -1; int result = -1; /* defaults to bad */ zassert(t); ifp = THREAD_ARG(t); zassert(ifp); fd = THREAD_FD(t); pim_ifp = ifp->info; zassert(pim_ifp); zassert(fd == pim_ifp->pim_sock_fd); len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from, &fromlen, &to, &tolen, &ifindex); if (len < 0) { zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); goto done; } if (PIM_DEBUG_PIM_PACKETS) { char from_str[100]; char to_str[100]; if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str))) sprintf(from_str, ""); if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str))) sprintf(to_str, ""); zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)", len, from_str, to_str, fd, ifindex, ifp->ifindex); } if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { pim_pkt_dump(__PRETTY_FUNCTION__, buf, len); } #ifdef PIM_CHECK_RECV_IFINDEX_SANITY /* ifindex sanity check */ if (ifindex != (int) ifp->ifindex) { char from_str[100]; char to_str[100]; struct interface *recv_ifp; if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str))) sprintf(from_str, ""); if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str))) sprintf(to_str, ""); recv_ifp = if_lookup_by_index(ifindex); if (recv_ifp) { zassert(ifindex == (int) recv_ifp->ifindex); } #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)", from_str, to_str, fd, ifindex, recv_ifp ? recv_ifp->name : "", ifp->ifindex, ifp->name); #endif goto done; } #endif int fail = pim_pim_packet(ifp, buf, len); if (fail) { zlog_warn("%s: pim_pim_packet() return=%d", __PRETTY_FUNCTION__, fail); goto done; } result = 0; /* good */ done: pim_sock_read_on(ifp); if (result) { ++pim_ifp->pim_ifstat_hello_recvfail; } return result; } static void pim_sock_read_on(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); zassert(ifp->info); pim_ifp = ifp->info; if (PIM_DEBUG_PIM_TRACE) { zlog_debug("Scheduling READ event on PIM socket fd=%d", pim_ifp->pim_sock_fd); } pim_ifp->t_pim_sock_read = 0; zassert(!pim_ifp->t_pim_sock_read); THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp, pim_ifp->pim_sock_fd); } static int pim_sock_open(struct in_addr ifaddr, ifindex_t ifindex) { int fd; fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */); if (fd < 0) return -1; if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) { close(fd); return -2; } return fd; } void pim_ifstat_reset(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { return; } pim_ifp->pim_ifstat_start = pim_time_monotonic_sec(); pim_ifp->pim_ifstat_hello_sent = 0; pim_ifp->pim_ifstat_hello_sendfail = 0; pim_ifp->pim_ifstat_hello_recv = 0; pim_ifp->pim_ifstat_hello_recvfail = 0; } void pim_sock_reset(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); zassert(ifp->info); pim_ifp = ifp->info; pim_ifp->primary_address = pim_find_primary_addr(ifp); pim_ifp->pim_sock_fd = -1; pim_ifp->pim_sock_creation = 0; pim_ifp->t_pim_sock_read = 0; pim_ifp->t_pim_hello_timer = 0; pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD; pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */ pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY; pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC; pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC; if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) { PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options); } else { PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options); } /* neighbors without lan_delay */ pim_ifp->pim_number_of_nonlandelay_neighbors = 0; pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0; pim_ifp->pim_neighbors_highest_override_interval_msec = 0; /* DR Election */ pim_ifp->pim_dr_election_last = 0; /* timestamp */ pim_ifp->pim_dr_election_count = 0; pim_ifp->pim_dr_election_changes = 0; pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */ pim_ifp->pim_dr_addr = pim_ifp->primary_address; pim_ifstat_reset(ifp); } int pim_msg_send(int fd, struct in_addr dst, uint8_t *pim_msg, int pim_msg_size, const char *ifname) { ssize_t sent; struct sockaddr_in to; socklen_t tolen; if (PIM_DEBUG_PIM_PACKETS) { char dst_str[100]; pim_inet4_dump("", dst, dst_str, sizeof(dst_str)); zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __PRETTY_FUNCTION__, dst_str, ifname, pim_msg_size, *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)); } memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; to.sin_addr = dst; tolen = sizeof(to); if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size); } sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, (struct sockaddr *)&to, tolen); if (sent != (ssize_t) pim_msg_size) { int e = errno; char dst_str[100]; pim_inet4_dump("", dst, dst_str, sizeof(dst_str)); if (sent < 0) { zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s", __PRETTY_FUNCTION__, dst_str, ifname, fd, pim_msg_size, e, safe_strerror(e)); } else { zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd", __PRETTY_FUNCTION__, dst_str, ifname, fd, pim_msg_size, sent); } return -1; } return 0; } static int hello_send(struct interface *ifp, uint16_t holdtime) { uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE]; struct pim_interface *pim_ifp; int pim_tlv_size; int pim_msg_size; pim_ifp = ifp->info; if (PIM_DEBUG_PIM_HELLO) { char dst_str[100]; pim_inet4_dump("", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str)); zlog_debug("%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d", __PRETTY_FUNCTION__, dst_str, ifp->name, holdtime, pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options), pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, listcount(ifp->connected)); } pim_tlv_size = pim_hello_build_tlv(ifp->name, pim_msg + PIM_PIM_MIN_LEN, sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime, pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options), ifp->connected); if (pim_tlv_size < 0) { return -1; } pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN; zassert(pim_msg_size >= PIM_PIM_MIN_LEN); zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE); pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO); if (pim_msg_send(pim_ifp->pim_sock_fd, qpim_all_pim_routers_addr, pim_msg, pim_msg_size, ifp->name)) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not send PIM message on interface %s", __PRETTY_FUNCTION__, ifp->name); } return -2; } return 0; } static int pim_hello_send(struct interface *ifp, uint16_t holdtime) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); if (hello_send(ifp, holdtime)) { ++pim_ifp->pim_ifstat_hello_sendfail; if (PIM_DEBUG_PIM_HELLO) { zlog_warn("Could not send PIM hello on interface %s", ifp->name); } return -1; } ++pim_ifp->pim_ifstat_hello_sent; return 0; } static void hello_resched(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); if (PIM_DEBUG_PIM_HELLO) { zlog_debug("Rescheduling %d sec hello on interface %s", pim_ifp->pim_hello_period, ifp->name); } THREAD_OFF(pim_ifp->t_pim_hello_timer); THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer, on_pim_hello_send, ifp, pim_ifp->pim_hello_period); } /* Periodic hello timer */ static int on_pim_hello_send(struct thread *t) { struct pim_interface *pim_ifp; struct interface *ifp; zassert(t); ifp = THREAD_ARG(t); zassert(ifp); pim_ifp = ifp->info; /* * Schedule next hello */ pim_ifp->t_pim_hello_timer = 0; hello_resched(ifp); /* * Send hello */ return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); } /* RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ void pim_hello_restart_now(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); /* * Reset next hello timer */ hello_resched(ifp); /* * Immediately send hello */ pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); } /* RFC 4601: 4.3.1. Sending Hello Messages To allow new or rebooting routers to learn of PIM neighbors quickly, when a Hello message is received from a new neighbor, or a Hello message with a new GenID is received from an existing neighbor, a new Hello message should be sent on this interface after a randomized delay between 0 and Triggered_Hello_Delay. */ void pim_hello_restart_triggered(struct interface *ifp) { struct pim_interface *pim_ifp; int triggered_hello_delay_msec; int random_msec; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay; if (pim_ifp->t_pim_hello_timer) { long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer); if (remain_msec <= triggered_hello_delay_msec) { /* Rescheduling hello would increase the delay, then it's faster to just wait for the scheduled periodic hello. */ return; } THREAD_OFF(pim_ifp->t_pim_hello_timer); pim_ifp->t_pim_hello_timer = 0; } zassert(!pim_ifp->t_pim_hello_timer); random_msec = random() % (triggered_hello_delay_msec + 1); if (PIM_DEBUG_PIM_HELLO) { zlog_debug("Scheduling %d msec triggered hello on interface %s", random_msec, ifp->name); } THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer, on_pim_hello_send, ifp, random_msec); } int pim_sock_add(struct interface *ifp) { struct pim_interface *pim_ifp; struct in_addr ifaddr; uint32_t old_genid; pim_ifp = ifp->info; zassert(pim_ifp); if (pim_ifp->pim_sock_fd >= 0) { zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s", pim_ifp->pim_sock_fd, ifp->name); return -1; } ifaddr = pim_ifp->primary_address; pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex); if (pim_ifp->pim_sock_fd < 0) { zlog_warn("Could not open PIM socket on interface %s", ifp->name); return -2; } pim_ifp->t_pim_sock_read = 0; pim_ifp->pim_sock_creation = pim_time_monotonic_sec(); /* * Just ensure that the new generation id * actually chooses something different. * Actually ran across a case where this * happened, pre-switch to random(). * While this is unlikely to happen now * let's make sure it doesn't. */ old_genid = pim_ifp->pim_generation_id; while (old_genid == pim_ifp->pim_generation_id) pim_ifp->pim_generation_id = random(); zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name, ifp->ifindex); /* * Start receiving PIM messages */ pim_sock_read_on(ifp); /* * Start sending PIM hello's */ pim_hello_restart_triggered(ifp); return 0; } quagga-1.2.4/pimd/pim_pim.h000066400000000000000000000056761325323223500155350ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_PIM_H #define PIM_PIM_H #include #include "if.h" #define PIM_PIM_BUFSIZE_READ (20000) #define PIM_PIM_BUFSIZE_WRITE (20000) #define PIM_NEXTHOP_IFINDEX_TAB_SIZE (20) #define PIM_DEFAULT_HELLO_PERIOD (30) /* seconds, RFC 4601: 4.11 */ #define PIM_DEFAULT_TRIGGERED_HELLO_DELAY (5) /* seconds, RFC 4601: 4.11 */ #define PIM_DEFAULT_DR_PRIORITY (1) /* RFC 4601: 4.3.1 */ #define PIM_DEFAULT_PROPAGATION_DELAY_MSEC (500) /* RFC 4601: 4.11. Timer Values */ #define PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC (2500) /* RFC 4601: 4.11. Timer Values */ #define PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION (0) /* boolean */ #define PIM_DEFAULT_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */ #define PIM_MSG_TYPE_HELLO (0) #define PIM_MSG_TYPE_REGISTER (1) #define PIM_MSG_TYPE_REG_STOP (2) #define PIM_MSG_TYPE_JOIN_PRUNE (3) #define PIM_MSG_TYPE_BOOTSTRAP (4) #define PIM_MSG_TYPE_ASSERT (5) #define PIM_MSG_TYPE_GRAFT (6) #define PIM_MSG_TYPE_GRAFT_ACK (7) #define PIM_MSG_TYPE_CANDIDATE (8) #define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg) #define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg) #define PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) (((char *)(pim_msg)) + 1) #define PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) (((char *)(pim_msg)) + 2) #define PIM_MSG_HDR_GET_VERSION(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_VERSION(pim_msg)) >> 4) #define PIM_MSG_HDR_GET_TYPE(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_TYPE(pim_msg)) & 0xF) #define PIM_MSG_HDR_GET_CHECKSUM(pim_msg) (*(uint16_t*) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)) void pim_ifstat_reset(struct interface *ifp); void pim_sock_reset(struct interface *ifp); int pim_sock_add(struct interface *ifp); void pim_sock_delete(struct interface *ifp, const char *delete_message); void pim_hello_restart_now(struct interface *ifp); void pim_hello_restart_triggered(struct interface *ifp); int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len); int pim_msg_send(int fd, struct in_addr dst, uint8_t *pim_msg, int pim_msg_size, const char *ifname); #endif /* PIM_PIM_H */ quagga-1.2.4/pimd/pim_routemap.c000066400000000000000000000017251325323223500165660ustar00rootroot00000000000000/* PIM Route-map Code * Copyright (C) 2016 Cumulus Networks * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "routemap.h" #include "pimd.h" void pim_route_map_init (void) { route_map_init (); route_map_init_vty (); } quagga-1.2.4/pimd/pim_rpf.c000066400000000000000000000203661325323223500155230ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "memory.h" #include "pimd.h" #include "pim_rpf.h" #include "pim_pim.h" #include "pim_str.h" #include "pim_iface.h" #include "pim_zlookup.h" #include "pim_ifchannel.h" static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr) { struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; int num_ifindex; struct interface *ifp; int first_ifindex; num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: could not find nexthop ifindex for address %s", __FILE__, __PRETTY_FUNCTION__, addr_str); return -1; } first_ifindex = nexthop_tab[0].ifindex; if (num_ifindex > 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", __FILE__, __PRETTY_FUNCTION__, num_ifindex, addr_str, first_ifindex); /* debug warning only, do not return */ } ifp = if_lookup_by_index(first_ifindex); if (!ifp) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: could not find interface for ifindex %d (address %s)", __FILE__, __PRETTY_FUNCTION__, first_ifindex, addr_str); return -2; } if (!ifp->info) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", __PRETTY_FUNCTION__, ifp->name, first_ifindex, addr_str); /* debug warning only, do not return */ } if (PIM_DEBUG_PIM_TRACE) { char nexthop_str[100]; char addr_str[100]; pim_inet4_dump("", nexthop_tab[0].nexthop_addr, nexthop_str, sizeof(nexthop_str)); pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d", __FILE__, __PRETTY_FUNCTION__, nexthop_str, addr_str, ifp->name, first_ifindex, nexthop_tab[0].route_metric, nexthop_tab[0].protocol_distance); } /* update nextop data */ nexthop->interface = ifp; nexthop->mrib_nexthop_addr = nexthop_tab[0].nexthop_addr; nexthop->mrib_metric_preference = nexthop_tab[0].protocol_distance; nexthop->mrib_route_metric = nexthop_tab[0].route_metric; return 0; } static int nexthop_mismatch(const struct pim_nexthop *nh1, const struct pim_nexthop *nh2) { return (nh1->interface != nh2->interface) || (nh1->mrib_nexthop_addr.s_addr != nh2->mrib_nexthop_addr.s_addr) || (nh1->mrib_metric_preference != nh2->mrib_metric_preference) || (nh1->mrib_route_metric != nh2->mrib_route_metric); } enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old_rpf) { struct pim_nexthop save_nexthop; struct pim_rpf save_rpf; struct pim_rpf *rpf = &up->rpf; save_nexthop = rpf->source_nexthop; /* detect change in pim_nexthop */ save_rpf = up->rpf; if (pim_nexthop_lookup(&rpf->source_nexthop, up->source_addr)) { return PIM_RPF_FAILURE; } rpf->rpf_addr = pim_rpf_find_rpf_addr(up); if (PIM_INADDR_IS_ANY(rpf->rpf_addr) && PIM_DEBUG_PIM_EVENTS) { /* RPF'(S,G) not found */ char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s %s: RPF'(%s,%s) not found: won't send join upstream", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str); /* warning only */ } /* detect change in pim_nexthop */ if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) { if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; char nhaddr_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str)); zlog_debug("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "", nhaddr_str, rpf->source_nexthop.mrib_metric_preference, rpf->source_nexthop.mrib_route_metric); /* warning only */ } pim_upstream_update_join_desired(up); pim_upstream_update_could_assert(up); pim_upstream_update_my_assert_metric(up); } /* detect change in RPF_interface(S) */ if (save_nexthop.interface != rpf->source_nexthop.interface) { if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, save_nexthop.interface ? save_nexthop.interface->name : "", rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""); /* warning only */ } pim_upstream_rpf_interface_changed(up, save_nexthop.interface); } /* detect change in RPF'(S,G) */ if (save_rpf.rpf_addr.s_addr != rpf->rpf_addr.s_addr) { /* return old rpf to caller ? */ if (old_rpf) *old_rpf = save_rpf; return PIM_RPF_CHANGED; } return PIM_RPF_OK; } /* RFC 4601: 4.1.6. State Summarization Macros neighbor RPF'(S,G) { if ( I_Am_Assert_Loser(S, G, RPF_interface(S) )) { return AssertWinner(S, G, RPF_interface(S) ) } else { return NBR( RPF_interface(S), MRIB.next_hop( S ) ) } } RPF'(*,G) and RPF'(S,G) indicate the neighbor from which data packets should be coming and to which joins should be sent on the RP tree and SPT, respectively. */ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up) { struct pim_ifchannel *rpf_ch; struct pim_neighbor *neigh; struct in_addr rpf_addr; if (!up->rpf.source_nexthop.interface) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: missing RPF interface for upstream (S,G)=(%s,%s)", __PRETTY_FUNCTION__, src_str, grp_str); rpf_addr.s_addr = PIM_NET_INADDR_ANY; return rpf_addr; } rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface, up->source_addr, up->group_addr); if (rpf_ch) { if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { return rpf_ch->ifassert_winner; } } /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */ neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface, up->rpf.source_nexthop.mrib_nexthop_addr); if (neigh) rpf_addr = neigh->source_addr; else rpf_addr.s_addr = PIM_NET_INADDR_ANY; return rpf_addr; } quagga-1.2.4/pimd/pim_rpf.h000066400000000000000000000021711325323223500155220ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_RPF_H #define PIM_RPF_H #include #include "pim_upstream.h" #include "pim_neighbor.h" int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr); enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old_rpf); #endif /* PIM_RPF_H */ quagga-1.2.4/pimd/pim_signals.c000066400000000000000000000033441325323223500163710ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include "sigevent.h" #include "memory.h" #include "log.h" #include "pim_signals.h" #include "pimd.h" /* * Signal handlers */ static void pim_sighup() { zlog_info ("SIGHUP received, ignoring"); } static void pim_sigint() { zlog_notice("Terminating on signal SIGINT"); pim_terminate(); exit(1); } static void pim_sigterm() { zlog_notice("Terminating on signal SIGTERM"); pim_terminate(); exit(1); } static void pim_sigusr1() { zlog_info ("SIGUSR1 received"); zlog_rotate (NULL); } static struct quagga_signal_t pimd_signals[] = { { .signal = SIGHUP, .handler = &pim_sighup, }, { .signal = SIGUSR1, .handler = &pim_sigusr1, }, { .signal = SIGINT, .handler = &pim_sigint, }, { .signal = SIGTERM, .handler = &pim_sigterm, }, }; void pim_signals_init() { signal_init(master, array_size(pimd_signals), pimd_signals); } quagga-1.2.4/pimd/pim_signals.h000066400000000000000000000016511325323223500163750ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_SIGNALS_H #define PIM_SIGNALS_H void pim_signals_init(void); #endif /* PIM_SIGNALS_H */ quagga-1.2.4/pimd/pim_sock.c000066400000000000000000000244531325323223500156740ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "pim_mroute.h" #include #include #include #include #include #include #include #include #include "log.h" #include "privs.h" #include "pimd.h" #include "pim_sock.h" #include "pim_str.h" #include "pim_igmp_join.h" /* GLOBAL VARS */ extern struct zebra_privs_t pimd_privs; int pim_socket_raw(int protocol) { int fd; if ( pimd_privs.change (ZPRIVS_RAISE) ) zlog_err ("pim_sockek_raw: could not raise privs, %s", safe_strerror (errno) ); fd = socket(AF_INET, SOCK_RAW, protocol); if ( pimd_privs.change (ZPRIVS_LOWER) ) zlog_err ("pim_socket_raw: could not lower privs, %s", safe_strerror (errno) ); if (fd < 0) { zlog_warn("Could not create raw socket: errno=%d: %s", errno, safe_strerror(errno)); return PIM_SOCK_ERR_SOCKET; } return fd; } int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) { int fd; fd = pim_socket_raw(protocol); if (fd < 0) { zlog_warn("Could not create multicast socket: errno=%d: %s", errno, safe_strerror(errno)); return PIM_SOCK_ERR_SOCKET; } /* Needed to obtain destination address from recvmsg() */ { #if defined(HAVE_IP_PKTINFO) /* Linux and Solaris IP_PKTINFO */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); } #elif defined(HAVE_IP_RECVDSTADDR) /* BSD IP_RECVDSTADDR */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); } #else zlog_err("%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", __FILE__, __PRETTY_FUNCTION__); close(fd); return PIM_SOCK_ERR_DSTADDR; #endif } /* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4. Message Formats)*/ if (protocol == IPPROTO_IGMP) { char ra[4]; ra[0] = 148; ra[1] = 4; ra[2] = 0; ra[3] = 0; if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) { zlog_warn("Could not set Router Alert Option on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_RA; } } { int reuse = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &reuse, sizeof(reuse))) { zlog_warn("Could not set Reuse Address Option on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_REUSE; } } { const int MTTL = 1; int ttl = MTTL; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &ttl, sizeof(ttl))) { zlog_warn("Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", MTTL, fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_TTL; } } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *) &loop, sizeof(loop))) { zlog_warn("Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", loop ? "enable" : "disable", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_LOOP; } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *) &ifaddr, sizeof(ifaddr))) { zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_IFACE; } { long flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { zlog_warn("Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_NONBLOCK_GETFL; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { zlog_warn("Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_NONBLOCK_SETFL; } } return fd; } int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, ifindex_t ifindex) { int ret; #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX struct ip_mreqn opt; #else struct ip_mreq opt; #endif opt.imr_multiaddr = group; #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX opt.imr_address = ifaddr; opt.imr_ifindex = ifindex; #else opt.imr_interface = ifaddr; #endif ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt)); if (ret) { char group_str[100]; char ifaddr_str[100]; if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str))) sprintf(group_str, ""); if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str))) sprintf(ifaddr_str, ""); zlog_err("Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s", fd, group_str, ifaddr_str, errno, safe_strerror(errno)); return ret; } if (PIM_DEBUG_TRACE) { char group_str[100]; char ifaddr_str[100]; if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str))) sprintf(group_str, ""); if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str))) sprintf(ifaddr_str, ""); zlog_debug("Socket fd=%d joined group %s on interface address %s", fd, group_str, ifaddr_str); } return ret; } int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname) { if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) { int e = errno; char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s", __PRETTY_FUNCTION__, fd, group_str, source_str, ifindex, ifname, e, safe_strerror(e)); return -1; } return 0; } int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, ifindex_t *ifindex) { struct msghdr msgh; struct cmsghdr *cmsg; struct iovec iov; char cbuf[1000]; int err; /* * IP_PKTINFO / IP_RECVDSTADDR don't yield sin_port. * Use getsockname() to get sin_port. */ if (to) { struct sockaddr_in si; socklen_t si_len = sizeof(si); ((struct sockaddr_in *) to)->sin_family = AF_INET; if (pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len)) { ((struct sockaddr_in *) to)->sin_port = ntohs(0); ((struct sockaddr_in *) to)->sin_addr.s_addr = ntohl(0); } else { ((struct sockaddr_in *) to)->sin_port = si.sin_port; ((struct sockaddr_in *) to)->sin_addr = si.sin_addr; } if (tolen) *tolen = sizeof(si); } memset(&msgh, 0, sizeof(struct msghdr)); iov.iov_base = buf; iov.iov_len = len; msgh.msg_control = cbuf; msgh.msg_controllen = sizeof(cbuf); msgh.msg_name = from; msgh.msg_namelen = fromlen ? *fromlen : 0; msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_flags = 0; err = recvmsg(fd, &msgh, 0); if (err < 0) return err; if (fromlen) *fromlen = msgh.msg_namelen; for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) { #ifdef HAVE_IP_PKTINFO if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg); if (to) ((struct sockaddr_in *) to)->sin_addr = i->ipi_addr; if (tolen) *tolen = sizeof(struct sockaddr_in); if (ifindex) *ifindex = i->ipi_ifindex; if (to && PIM_DEBUG_PACKETS) { char to_str[100]; pim_inet4_dump("", to->sin_addr, to_str, sizeof(to_str)); zlog_debug("%s: HAVE_IP_PKTINFO to=%s,%d", __PRETTY_FUNCTION__, to_str, ntohs(to->sin_port)); } break; } #endif #ifdef HAVE_IP_RECVDSTADDR if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) { struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg); if (to) ((struct sockaddr_in *) to)->sin_addr = *i; if (tolen) *tolen = sizeof(struct sockaddr_in); if (to && PIM_DEBUG_PACKETS) { char to_str[100]; pim_inet4_dump("", to->sin_addr, to_str, sizeof(to_str)); zlog_debug("%s: HAVE_IP_RECVDSTADDR to=%s,%d", __PRETTY_FUNCTION__, to_str, ntohs(to->sin_port)); } break; } #endif #if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX) if (cmsg->cmsg_type == IP_RECVIF) if (ifindex) *ifindex = CMSG_IFINDEX(cmsg); #endif } /* for (cmsg) */ return err; /* len */ } int pim_socket_mcastloop_get(int fd) { int loop; socklen_t loop_len = sizeof(loop); if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &loop_len)) { int e = errno; zlog_warn("Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); errno = e; return PIM_SOCK_ERR_LOOP; } return loop; } int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen) { if (getsockname(fd, name, namelen)) { int e = errno; zlog_warn("Could not get Socket Name for socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); errno = e; return PIM_SOCK_ERR_NAME; } return PIM_SOCK_ERR_NONE; } quagga-1.2.4/pimd/pim_sock.h000066400000000000000000000042531325323223500156750ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_SOCK_H #define PIM_SOCK_H #include #define PIM_SOCK_ERR_NONE (0) /* No error */ #define PIM_SOCK_ERR_SOCKET (-1) /* socket() */ #define PIM_SOCK_ERR_RA (-2) /* Router Alert option */ #define PIM_SOCK_ERR_REUSE (-3) /* Reuse option */ #define PIM_SOCK_ERR_TTL (-4) /* TTL option */ #define PIM_SOCK_ERR_LOOP (-5) /* Loopback option */ #define PIM_SOCK_ERR_IFACE (-6) /* Outgoing interface option */ #define PIM_SOCK_ERR_DSTADDR (-7) /* Outgoing interface option */ #define PIM_SOCK_ERR_NONBLOCK_GETFL (-8) /* Get O_NONBLOCK */ #define PIM_SOCK_ERR_NONBLOCK_SETFL (-9) /* Set O_NONBLOCK */ #define PIM_SOCK_ERR_NAME (-10) /* Socket name (getsockname) */ int pim_socket_raw(int protocol); int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop); int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, ifindex_t ifindex); int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, ifindex_t *ifindex); int pim_socket_mcastloop_get(int fd); int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen); #endif /* PIM_SOCK_H */ quagga-1.2.4/pimd/pim_ssmpingd.c000066400000000000000000000272771325323223500165700ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "if.h" #include "log.h" #include "memory.h" #include "pim_ssmpingd.h" #include "pim_time.h" #include "pim_sock.h" #include "pim_str.h" #include "pimd.h" static const char * const PIM_SSMPINGD_REPLY_GROUP = "232.43.211.234"; enum { PIM_SSMPINGD_REQUEST = 'Q', PIM_SSMPINGD_REPLY = 'A' }; static void ssmpingd_read_on(struct ssmpingd_sock *ss); void pim_ssmpingd_init() { int result; zassert(!qpim_ssmpingd_list); result = inet_pton(AF_INET, PIM_SSMPINGD_REPLY_GROUP, &qpim_ssmpingd_group_addr); zassert(result > 0); } void pim_ssmpingd_destroy() { if (qpim_ssmpingd_list) { list_free(qpim_ssmpingd_list); qpim_ssmpingd_list = 0; } } static struct ssmpingd_sock *ssmpingd_find(struct in_addr source_addr) { struct listnode *node; struct ssmpingd_sock *ss; if (!qpim_ssmpingd_list) return 0; for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) if (source_addr.s_addr == ss->source_addr.s_addr) return ss; return 0; } static void ssmpingd_free(struct ssmpingd_sock *ss) { XFREE(MTYPE_PIM_SSMPINGD, ss); } static int ssmpingd_socket(struct in_addr addr, int port, int mttl) { struct sockaddr_in sockaddr; int fd; fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { zlog_err("%s: could not create socket: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; } sockaddr.sin_family = AF_INET; sockaddr.sin_addr = addr; sockaddr.sin_port = htons(port); if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s", __PRETTY_FUNCTION__, fd, addr_str, port, sizeof(sockaddr), errno, safe_strerror(errno)); close(fd); return -1; } /* Needed to obtain destination address from recvmsg() */ { #if defined(HAVE_IP_PKTINFO) /* Linux and Solaris IP_PKTINFO */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn("%s: could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } #elif defined(HAVE_IP_RECVDSTADDR) /* BSD IP_RECVDSTADDR */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { zlog_warn("%s: could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } #else zlog_err("%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", __FILE__, __PRETTY_FUNCTION__); close(fd); return -1; #endif } { int reuse = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &reuse, sizeof(reuse))) { zlog_warn("%s: could not set Reuse Address Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &mttl, sizeof(mttl))) { zlog_warn("%s: could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, mttl, fd, errno, safe_strerror(errno)); close(fd); return -1; } { int loop = 0; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *) &loop, sizeof(loop))) { zlog_warn("%s: could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, loop ? "enable" : "disable", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_LOOP; } } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *) &addr, sizeof(addr))) { zlog_warn("%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } { long flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { zlog_warn("%s: could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { zlog_warn("%s: could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } } return fd; } static void ssmpingd_delete(struct ssmpingd_sock *ss) { zassert(ss); zassert(qpim_ssmpingd_list); THREAD_OFF(ss->t_sock_read); if (close(ss->sock_fd)) { int e = errno; char source_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure closing ssmpingd sock_fd=%d for source %s: errno=%d: %s", __PRETTY_FUNCTION__, ss->sock_fd, source_str, e, safe_strerror(e)); /* warning only */ } listnode_delete(qpim_ssmpingd_list, ss); ssmpingd_free(ss); } static void ssmpingd_sendto(struct ssmpingd_sock *ss, const uint8_t *buf, int len, struct sockaddr_in to) { socklen_t tolen = sizeof(to); int sent; sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&to, tolen); if (sent != len) { int e = errno; char to_str[100]; pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); if (sent < 0) { zlog_warn("%s: sendto() failure to %s,%d: fd=%d len=%d: errno=%d: %s", __PRETTY_FUNCTION__, to_str, ntohs(to.sin_port), ss->sock_fd, len, e, safe_strerror(e)); } else { zlog_warn("%s: sendto() partial to %s,%d: fd=%d len=%d: sent=%d", __PRETTY_FUNCTION__, to_str, ntohs(to.sin_port), ss->sock_fd, len, sent); } } } static int ssmpingd_read_msg(struct ssmpingd_sock *ss) { struct interface *ifp; struct sockaddr_in from; struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); ifindex_t ifindex = -1; uint8_t buf[1000]; int len; ++ss->requests; len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), &from, &fromlen, &to, &tolen, &ifindex); if (len < 0) { char source_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, source_str, ss->sock_fd, errno, safe_strerror(errno)); return -1; } ifp = if_lookup_by_index(ifindex); if (buf[0] != PIM_SSMPINGD_REQUEST) { char source_str[100]; char from_str[100]; char to_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", from.sin_addr, from_str, sizeof(from_str)); pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); zlog_warn("%s: bad ssmping type=%d from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", __PRETTY_FUNCTION__, buf[0], from_str, ntohs(from.sin_port), to_str, ntohs(to.sin_port), ifp ? ifp->name : "", ifindex, ss->sock_fd, source_str); return 0; } if (PIM_DEBUG_SSMPINGD) { char source_str[100]; char from_str[100]; char to_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", from.sin_addr, from_str, sizeof(from_str)); pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); zlog_debug("%s: recv ssmping from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", __PRETTY_FUNCTION__, from_str, ntohs(from.sin_port), to_str, ntohs(to.sin_port), ifp ? ifp->name : "", ifindex, ss->sock_fd, source_str); } buf[0] = PIM_SSMPINGD_REPLY; /* unicast reply */ ssmpingd_sendto(ss, buf, len, from); /* multicast reply */ from.sin_addr = qpim_ssmpingd_group_addr; ssmpingd_sendto(ss, buf, len, from); return 0; } static int ssmpingd_sock_read(struct thread *t) { struct ssmpingd_sock *ss; int sock_fd; int result; zassert(t); ss = THREAD_ARG(t); zassert(ss); sock_fd = THREAD_FD(t); zassert(sock_fd == ss->sock_fd); result = ssmpingd_read_msg(ss); /* Keep reading */ ss->t_sock_read = 0; ssmpingd_read_on(ss); return result; } static void ssmpingd_read_on(struct ssmpingd_sock *ss) { zassert(!ss->t_sock_read); THREAD_READ_ON(master, ss->t_sock_read, ssmpingd_sock_read, ss, ss->sock_fd); } static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr) { struct ssmpingd_sock *ss; int sock_fd; if (!qpim_ssmpingd_list) { qpim_ssmpingd_list = list_new(); if (!qpim_ssmpingd_list) { zlog_err("%s %s: failure: qpim_ssmpingd_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return 0; } qpim_ssmpingd_list->del = (void (*)(void *)) ssmpingd_free; } sock_fd = ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64); if (sock_fd < 0) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: ssmpingd_socket() failure for source %s", __PRETTY_FUNCTION__, source_str); return 0; } ss = XMALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss)); if (!ss) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_err("%s: XMALLOC(%zu) failure for ssmpingd source %s", __PRETTY_FUNCTION__, sizeof(*ss), source_str); close(sock_fd); return 0; } ss->sock_fd = sock_fd; ss->t_sock_read = 0; ss->source_addr = source_addr; ss->creation = pim_time_monotonic_sec(); ss->requests = 0; listnode_add(qpim_ssmpingd_list, ss); ssmpingd_read_on(ss); return ss; } int pim_ssmpingd_start(struct in_addr source_addr) { struct ssmpingd_sock *ss; ss = ssmpingd_find(source_addr); if (ss) { /* silently ignore request to recreate entry */ return 0; } { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_info("%s: starting ssmpingd for source %s", __PRETTY_FUNCTION__, source_str); } ss = ssmpingd_new(source_addr); if (!ss) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: ssmpingd_new() failure for source %s", __PRETTY_FUNCTION__, source_str); return -1; } return 0; } int pim_ssmpingd_stop(struct in_addr source_addr) { struct ssmpingd_sock *ss; ss = ssmpingd_find(source_addr); if (!ss) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: could not find ssmpingd for source %s", __PRETTY_FUNCTION__, source_str); return -1; } { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_info("%s: stopping ssmpingd for source %s", __PRETTY_FUNCTION__, source_str); } ssmpingd_delete(ss); return 0; } quagga-1.2.4/pimd/pim_ssmpingd.h000066400000000000000000000026261325323223500165640ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_SSMPINGD_H #define PIM_SSMPINGD_H #include #include "if.h" #include "pim_iface.h" struct ssmpingd_sock { int sock_fd; /* socket */ struct thread *t_sock_read; /* thread for reading socket */ struct in_addr source_addr; /* source address */ int64_t creation; /* timestamp of socket creation */ int64_t requests; /* counter */ }; void pim_ssmpingd_init(void); void pim_ssmpingd_destroy(void); int pim_ssmpingd_start(struct in_addr source_addr); int pim_ssmpingd_stop(struct in_addr source_addr); #endif /* PIM_SSMPINGD_H */ quagga-1.2.4/pimd/pim_static.c000066400000000000000000000265621325323223500162270ustar00rootroot00000000000000/* PIM for Quagga: add the ability to configure multicast static routes Copyright (C) 2014 Nathan Bahr, ATCorp 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "vty.h" #include "pim_static.h" #include "pim_time.h" #include "pim_str.h" #include "pimd.h" #include "pim_iface.h" #include "log.h" #include "memory.h" #include "linklist.h" void pim_static_route_free(struct static_route *s_route) { XFREE(MTYPE_PIM_STATIC_ROUTE, s_route); } static struct static_route * static_route_alloc() { struct static_route *s_route; s_route = XCALLOC(MTYPE_PIM_STATIC_ROUTE, sizeof(*s_route)); if (!s_route) { zlog_err("PIM XCALLOC(%zu) failure", sizeof(*s_route)); return 0; } return s_route; } static struct static_route *static_route_new(unsigned int iif, unsigned int oif, struct in_addr group, struct in_addr source) { struct static_route * s_route; s_route = static_route_alloc(); if (!s_route) { return 0; } s_route->group = group; s_route->source = source; s_route->iif = iif; s_route->oif_ttls[oif] = 1; s_route->oif_count = 1; s_route->mc.mfcc_origin = source; s_route->mc.mfcc_mcastgrp = group; s_route->mc.mfcc_parent = iif; s_route->mc.mfcc_ttls[oif] = 1; s_route->creation[oif] = pim_time_monotonic_sec(); return s_route; } int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source) { struct listnode *node = 0; struct static_route *s_route = 0; struct static_route *original_s_route = 0; struct pim_interface *pim_iif = iif ? iif->info : 0; struct pim_interface *pim_oif = oif ? oif->info : 0; unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; if (!iif_index || !oif_index) { zlog_warn("%s %s: Unable to add static route: Invalid interface index(iif=%d,oif=%d)", __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index); return -2; } #ifdef PIM_ENFORCE_LOOPFREE_MFC if (iif_index == oif_index) { /* looped MFC entry */ zlog_warn("%s %s: Unable to add static route: Looped MFC entry(iif=%d,oif=%d)", __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index); return -4; } #endif for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { if (s_route->group.s_addr == group.s_addr && s_route->source.s_addr == source.s_addr) { if (s_route->iif == iif_index && s_route->oif_ttls[oif_index]) { char gifaddr_str[100]; char sifaddr_str[100]; pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)", __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index, gifaddr_str, sifaddr_str); return -3; } /* Ok, from here on out we will be making changes to the s_route structure, but if * for some reason we fail to commit these changes to the kernel, we want to be able * restore the state of the list. So copy the node data and if need be, we can copy * back if it fails. */ original_s_route = static_route_alloc(); if (!original_s_route) { return -5; } memcpy(original_s_route, s_route, sizeof(struct static_route)); /* Route exists and has the same input interface, but adding a new output interface */ if (s_route->iif == iif_index) { s_route->oif_ttls[oif_index] = 1; s_route->mc.mfcc_ttls[oif_index] = 1; s_route->creation[oif_index] = pim_time_monotonic_sec(); ++s_route->oif_count; } else { /* input interface changed */ s_route->iif = iif_index; s_route->mc.mfcc_parent = iif_index; #ifdef PIM_ENFORCE_LOOPFREE_MFC /* check to make sure the new input was not an old output */ if (s_route->oif_ttls[iif_index]) { s_route->oif_ttls[iif_index] = 0; s_route->creation[iif_index] = 0; s_route->mc.mfcc_ttls[iif_index] = 0; --s_route->oif_count; } #endif /* now add the new output, if it is new */ if (!s_route->oif_ttls[oif_index]) { s_route->oif_ttls[oif_index] = 1; s_route->creation[oif_index] = pim_time_monotonic_sec(); s_route->mc.mfcc_ttls[oif_index] = 1; ++s_route->oif_count; } } break; } } /* If node is null then we reached the end of the list without finding a match */ if (!node) { s_route = static_route_new(iif_index, oif_index, group, source); listnode_add(qpim_static_route_list, s_route); } if (pim_mroute_add(&(s_route->mc))) { char gifaddr_str[100]; char sifaddr_str[100]; pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)", __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index, gifaddr_str, sifaddr_str); /* Need to put s_route back to the way it was */ if (original_s_route) { memcpy(s_route, original_s_route, sizeof(struct static_route)); } else { /* we never stored off a copy, so it must have been a fresh new route */ listnode_delete(qpim_static_route_list, s_route); pim_static_route_free(s_route); } if (original_s_route) { pim_static_route_free(original_s_route); } return -1; } /* Make sure we free the memory for the route copy if used */ if (original_s_route) { pim_static_route_free(original_s_route); } if (PIM_DEBUG_STATIC) { char gifaddr_str[100]; char sifaddr_str[100]; pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)", __PRETTY_FUNCTION__, iif_index, oif_index, gifaddr_str, sifaddr_str); } return 0; } int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source) { struct listnode *node = 0; struct listnode *nextnode = 0; struct static_route *s_route = 0; struct pim_interface *pim_iif = iif ? iif->info : 0; struct pim_interface *pim_oif = oif ? oif->info : 0; unsigned int iif_index = pim_iif ? pim_iif->mroute_vif_index : 0; unsigned int oif_index = pim_oif ? pim_oif->mroute_vif_index : 0; if (!iif_index || !oif_index) { zlog_warn("%s %s: Unable to remove static route: Invalid interface index(iif=%d,oif=%d)", __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index); return -2; } for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode, s_route)) { if (s_route->iif == iif_index && s_route->group.s_addr == group.s_addr && s_route->source.s_addr == source.s_addr && s_route->oif_ttls[oif_index]) { s_route->oif_ttls[oif_index] = 0; s_route->mc.mfcc_ttls[oif_index] = 0; --s_route->oif_count; /* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */ if (s_route->oif_count <= 0 ? pim_mroute_del(&s_route->mc) : pim_mroute_add(&s_route->mc)) { char gifaddr_str[100]; char sifaddr_str[100]; pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)", __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index, gifaddr_str, sifaddr_str); s_route->oif_ttls[oif_index] = 1; s_route->mc.mfcc_ttls[oif_index] = 1; ++s_route->oif_count; return -1; } s_route->creation[oif_index] = 0; if (s_route->oif_count <= 0) { listnode_delete(qpim_static_route_list, s_route); pim_static_route_free(s_route); } if (PIM_DEBUG_STATIC) { char gifaddr_str[100]; char sifaddr_str[100]; pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)", __PRETTY_FUNCTION__, iif_index, oif_index, gifaddr_str, sifaddr_str); } break; } } if (!node) { char gifaddr_str[100]; char sifaddr_str[100]; pim_inet4_dump("", group, gifaddr_str, sizeof(gifaddr_str)); pim_inet4_dump("", source, sifaddr_str, sizeof(sifaddr_str)); zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)", __FILE__, __PRETTY_FUNCTION__, iif_index, oif_index, gifaddr_str, sifaddr_str); return -3; } return 0; } int pim_static_write_mroute (struct vty *vty, struct interface *ifp) { struct listnode *node; struct static_route *sroute; int count = 0; char sbuf[100]; char gbuf[100]; for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute)) { pim_inet4_dump ("", sroute->group, gbuf, sizeof (gbuf)); pim_inet4_dump ("", sroute->source, sbuf, sizeof (sbuf)); if (sroute->iif == ifp->ifindex) { int i; for (i = 0; i < MAXVIFS; i++) if (sroute->oif_ttls[i]) { struct interface *oifp = if_lookup_by_index (i); vty_out (vty, " ip mroute %s %s %s%s", oifp->name, gbuf, sbuf, VTY_NEWLINE); count ++; } } } return count; } quagga-1.2.4/pimd/pim_static.h000066400000000000000000000031661325323223500162270ustar00rootroot00000000000000/* PIM for Quagga: add the ability to configure multicast static routes Copyright (C) 2014 Nathan Bahr, ATCorp 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_STATIC_H_ #define PIM_STATIC_H_ #include #include "pim_mroute.h" #include "if.h" struct static_route { /* Each static route is unique by these pair of addresses */ struct in_addr group; struct in_addr source; unsigned int iif; unsigned char oif_ttls[MAXVIFS]; int oif_count; struct mfcctl mc; time_t creation[MAXVIFS]; }; void pim_static_route_free(struct static_route *s_route); int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source); int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source); int pim_static_write_mroute (struct vty *vty, struct interface *ifp); #endif /* PIM_STATIC_H_ */ quagga-1.2.4/pimd/pim_str.c000066400000000000000000000025021325323223500155340ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include #include "log.h" #include "pim_str.h" void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size) { int save_errno = errno; if (!inet_ntop(AF_INET, &addr, buf, buf_size)) { int e = errno; zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s", buf_size, e, safe_strerror(e)); if (onfail) snprintf(buf, buf_size, "%s", onfail); } errno = save_errno; } quagga-1.2.4/pimd/pim_str.h000066400000000000000000000020161325323223500155410ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_STR_H #define PIM_STR_H #include #include #include void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size); #endif quagga-1.2.4/pimd/pim_time.c000066400000000000000000000070631325323223500156710ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include #include "log.h" #include "thread.h" #include "pim_time.h" static int gettime_monotonic(struct timeval *tv) { int result; result = gettimeofday(tv, 0); if (result) { zlog_err("%s: gettimeofday() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); } return result; } /* pim_time_monotonic_sec(): number of seconds since some unspecified starting point */ int64_t pim_time_monotonic_sec() { struct timeval now_tv; if (gettime_monotonic(&now_tv)) { zlog_err("%s: gettime_monotonic() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; } return now_tv.tv_sec; } /* pim_time_monotonic_dsec(): number of deciseconds since some unspecified starting point */ int64_t pim_time_monotonic_dsec() { struct timeval now_tv; int64_t now_dsec; if (gettime_monotonic(&now_tv)) { zlog_err("%s: gettime_monotonic() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; } now_dsec = ((int64_t) now_tv.tv_sec) * 10 + ((int64_t) now_tv.tv_usec) / 100000; return now_dsec; } int pim_time_mmss(char *buf, int buf_size, long sec) { long mm; int wr; zassert(buf_size >= 5); mm = sec / 60; sec %= 60; wr = snprintf(buf, buf_size, "%02ld:%02ld", mm, sec); return wr != 8; } static int pim_time_hhmmss(char *buf, int buf_size, long sec) { long hh; long mm; int wr; zassert(buf_size >= 8); hh = sec / 3600; sec %= 3600; mm = sec / 60; sec %= 60; wr = snprintf(buf, buf_size, "%02ld:%02ld:%02ld", hh, mm, sec); return wr != 8; } void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t_timer) { if (t_timer) { pim_time_mmss(buf, buf_size, thread_timer_remain_second(t_timer)); } else { snprintf(buf, buf_size, "--:--"); } } void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t_timer) { if (t_timer) { pim_time_hhmmss(buf, buf_size, thread_timer_remain_second(t_timer)); } else { snprintf(buf, buf_size, "--:--:--"); } } void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec) { zassert(buf_size >= 8); pim_time_hhmmss(buf, buf_size, uptime_sec); } void pim_time_uptime_begin(char *buf, int buf_size, int64_t now, int64_t begin) { if (begin > 0) pim_time_uptime(buf, buf_size, now - begin); else snprintf(buf, buf_size, "--:--:--"); } long pim_time_timer_remain_msec(struct thread *t_timer) { /* FIXME: Actually fetch msec resolution from thread */ /* no timer thread running means timer has expired: return 0 */ return t_timer ? 1000 * thread_timer_remain_second(t_timer) : 0; } quagga-1.2.4/pimd/pim_time.h000066400000000000000000000026421325323223500156740ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_TIME_H #define PIM_TIME_H #include #include #include "thread.h" int64_t pim_time_monotonic_sec(void); int64_t pim_time_monotonic_dsec(void); int pim_time_mmss(char *buf, int buf_size, long sec); void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t); void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t); void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec); void pim_time_uptime_begin(char *buf, int buf_size, int64_t now, int64_t begin); long pim_time_timer_remain_msec(struct thread *t_timer); #endif /* PIM_TIME_H */ quagga-1.2.4/pimd/pim_tlv.c000066400000000000000000000460141325323223500155370ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "pimd.h" #include "pim_int.h" #include "pim_tlv.h" #include "pim_str.h" #include "pim_msg.h" uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value) { uint16_t option_len = 2; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) return NULL; *(uint16_t *) buf = htons(option_type); buf += 2; *(uint16_t *) buf = htons(option_len); buf += 2; *(uint16_t *) buf = htons(option_value); buf += option_len; return buf; } uint8_t *pim_tlv_append_2uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value1, uint16_t option_value2) { uint16_t option_len = 4; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) return NULL; *(uint16_t *) buf = htons(option_type); buf += 2; *(uint16_t *) buf = htons(option_len); buf += 2; *(uint16_t *) buf = htons(option_value1); buf += 2; *(uint16_t *) buf = htons(option_value2); buf += 2; return buf; } uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint32_t option_value) { uint16_t option_len = 4; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) return NULL; *(uint16_t *) buf = htons(option_type); buf += 2; *(uint16_t *) buf = htons(option_len); buf += 2; pim_write_uint32(buf, option_value); buf += option_len; return buf; } #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, struct list *ifconnected) { struct listnode *node; uint16_t option_len = 0; uint8_t *curr; node = listhead(ifconnected); /* Empty address list ? */ if (!node) { return buf; } /* Skip first address (primary) */ node = listnextnode(node); /* Scan secondary address list */ curr = buf + 4; /* skip T and L */ for (; node; node = listnextnode(node)) { struct connected *ifc = listgetdata(node); struct prefix *p = ifc->address; if (p->family != AF_INET) continue; if ((curr + ucast_ipv4_encoding_len) > buf_pastend) return 0; /* Write encoded unicast IPv4 address */ *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ ++curr; *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ ++curr; memcpy(curr, &p->u.prefix4, sizeof(struct in_addr)); curr += sizeof(struct in_addr); option_len += ucast_ipv4_encoding_len; } if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu", __PRETTY_FUNCTION__, option_len / ucast_ipv4_encoding_len); } if (option_len < 1) { /* Empty secondary unicast IPv4 address list */ return buf; } /* * Write T and L */ *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST); *(uint16_t *) (buf + 2) = htons(option_len); return curr; } static int check_tlv_length(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int correct_len, int option_len) { if (option_len != correct_len) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", label, tlv_name, option_len, correct_len, src_str, ifname); return -1; } return 0; } static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, pim_hello_options options, pim_hello_options opt_mask, uint16_t new, uint16_t old) { if (PIM_OPTION_IS_SET(options, opt_mask)) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", label, tlv_name, new, old, src_str, ifname); } } static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, pim_hello_options options, pim_hello_options opt_mask, uint32_t new, uint32_t old) { if (PIM_OPTION_IS_SET(options, opt_mask)) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", label, tlv_name, new, old, src_str, ifname); } } static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, pim_hello_options options, pim_hello_options opt_mask, uint32_t new, uint32_t old) { if (PIM_OPTION_IS_SET(options, opt_mask)) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", label, tlv_name, new, old, src_str, ifname); } } int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, const uint8_t *tlv_curr) { const char *label = "holdtime"; if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, sizeof(uint16_t), option_len)) { return -1; } check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label, ifname, src_addr, *hello_options, PIM_OPTION_MASK_HOLDTIME, PIM_TLV_GET_HOLDTIME(tlv_curr), *hello_option_holdtime); PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME); *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr); return 0; } int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, uint16_t option_len, const uint8_t *tlv_curr) { if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", ifname, src_addr, sizeof(uint32_t), option_len)) { return -1; } check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay", ifname, src_addr, *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY, PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr), *hello_option_propagation_delay); PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr); if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) { PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); } else { PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); } ++tlv_curr; ++tlv_curr; *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr); return 0; } int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, const uint8_t *tlv_curr) { const char *label = "dr_priority"; if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, sizeof(uint32_t), option_len)) { return -1; } check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label, ifname, src_addr, *hello_options, PIM_OPTION_MASK_DR_PRIORITY, PIM_TLV_GET_DR_PRIORITY(tlv_curr), *hello_option_dr_priority); PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); return 0; } int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, const uint8_t *tlv_curr) { const char *label = "generation_id"; if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, sizeof(uint32_t), option_len)) { return -1; } check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label, ifname, src_addr, *hello_options, PIM_OPTION_MASK_GENERATION_ID, PIM_TLV_GET_GENERATION_ID(tlv_curr), *hello_option_generation_id); PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID); *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr); return 0; } int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, struct prefix *p, const uint8_t *buf, int buf_size) { const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ const uint8_t *addr; const uint8_t *pastend; int family; int type; if (buf_size < ucast_encoding_min_len) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s", __PRETTY_FUNCTION__, buf_size, ucast_encoding_min_len, src_str, ifname); return -1; } addr = buf; pastend = buf + buf_size; family = *addr++; type = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: if (type) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s", __PRETTY_FUNCTION__, type, src_str, ifname); return -2; } if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); return -3; } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); addr += sizeof(struct in_addr); break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s", __PRETTY_FUNCTION__, family, src_str, ifname); return -4; } } return addr - buf; } int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, struct prefix *p, const uint8_t *buf, int buf_size) { const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ const uint8_t *addr; const uint8_t *pastend; int family; int type; int mask_len; if (buf_size < grp_encoding_min_len) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s", __PRETTY_FUNCTION__, buf_size, grp_encoding_min_len, src_str, ifname); return -1; } addr = buf; pastend = buf + buf_size; family = *addr++; type = *addr++; //++addr; ++addr; /* skip b_reserved_z fields */ mask_len = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: if (type) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown group address encoding type=%d from %s on %s", __PRETTY_FUNCTION__, type, src_str, ifname); return -2; } if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); return -3; } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); p->prefixlen = mask_len; addr += sizeof(struct in_addr); break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown group address encoding family=%d from %s on %s", __PRETTY_FUNCTION__, family, src_str, ifname); return -4; } } return addr - buf; } int pim_parse_addr_source(const char *ifname, struct in_addr src_addr, struct prefix *p, uint8_t *flags, const uint8_t *buf, int buf_size) { const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ const uint8_t *addr; const uint8_t *pastend; int family; int type; int mask_len; if (buf_size < src_encoding_min_len) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s", __PRETTY_FUNCTION__, buf_size, src_encoding_min_len, src_str, ifname); return -1; } addr = buf; pastend = buf + buf_size; family = *addr++; type = *addr++; *flags = *addr++; mask_len = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: if (type) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown source address encoding type=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", __PRETTY_FUNCTION__, type, src_str, ifname, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); return -2; } if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); return -3; } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); p->prefixlen = mask_len; /* RFC 4601: 4.9.1 Encoded Source and Group Address Formats Encoded-Source Address The mask length MUST be equal to the mask length in bits for the given Address Family and Encoding Type (32 for IPv4 native and 128 for IPv6 native). A router SHOULD ignore any messages received with any other mask length. */ if (p->prefixlen != 32) { char src_str[100]; pim_inet4_dump("", p->u.prefix4, src_str, sizeof(src_str)); zlog_warn("%s: IPv4 bad source address mask: %s/%d", __PRETTY_FUNCTION__, src_str, p->prefixlen); return -4; } addr += sizeof(struct in_addr); break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown source address encoding family=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", __PRETTY_FUNCTION__, family, src_str, ifname, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); return -5; } } return addr - buf; } #define FREE_ADDR_LIST(hello_option_addr_list) \ { \ if (hello_option_addr_list) { \ list_delete(hello_option_addr_list); \ hello_option_addr_list = 0; \ } \ } int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, const uint8_t *tlv_curr) { const uint8_t *addr; const uint8_t *pastend; zassert(hello_option_addr_list); /* Scan addr list */ addr = tlv_curr; pastend = tlv_curr + option_len; while (addr < pastend) { struct prefix tmp; int addr_offset; /* Parse ucast addr */ addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp, addr, pastend - addr); if (addr_offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", __PRETTY_FUNCTION__, src_str, ifname); FREE_ADDR_LIST(*hello_option_addr_list); return -1; } addr += addr_offset; /* Debug */ if (PIM_DEBUG_PIM_TRACE) { switch (tmp.family) { case AF_INET: { char addr_str[100]; char src_str[100]; pim_inet4_dump("", tmp.u.prefix4, addr_str, sizeof(addr_str)); pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", __PRETTY_FUNCTION__, *hello_option_addr_list ? ((int) listcount(*hello_option_addr_list)) : -1, addr_str, src_str, ifname); } break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", __PRETTY_FUNCTION__, *hello_option_addr_list ? ((int) listcount(*hello_option_addr_list)) : -1, src_str, ifname); } } } /* Exclude neighbor's primary address if incorrectly included in the secondary address list */ if (tmp.family == AF_INET) { if (tmp.u.prefix4.s_addr == src_addr.s_addr) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: ignoring primary address in secondary list from %s on %s", __PRETTY_FUNCTION__, src_str, ifname); continue; } } /* Allocate list if needed */ if (!*hello_option_addr_list) { *hello_option_addr_list = list_new(); if (!*hello_option_addr_list) { zlog_err("%s %s: failure: hello_option_addr_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return -2; } (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free; } /* Attach addr to list */ { struct prefix *p; p = prefix_new(); if (!p) { zlog_err("%s %s: failure: prefix_new()", __FILE__, __PRETTY_FUNCTION__); FREE_ADDR_LIST(*hello_option_addr_list); return -3; } p->family = tmp.family; p->u.prefix4 = tmp.u.prefix4; listnode_add(*hello_option_addr_list, p); } } /* while (addr < pastend) */ /* Mark hello option */ PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST); return 0; } quagga-1.2.4/pimd/pim_tlv.h000066400000000000000000000123021325323223500155350ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_TLV_H #define PIM_TLV_H #include #include "config.h" #include "if.h" #include "linklist.h" #ifdef HAVE_INTTYPES_H #include #endif /* HAVE_INTTYPES_H */ #define PIM_MSG_OPTION_TYPE_HOLDTIME (1) #define PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY (2) #define PIM_MSG_OPTION_TYPE_DR_PRIORITY (19) #define PIM_MSG_OPTION_TYPE_GENERATION_ID (20) #define PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH (21) #define PIM_MSG_OPTION_TYPE_ADDRESS_LIST (24) typedef uint32_t pim_hello_options; #define PIM_OPTION_MASK_HOLDTIME (1 << 0) /* recv holdtime */ #define PIM_OPTION_MASK_LAN_PRUNE_DELAY (1 << 1) /* recv lan_prune_delay */ #define PIM_OPTION_MASK_DR_PRIORITY (1 << 2) /* recv dr_priority */ #define PIM_OPTION_MASK_GENERATION_ID (1 << 3) /* recv generation_id */ #define PIM_OPTION_MASK_ADDRESS_LIST (1 << 4) /* recv secondary address list */ #define PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION (1 << 5) /* T bit value (valid if recv lan_prune_delay) */ #define PIM_RPT_BIT_MASK (1 << 0) #define PIM_WILDCARD_BIT_MASK (1 << 1) #define PIM_OPTION_SET(options, option_mask) ((options) |= (option_mask)) #define PIM_OPTION_UNSET(options, option_mask) ((options) &= ~(option_mask)) #define PIM_OPTION_IS_SET(options, option_mask) ((options) & (option_mask)) #define PIM_TLV_GET_UINT16(buf) ntohs(*(const uint16_t *)(buf)) #define PIM_TLV_GET_UINT32(buf) ntohl(*(const uint32_t *)(buf)) #define PIM_TLV_GET_TYPE(buf) PIM_TLV_GET_UINT16(buf) #define PIM_TLV_GET_LENGTH(buf) PIM_TLV_GET_UINT16(buf) #define PIM_TLV_GET_HOLDTIME(buf) PIM_TLV_GET_UINT16(buf) #define PIM_TLV_GET_PROPAGATION_DELAY(buf) (PIM_TLV_GET_UINT16(buf) & 0x7FFF) #define PIM_TLV_GET_OVERRIDE_INTERVAL(buf) PIM_TLV_GET_UINT16(buf) #define PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(buf) ((*(const uint8_t *)(buf)) & 0x80) #define PIM_TLV_GET_DR_PRIORITY(buf) PIM_TLV_GET_UINT32(buf) #define PIM_TLV_GET_GENERATION_ID(buf) PIM_TLV_GET_UINT32(buf) #define PIM_TLV_TYPE_SIZE (2) #define PIM_TLV_LENGTH_SIZE (2) #define PIM_TLV_MIN_SIZE (PIM_TLV_TYPE_SIZE + PIM_TLV_LENGTH_SIZE) #define PIM_TLV_OPTION_SIZE(option_len) (PIM_TLV_MIN_SIZE + (option_len)) uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value); uint8_t *pim_tlv_append_2uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value1, uint16_t option_value2); uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint32_t option_value); uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, struct list *ifconnected); int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, const uint8_t *tlv_curr); int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, uint16_t option_len, const uint8_t *tlv_curr); int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, const uint8_t *tlv_curr); int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, const uint8_t *tlv_curr); int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, const uint8_t *tlv_curr); int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, struct prefix *p, const uint8_t *buf, int buf_size); int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, struct prefix *p, const uint8_t *buf, int buf_size); int pim_parse_addr_source(const char *ifname, struct in_addr src_addr, struct prefix *p, uint8_t *flags, const uint8_t *buf, int buf_size); #endif /* PIM_TLV_H */ quagga-1.2.4/pimd/pim_upstream.c000066400000000000000000000450161325323223500165730ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "zebra/rib.h" #include "log.h" #include "zclient.h" #include "memory.h" #include "thread.h" #include "linklist.h" #include "pimd.h" #include "pim_pim.h" #include "pim_str.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_join.h" #include "pim_zlookup.h" #include "pim_upstream.h" #include "pim_ifchannel.h" #include "pim_neighbor.h" #include "pim_rpf.h" #include "pim_zebra.h" #include "pim_oil.h" #include "pim_macro.h" static void join_timer_start(struct pim_upstream *up); static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up); void pim_upstream_free(struct pim_upstream *up) { XFREE(MTYPE_PIM_UPSTREAM, up); } static void upstream_channel_oil_detach(struct pim_upstream *up) { if (up->channel_oil) { pim_channel_oil_del(up->channel_oil); up->channel_oil = 0; } } void pim_upstream_delete(struct pim_upstream *up) { THREAD_OFF(up->t_join_timer); upstream_channel_oil_detach(up); /* notice that listnode_delete() can't be moved into pim_upstream_free() because the later is called by list_delete_all_node() */ listnode_delete(qpim_upstream_list, up); pim_upstream_free(up); } static void send_join(struct pim_upstream *up) { zassert(up->join_state == PIM_UPSTREAM_JOINED); if (PIM_DEBUG_PIM_TRACE) { if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) { char src_str[100]; char grp_str[100]; char rpf_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s", __PRETTY_FUNCTION__, src_str, grp_str, rpf_str); /* warning only */ } } /* send Join(S,G) to the current upstream neighbor */ pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 1 /* join */); } static int on_join_timer(struct thread *t) { struct pim_upstream *up; zassert(t); up = THREAD_ARG(t); zassert(up); send_join(up); up->t_join_timer = 0; join_timer_start(up); return 0; } static void join_timer_start(struct pim_upstream *up) { if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: starting %d sec timer for upstream (S,G)=(%s,%s)", __PRETTY_FUNCTION__, qpim_t_periodic, src_str, grp_str); } zassert(!up->t_join_timer); THREAD_TIMER_ON(master, up->t_join_timer, on_join_timer, up, qpim_t_periodic); } void pim_upstream_join_timer_restart(struct pim_upstream *up) { THREAD_OFF(up->t_join_timer); join_timer_start(up); } static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up, int interval_msec) { if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: restarting %d msec timer for upstream (S,G)=(%s,%s)", __PRETTY_FUNCTION__, interval_msec, src_str, grp_str); } THREAD_OFF(up->t_join_timer); THREAD_TIMER_MSEC_ON(master, up->t_join_timer, on_join_timer, up, interval_msec); } void pim_upstream_join_suppress(struct pim_upstream *up, struct in_addr rpf_addr, int holdtime) { long t_joinsuppress_msec; long join_timer_remain_msec; t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface), 1000 * holdtime); join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; char rpf_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf_addr, rpf_str, sizeof(rpf_str)); zlog_debug("%s %s: detected Join(%s,%s) to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, rpf_str, join_timer_remain_msec, t_joinsuppress_msec); } if (join_timer_remain_msec < t_joinsuppress_msec) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s %s: suppressing Join(S,G)=(%s,%s) for %ld msec", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, t_joinsuppress_msec); } pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec); } } void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, struct pim_upstream *up, struct in_addr rpf_addr) { long join_timer_remain_msec; int t_override_msec; join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface); if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; char rpf_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf_addr, rpf_str, sizeof(rpf_str)); zlog_debug("%s: to RPF'(%s,%s)=%s: join_timer=%ld msec t_override=%d msec", debug_label, src_str, grp_str, rpf_str, join_timer_remain_msec, t_override_msec); } if (join_timer_remain_msec > t_override_msec) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: decreasing (S,G)=(%s,%s) join timer to t_override=%d msec", debug_label, src_str, grp_str, t_override_msec); } pim_upstream_join_timer_restart_msec(up, t_override_msec); } } static void forward_on(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; if (pim_macro_chisin_oiflist(ch)) pim_forward_start(ch); } /* scan iface channel list */ } /* scan iflist */ } static void forward_off(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; pim_forward_stop(ch); } /* scan iface channel list */ } /* scan iflist */ } static void pim_upstream_switch(struct pim_upstream *up, enum pim_upstream_state new_state) { enum pim_upstream_state old_state = up->join_state; zassert(old_state != new_state); up->join_state = new_state; up->state_transition = pim_time_monotonic_sec(); if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)", __PRETTY_FUNCTION__, ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"), src_str, grp_str); } pim_upstream_update_assert_tracking_desired(up); if (new_state == PIM_UPSTREAM_JOINED) { forward_on(up); send_join(up); join_timer_start(up); } else { forward_off(up); pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 0 /* prune */); zassert(up->t_join_timer); THREAD_OFF(up->t_join_timer); } } static struct pim_upstream *pim_upstream_new(struct in_addr source_addr, struct in_addr group_addr) { struct pim_upstream *up; enum pim_rpf_result rpf_result; up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up)); if (!up) { zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*up)); return 0; } up->source_addr = source_addr; up->group_addr = group_addr; up->flags = 0; up->ref_count = 1; up->t_join_timer = 0; up->join_state = 0; up->state_transition = pim_time_monotonic_sec(); up->channel_oil = 0; up->rpf.source_nexthop.interface = 0; up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY; up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference; up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric; up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY; rpf_result = pim_rpf_update(up, 0); if (rpf_result == PIM_RPF_FAILURE) { XFREE(MTYPE_PIM_UPSTREAM, up); return NULL; } listnode_add(qpim_upstream_list, up); return up; } struct pim_upstream *pim_upstream_find(struct in_addr source_addr, struct in_addr group_addr) { struct listnode *up_node; struct pim_upstream *up; for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) { if ( (source_addr.s_addr == up->source_addr.s_addr) && (group_addr.s_addr == up->group_addr.s_addr) ) { return up; } } return 0; } struct pim_upstream *pim_upstream_add(struct in_addr source_addr, struct in_addr group_addr) { struct pim_upstream *up; up = pim_upstream_find(source_addr, group_addr); if (up) { ++up->ref_count; } else { up = pim_upstream_new(source_addr, group_addr); } return up; } void pim_upstream_del(struct pim_upstream *up) { --up->ref_count; if (up->ref_count < 1) { pim_upstream_delete(up); } } /* Evaluate JoinDesired(S,G): JoinDesired(S,G) is true if there is a downstream (S,G) interface I in the set: inherited_olist(S,G) = joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) JoinDesired(S,G) may be affected by changes in the following: pim_ifp->primary_address pim_ifp->pim_dr_addr ch->ifassert_winner_metric ch->ifassert_winner ch->local_ifmembership ch->ifjoin_state ch->upstream->rpf.source_nexthop.mrib_metric_preference ch->upstream->rpf.source_nexthop.mrib_route_metric ch->upstream->rpf.source_nexthop.interface See also pim_upstream_update_join_desired() below. */ int pim_upstream_evaluate_join_desired(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; if (pim_macro_ch_lost_assert(ch)) continue; /* keep searching */ if (pim_macro_chisin_joins_or_include(ch)) return 1; /* true */ } /* scan iface channel list */ } /* scan iflist */ return 0; /* false */ } /* See also pim_upstream_evaluate_join_desired() above. */ void pim_upstream_update_join_desired(struct pim_upstream *up) { int was_join_desired; /* boolean */ int is_join_desired; /* boolean */ was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags); is_join_desired = pim_upstream_evaluate_join_desired(up); if (is_join_desired) PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags); else PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); /* switched from false to true */ if (is_join_desired && !was_join_desired) { zassert(up->join_state == PIM_UPSTREAM_NOTJOINED); pim_upstream_switch(up, PIM_UPSTREAM_JOINED); return; } /* switched from true to false */ if (!is_join_desired && was_join_desired) { zassert(up->join_state == PIM_UPSTREAM_JOINED); pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED); return; } } /* RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages Transitions from Joined State RPF'(S,G) GenID changes The upstream (S,G) state machine remains in Joined state. If the Join Timer is set to expire in more than t_override seconds, reset it so that it expires after t_override seconds. */ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr) { struct listnode *up_node; struct listnode *up_nextnode; struct pim_upstream *up; /* Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { if (PIM_DEBUG_PIM_TRACE) { char neigh_str[100]; char src_str[100]; char grp_str[100]; char rpf_addr_str[100]; pim_inet4_dump("", neigh_addr, neigh_str, sizeof(neigh_str)); pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s", __PRETTY_FUNCTION__, neigh_str, src_str, grp_str, up->join_state == PIM_UPSTREAM_JOINED, rpf_addr_str); } /* consider only (S,G) upstream in Joined state */ if (up->join_state != PIM_UPSTREAM_JOINED) continue; /* match RPF'(S,G)=neigh_addr */ if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr) continue; pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change", up, neigh_addr); } } void pim_upstream_rpf_interface_changed(struct pim_upstream *up, struct interface *old_rpf_ifp) { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { struct listnode *chnode; struct listnode *chnextnode; struct pim_ifchannel *ch; struct pim_interface *pim_ifp; pim_ifp = ifp->info; if (!pim_ifp) continue; /* search all ifchannels */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { if ( /* RPF_interface(S) was NOT I */ (old_rpf_ifp == ch->interface) && /* RPF_interface(S) stopped being I */ (ch->upstream->rpf.source_nexthop.interface != ch->interface) ) { assert_action_a5(ch); } } /* PIM_IFASSERT_I_AM_LOSER */ pim_ifchannel_update_assert_tracking_desired(ch); } } } void pim_upstream_update_could_assert(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; pim_ifchannel_update_could_assert(ch); } /* scan iface channel list */ } /* scan iflist */ } void pim_upstream_update_my_assert_metric(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; pim_ifchannel_update_my_assert_metric(ch); } /* scan iface channel list */ } /* scan iflist */ } static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; pim_ifchannel_update_assert_tracking_desired(ch); } /* scan iface channel list */ } /* scan iflist */ } quagga-1.2.4/pimd/pim_upstream.h000066400000000000000000000105061325323223500165740ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_UPSTREAM_H #define PIM_UPSTREAM_H #include #define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED (1 << 0) #define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED (2 << 0) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) /* RFC 4601: Metric Preference Preference value assigned to the unicast routing protocol that provided the route to the multicast source or Rendezvous-Point. Metric The unicast routing table metric associated with the route used to reach the multicast source or Rendezvous-Point. The metric is in units applicable to the unicast routing protocol used. */ struct pim_nexthop { struct interface *interface; /* RPF_interface(S) */ struct in_addr mrib_nexthop_addr; /* MRIB.next_hop(S) */ uint32_t mrib_metric_preference; /* MRIB.pref(S) */ uint32_t mrib_route_metric; /* MRIB.metric(S) */ }; struct pim_rpf { struct pim_nexthop source_nexthop; struct in_addr rpf_addr; /* RPF'(S,G) */ }; enum pim_rpf_result { PIM_RPF_OK = 0, PIM_RPF_CHANGED, PIM_RPF_FAILURE }; enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, PIM_UPSTREAM_JOINED }; /* Upstream (S,G) channel in Joined state (S,G) in the "Not Joined" state is not represented See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message */ struct pim_upstream { struct in_addr source_addr; /* (S,G) source key */ struct in_addr group_addr; /* (S,G) group key */ uint32_t flags; struct channel_oil *channel_oil; enum pim_upstream_state join_state; int ref_count; struct pim_rpf rpf; struct thread *t_join_timer; int64_t state_transition; /* Record current state uptime */ }; void pim_upstream_free(struct pim_upstream *up); void pim_upstream_delete(struct pim_upstream *up); struct pim_upstream *pim_upstream_find(struct in_addr source_addr, struct in_addr group_addr); struct pim_upstream *pim_upstream_add(struct in_addr source_addr, struct in_addr group_addr); void pim_upstream_del(struct pim_upstream *up); int pim_upstream_evaluate_join_desired(struct pim_upstream *up); void pim_upstream_update_join_desired(struct pim_upstream *up); void pim_upstream_join_suppress(struct pim_upstream *up, struct in_addr rpf_addr, int holdtime); void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, struct pim_upstream *up, struct in_addr rpf_addr); void pim_upstream_join_timer_restart(struct pim_upstream *up); void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr); void pim_upstream_rpf_interface_changed(struct pim_upstream *up, struct interface *old_rpf_ifp); void pim_upstream_update_could_assert(struct pim_upstream *up); void pim_upstream_update_my_assert_metric(struct pim_upstream *up); #endif /* PIM_UPSTREAM_H */ quagga-1.2.4/pimd/pim_util.c000066400000000000000000000052711325323223500157070ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "pim_util.h" /* RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) If QQIC < 128, QQI = QQIC If QQIC >= 128, QQI = (mant | 0x10) << (exp + 3) 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+ Since exp=0..7 then (exp+3)=3..10, then QQI has one of the following bit patterns: exp=0: QQI = 0000.0000.1MMM.M000 exp=1: QQI = 0000.0001.MMMM.0000 ... exp=6: QQI = 001M.MMM0.0000.0000 exp=7: QQI = 01MM.MM00.0000.0000 --------- --------- 0x4 0x0 0x0 0x0 */ uint8_t igmp_msg_encode16to8(uint16_t value) { uint8_t code; if (value < 128) { code = value; } else { uint16_t mask = 0x4000; uint8_t exp; uint16_t mant; for (exp = 7; exp > 0; --exp) { if (mask & value) break; mask >>= 1; } mant = 0x000F & (value >> (exp + 3)); code = ((uint8_t) 1 << 7) | ((uint8_t) exp << 4) | (uint8_t) mant; } return code; } /* RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) If QQIC < 128, QQI = QQIC If QQIC >= 128, QQI = (mant | 0x10) << (exp + 3) 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+ */ uint16_t igmp_msg_decode8to16(uint8_t code) { uint16_t value; if (code < 128) { value = code; } else { uint16_t mant = (code & 0x0F); uint8_t exp = (code & 0x70) >> 4; value = (mant | 0x10) << (exp + 3); } return value; } void pim_pkt_dump(const char *label, const uint8_t *buf, int size) { char dump_buf[1000]; int i = 0; int j = 0; for (; i < size; ++i, j += 2) { int left = sizeof(dump_buf) - j; if (left < 4) { if (left > 1) { strcat(dump_buf + j, "!"); /* mark as truncated */ } break; } snprintf(dump_buf + j, left, "%02x", buf[i]); } zlog_debug("%s: pkt dump size=%d: %s", label, size, dump_buf); } quagga-1.2.4/pimd/pim_util.h000066400000000000000000000021431325323223500157070ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_UTIL_H #define PIM_UTIL_H #include #include #include "checksum.h" uint8_t igmp_msg_encode16to8(uint16_t value); uint16_t igmp_msg_decode8to16(uint8_t code); void pim_pkt_dump(const char *label, const uint8_t *buf, int size); #endif /* PIM_UTIL_H */ quagga-1.2.4/pimd/pim_version.c000066400000000000000000000016451325323223500164200ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "pim_version.h" const char * const PIMD_VERSION = PIMD_VERSION_STR; quagga-1.2.4/pimd/pim_version.h000066400000000000000000000017171325323223500164250ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_VERSION_H #define PIM_VERSION_H #define PIMD_VERSION_STR "0.166" const char * const PIMD_VERSION; #endif /* PIM_VERSION_H */ quagga-1.2.4/pimd/pim_vty.c000066400000000000000000000121071325323223500155500ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "if.h" #include "linklist.h" #include "pimd.h" #include "pim_vty.h" #include "pim_iface.h" #include "pim_cmd.h" #include "pim_str.h" #include "pim_ssmpingd.h" #include "pim_pim.h" #include "pim_static.h" int pim_debug_config_write(struct vty *vty) { int writes = 0; if (PIM_DEBUG_IGMP_EVENTS) { vty_out(vty, "debug igmp events%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_IGMP_PACKETS) { vty_out(vty, "debug igmp packets%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_IGMP_TRACE) { vty_out(vty, "debug igmp trace%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_MROUTE) { vty_out(vty, "debug mroute%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_EVENTS) { vty_out(vty, "debug pim events%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_PACKETS) { vty_out(vty, "debug pim packets%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { vty_out(vty, "debug pim packet-dump send%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { vty_out(vty, "debug pim packet-dump receive%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_TRACE) { vty_out(vty, "debug pim trace%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_ZEBRA) { vty_out(vty, "debug pim zebra%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_SSMPINGD) { vty_out(vty, "debug ssmpingd%s", VTY_NEWLINE); ++writes; } return writes; } int pim_global_config_write(struct vty *vty) { int writes = 0; if (PIM_MROUTE_IS_ENABLED) { vty_out(vty, "%s%s", PIM_CMD_IP_MULTICAST_ROUTING, VTY_NEWLINE); ++writes; } if (qpim_ssmpingd_list) { struct listnode *node; struct ssmpingd_sock *ss; vty_out(vty, "!%s", VTY_NEWLINE); ++writes; for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { char source_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE); ++writes; } } return writes; } int pim_interface_config_write(struct vty *vty) { int writes = 0; struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { /* IF name */ vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); ++writes; if (ifp->info) { struct pim_interface *pim_ifp = ifp->info; /* IF ip pim ssm */ if (PIM_IF_TEST_PIM(pim_ifp->options)) { vty_out(vty, " ip pim ssm%s", VTY_NEWLINE); ++writes; } /* IF ip pim drpriority */ if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) { vty_out(vty, " ip pim drpriority %d%s", pim_ifp->pim_dr_priority, VTY_NEWLINE); ++writes; } /* IF ip pim hello */ if (pim_ifp->pim_hello_period != PIM_DEFAULT_HELLO_PERIOD) { vty_out(vty, " ip pim hello %d", pim_ifp->pim_hello_period); if (pim_ifp->pim_default_holdtime != -1) vty_out(vty, " %d", pim_ifp->pim_default_holdtime); vty_out(vty, "%s", VTY_NEWLINE); } /* IF ip igmp */ if (PIM_IF_TEST_IGMP(pim_ifp->options)) { vty_out(vty, " ip igmp%s", VTY_NEWLINE); ++writes; } /* IF ip igmp query-interval */ if (pim_ifp->igmp_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL) { vty_out(vty, " %s %d%s", PIM_CMD_IP_IGMP_QUERY_INTERVAL, pim_ifp->igmp_default_query_interval, VTY_NEWLINE); ++writes; } /* IF ip igmp query-max-response-time */ if (pim_ifp->igmp_query_max_response_time_dsec != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) { vty_out(vty, " %s %d%s", PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, pim_ifp->igmp_query_max_response_time_dsec, VTY_NEWLINE); ++writes; } /* IF ip igmp join */ if (pim_ifp->igmp_join_list) { struct listnode *node; struct igmp_join *ij; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, node, ij)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", ij->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", ij->source_addr, source_str, sizeof(source_str)); vty_out(vty, " ip igmp join %s %s%s", group_str, source_str, VTY_NEWLINE); ++writes; } } writes += pim_static_write_mroute (vty, ifp); } vty_out(vty, "!%s", VTY_NEWLINE); ++writes; } return writes; } quagga-1.2.4/pimd/pim_vty.h000066400000000000000000000020361325323223500155550ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_VTY_H #define PIM_VTY_H #include "vty.h" int pim_debug_config_write(struct vty *vty); int pim_global_config_write(struct vty *vty); int pim_interface_config_write(struct vty *vty); #endif /* PIM_VTY_H */ quagga-1.2.4/pimd/pim_zebra.c000066400000000000000000001223341325323223500160350ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "zebra/rib.h" #include "if.h" #include "log.h" #include "prefix.h" #include "zclient.h" #include "stream.h" #include "network.h" #include "pimd.h" #include "pim_pim.h" #include "pim_zebra.h" #include "pim_iface.h" #include "pim_str.h" #include "pim_oil.h" #include "pim_rpf.h" #include "pim_time.h" #include "pim_join.h" #include "pim_zlookup.h" #include "pim_ifchannel.h" #undef PIM_DEBUG_IFADDR_DUMP #define PIM_DEBUG_IFADDR_DUMP static int fib_lookup_if_vif_index(struct in_addr addr); static int del_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask); /* Router-id update message from zebra. */ static int pim_router_id_update_zebra(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct prefix router_id; zebra_router_id_update_read(zclient->ibuf, &router_id); return 0; } static int pim_zebra_if_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; /* zebra api adds/dels interfaces using the same call interface_add_read below, see comments in lib/zclient.c */ ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); if (!ifp) return 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } if (if_is_operative(ifp)) pim_if_addr_add_all(ifp); return 0; } static int pim_zebra_if_del(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; /* zebra api adds/dels interfaces using the same call interface_add_read below, see comments in lib/zclient.c comments in lib/zclient.c seem to indicate that calling zebra_interface_add_read is the correct call, but that results in an attemted out of bounds read which causes pimd to assert. Other clients use zebra_interface_state_read and it appears to work just fine. */ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); if (!ifp) return 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } if (!if_is_operative(ifp)) pim_if_addr_del_all(ifp); return 0; } static int pim_zebra_if_state_up(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; /* zebra api notifies interface up/down events by using the same call zebra_interface_state_read below, see comments in lib/zclient.c */ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); if (!ifp) return 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } if (if_is_operative(ifp)) { /* pim_if_addr_add_all() suffices for bringing up both IGMP and PIM */ pim_if_addr_add_all(ifp); } return 0; } static int pim_zebra_if_state_down(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; /* zebra api notifies interface up/down events by using the same call zebra_interface_state_read below, see comments in lib/zclient.c */ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); if (!ifp) return 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } if (!if_is_operative(ifp)) { /* pim_if_addr_del_all() suffices for shutting down IGMP, but not for shutting down PIM */ pim_if_addr_del_all(ifp); /* pim_sock_delete() closes the socket, stops read and timer threads, and kills all neighbors. */ if (ifp->info) { pim_sock_delete(ifp, "link down"); } } return 0; } #ifdef PIM_DEBUG_IFADDR_DUMP static void dump_if_address(struct interface *ifp) { struct connected *ifc; struct listnode *node; zlog_debug("%s %s: interface %s addresses:", __FILE__, __PRETTY_FUNCTION__, ifp->name); for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; zlog_debug("%s %s: interface %s address %s %s", __FILE__, __PRETTY_FUNCTION__, ifp->name, inet_ntoa(p->u.prefix4), CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } } #endif static int pim_zebra_if_address_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; /* zebra api notifies address adds/dels events by using the same call interface_add_read below, see comments in lib/zclient.c zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...) will add address to interface list by calling connected_add_by_prefix() */ c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); if (!c) return 0; p = c->address; if (p->family != AF_INET) return 0; if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); zlog_debug("%s: %s connected IP address %s flags %u %s", __PRETTY_FUNCTION__, c->ifp->name, buf, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); #ifdef PIM_DEBUG_IFADDR_DUMP dump_if_address(c->ifp); #endif } if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { /* trying to add primary address */ struct in_addr primary_addr = pim_find_primary_addr(c->ifp); if (primary_addr.s_addr != p->u.prefix4.s_addr) { if (PIM_DEBUG_ZEBRA) { /* but we had a primary address already */ char buf[BUFSIZ]; char old[100]; prefix2str(p, buf, BUFSIZ); pim_inet4_dump("", primary_addr, old, sizeof(old)); zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s", __PRETTY_FUNCTION__, c->ifp->name, old, buf); } SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY); } } pim_if_addr_add(c); return 0; } static int pim_zebra_if_address_del(int command, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; /* zebra api notifies address adds/dels events by using the same call interface_add_read below, see comments in lib/zclient.c zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...) will remove address from interface list by calling connected_delete_by_prefix() */ c = zebra_interface_address_read(command, client->ibuf, vrf_id); if (!c) return 0; p = c->address; if (p->family != AF_INET) return 0; if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); zlog_debug("%s: %s disconnected IP address %s flags %u %s", __PRETTY_FUNCTION__, c->ifp->name, buf, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); #ifdef PIM_DEBUG_IFADDR_DUMP dump_if_address(c->ifp); #endif } pim_if_addr_del(c, 0); return 0; } static void scan_upstream_rpf_cache() { struct listnode *up_node; struct listnode *up_nextnode; struct pim_upstream *up; for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { struct pim_rpf old_rpf; enum pim_rpf_result rpf_result; rpf_result = pim_rpf_update(up, &old_rpf); if (rpf_result == PIM_RPF_FAILURE) continue; if (rpf_result == PIM_RPF_CHANGED) { if (up->join_state == PIM_UPSTREAM_JOINED) { /* RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages Transitions from Joined State RPF'(S,G) changes not due to an Assert The upstream (S,G) state machine remains in Joined state. Send Join(S,G) to the new upstream neighbor, which is the new value of RPF'(S,G). Send Prune(S,G) to the old upstream neighbor, which is the old value of RPF'(S,G). Set the Join Timer (JT) to expire after t_periodic seconds. */ /* send Prune(S,G) to the old upstream neighbor */ pim_joinprune_send(old_rpf.source_nexthop.interface, old_rpf.rpf_addr, up->source_addr, up->group_addr, 0 /* prune */); /* send Join(S,G) to the current upstream neighbor */ pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 1 /* join */); pim_upstream_join_timer_restart(up); } /* up->join_state == PIM_UPSTREAM_JOINED */ /* FIXME can join_desired actually be changed by pim_rpf_update() returning PIM_RPF_CHANGED ? */ pim_upstream_update_join_desired(up); } /* PIM_RPF_CHANGED */ } /* for (qpim_upstream_list) */ } void pim_scan_oil() { struct listnode *node; struct listnode *nextnode; struct channel_oil *c_oil; qpim_scan_oil_last = pim_time_monotonic_sec(); ++qpim_scan_oil_events; for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) { int old_vif_index; int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin); if (input_iface_vif_index < 1) { char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); continue; } if (input_iface_vif_index == c_oil->oil.mfcc_parent) { /* RPF unchanged */ continue; } if (PIM_DEBUG_ZEBRA) { struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, old_iif ? old_iif->name : "", c_oil->oil.mfcc_parent, new_iif ? new_iif->name : "", input_iface_vif_index); } /* new iif loops to existing oif ? */ if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) { struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); if (PIM_DEBUG_ZEBRA) { char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, new_iif ? new_iif->name : "", input_iface_vif_index); } del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY); } /* update iif vif_index */ old_vif_index = c_oil->oil.mfcc_parent; c_oil->oil.mfcc_parent = input_iface_vif_index; /* update kernel multicast forwarding cache (MFC) */ if (pim_mroute_add(&c_oil->oil)) { /* just log warning */ struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index); struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, old_iif ? old_iif->name : "", c_oil->oil.mfcc_parent, new_iif ? new_iif->name : "", input_iface_vif_index); continue; } } /* for (qpim_channel_oil_list) */ } static int on_rpf_cache_refresh(struct thread *t) { zassert(t); zassert(qpim_rpf_cache_refresher); qpim_rpf_cache_refresher = 0; /* update PIM protocol state */ scan_upstream_rpf_cache(); /* update kernel multicast forwarding cache (MFC) */ pim_scan_oil(); qpim_rpf_cache_refresh_last = pim_time_monotonic_sec(); ++qpim_rpf_cache_refresh_events; return 0; } static void sched_rpf_cache_refresh() { ++qpim_rpf_cache_refresh_requests; if (qpim_rpf_cache_refresher) { /* Refresh timer is already running */ return; } /* Start refresh timer */ if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: triggering %ld msec timer", __PRETTY_FUNCTION__, qpim_rpf_cache_refresh_delay_msec); } THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher, on_rpf_cache_refresh, 0, qpim_rpf_cache_refresh_delay_msec); } static int redist_read_ipv4_route(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv4 api; ifindex_t ifindex; struct in_addr nexthop; struct prefix_ipv4 p; int min_len = 4; if (length < min_len) { zlog_warn("%s %s: short buffer: length=%d min=%d", __FILE__, __PRETTY_FUNCTION__, length, min_len); return -1; } 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 length. */ memset(&p, 0, sizeof(struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc(s); min_len += PSIZE(p.prefixlen) + CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s", __FILE__, __PRETTY_FUNCTION__, length, min_len, CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); } if (length < min_len) { zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s", __FILE__, __PRETTY_FUNCTION__, length, min_len, CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); return -1; } /* IPv4 prefix. */ 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); } api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? stream_getc(s) : 0; api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? stream_getl(s) : 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) api.tag = stream_getl (s); else api.tag = 0; switch (command) { case ZEBRA_IPV4_ROUTE_ADD: if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: add %s %s/%d " "nexthop %s ifindex %d metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), ifindex, CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss", api.metric, CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss", api.distance); } break; case ZEBRA_IPV4_ROUTE_DELETE: if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: delete %s %s/%d " "nexthop %s ifindex %d metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), ifindex, CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss", api.metric, CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss", api.distance); } break; default: zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command); return -1; } sched_rpf_cache_refresh(); return 0; } static void pim_zebra_connected(struct zclient *zclient) { zclient_send_requests(zclient, VRF_DEFAULT); } void pim_zebra_init (struct thread_master *master, char *zebra_sock_path) { int i; if (zebra_sock_path) zclient_serv_path_set(zebra_sock_path); #ifdef HAVE_TCP_ZEBRA zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT); #else zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get()); #endif /* Socket for receiving updates from Zebra daemon */ qpim_zclient_update = zclient_new (master); qpim_zclient_update->zebra_connected = pim_zebra_connected; qpim_zclient_update->router_id_update = pim_router_id_update_zebra; qpim_zclient_update->interface_add = pim_zebra_if_add; qpim_zclient_update->interface_delete = pim_zebra_if_del; qpim_zclient_update->interface_up = pim_zebra_if_state_up; qpim_zclient_update->interface_down = pim_zebra_if_state_down; qpim_zclient_update->interface_address_add = pim_zebra_if_address_add; qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del; qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route; qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route; zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); if (PIM_DEBUG_PIM_TRACE) { zlog_info("zclient_init cleared redistribution request"); } zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM); /* Request all redistribution */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (i == qpim_zclient_update->redist_default) continue; vrf_bitmap_set(qpim_zclient_update->redist[i], VRF_DEFAULT); if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: requesting redistribution for %s (%i)", __PRETTY_FUNCTION__, zebra_route_string(i), i); } } /* Request default information */ vrf_bitmap_set(qpim_zclient_update->default_information, VRF_DEFAULT); if (PIM_DEBUG_PIM_TRACE) { zlog_info("%s: requesting default information redistribution", __PRETTY_FUNCTION__); zlog_notice("%s: zclient update socket initialized", __PRETTY_FUNCTION__); } zassert(!qpim_zclient_lookup); qpim_zclient_lookup = zclient_lookup_new(); zassert(qpim_zclient_lookup); } void igmp_anysource_forward_start(struct igmp_group *group) { /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ zassert(group->group_filtermode_isexcl); zassert(listcount(group->group_source_list) < 1); if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("%s %s: UNIMPLEMENTED", __FILE__, __PRETTY_FUNCTION__); } } void igmp_anysource_forward_stop(struct igmp_group *group) { /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0)); if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("%s %s: UNIMPLEMENTED", __FILE__, __PRETTY_FUNCTION__); } } static int fib_lookup_if_vif_index(struct in_addr addr) { struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; int num_ifindex; int vif_index; ifindex_t first_ifindex; num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: could not find nexthop ifindex for address %s", __FILE__, __PRETTY_FUNCTION__, addr_str); return -1; } first_ifindex = nexthop_tab[0].ifindex; if (num_ifindex > 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", __FILE__, __PRETTY_FUNCTION__, num_ifindex, addr_str, first_ifindex); /* debug warning only, do not return */ } if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s", __FILE__, __PRETTY_FUNCTION__, first_ifindex, ifindex2ifname(first_ifindex), addr_str); } vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex); if (vif_index < 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s", __FILE__, __PRETTY_FUNCTION__, vif_index, addr_str); return -2; } zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); if (vif_index > qpim_mroute_oif_highest_vif_index) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s", __FILE__, __PRETTY_FUNCTION__, vif_index, qpim_mroute_oif_highest_vif_index, addr_str); zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?", __FILE__, __PRETTY_FUNCTION__, ifindex2ifname(vif_index), vif_index); return -3; } return vif_index; } static int add_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask) { struct pim_interface *pim_ifp; int old_ttl; zassert(channel_oil); pim_ifp = oif->info; if (PIM_DEBUG_MROUTE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, proto_mask, oif->name, pim_ifp->mroute_vif_index); } if (pim_ifp->mroute_vif_index < 1) { zlog_warn("%s %s: interface %s vif_index=%d < 1", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index); return -1; } #ifdef PIM_ENFORCE_LOOPFREE_MFC /* Prevent creating MFC entry with OIF=IIF. This is a protection against implementation mistakes. PIM protocol implicitely ensures loopfree multicast topology. IGMP must be protected against adding looped MFC entries created by both source and receiver attached to the same interface. See TODO T22. */ if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); return -2; } #endif zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index); /* Prevent single protocol from subscribing same interface to channel (S,G) multiple times */ if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], source_str, group_str); return -3; } /* Allow other protocol to request subscription of same interface to channel (S,G) multiple times, by silently ignoring further requests */ if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { /* Check the OIF really exists before returning, and only log warning otherwise */ if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], source_str, group_str); } return 0; } old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]; if (old_ttl > 0) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); return -4; } channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; if (pim_mroute_add(&channel_oil->oil)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; return -5; } channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec(); ++channel_oil->oil_size; channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; if (PIM_DEBUG_MROUTE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, proto_mask, oif->name, pim_ifp->mroute_vif_index); } return 0; } static int del_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask) { struct pim_interface *pim_ifp; int old_ttl; zassert(channel_oil); pim_ifp = oif->info; zassert(pim_ifp->mroute_vif_index >= 1); zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index); if (PIM_DEBUG_MROUTE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, proto_mask, oif->name, pim_ifp->mroute_vif_index); } /* Prevent single protocol from unsubscribing same interface from channel (S,G) multiple times */ if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], source_str, group_str); return -2; } /* Mark that protocol is no longer interested in this OIF */ channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask; /* Allow multiple protocols to unsubscribe same interface from channel (S,G) multiple times, by silently ignoring requests while there is at least one protocol interested in the channel */ if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { /* Check the OIF keeps existing before returning, and only log warning otherwise */ if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], source_str, group_str); } return 0; } old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]; if (old_ttl < 1) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); return -3; } channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0; if (pim_mroute_add(&channel_oil->oil)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; return -4; } --channel_oil->oil_size; if (channel_oil->oil_size < 1) { if (pim_mroute_del(&channel_oil->oil)) { /* just log a warning in case of failure */ char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); } } if (PIM_DEBUG_MROUTE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, proto_mask, oif->name, pim_ifp->mroute_vif_index); } return 0; } void igmp_source_forward_start(struct igmp_source *source) { struct igmp_group *group; int result; if (PIM_DEBUG_IGMP_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d", __PRETTY_FUNCTION__, source_str, group_str, source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->interface->name, IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); } /* Prevent IGMP interface from installing multicast route multiple times */ if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { return; } group = source->source_group; if (!source->source_channel_oil) { struct pim_interface *pim_oif; int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr); if (input_iface_vif_index < 1) { char source_str[100]; pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_warn("%s %s: could not find input interface for source %s", __FILE__, __PRETTY_FUNCTION__, source_str); return; } /* Protect IGMP against adding looped MFC entries created by both source and receiver attached to the same interface. See TODO T22. */ pim_oif = source->source_group->group_igmp_sock->interface->info; if (!pim_oif) { zlog_warn("%s: multicast not enabled on oif=%s ?", __PRETTY_FUNCTION__, source->source_group->group_igmp_sock->interface->name); return; } if (pim_oif->mroute_vif_index < 1) { zlog_warn("%s %s: oif=%s vif_index=%d < 1", __FILE__, __PRETTY_FUNCTION__, source->source_group->group_igmp_sock->interface->name, pim_oif->mroute_vif_index); return; } if (input_iface_vif_index == pim_oif->mroute_vif_index) { /* ignore request for looped MFC entry */ if (PIM_DEBUG_IGMP_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d", __PRETTY_FUNCTION__, source_str, group_str, source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->interface->name, input_iface_vif_index); } return; } source->source_channel_oil = pim_channel_oil_add(group->group_addr, source->source_addr, input_iface_vif_index); if (!source->source_channel_oil) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); return; } } result = add_oif(source->source_channel_oil, group->group_igmp_sock->interface, PIM_OIF_FLAG_PROTO_IGMP); if (result) { zlog_warn("%s: add_oif() failed with return=%d", __func__, result); return; } /* Feed IGMPv3-gathered local membership information into PIM per-interface (S,G) state. */ pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, source->source_addr, group->group_addr); IGMP_SOURCE_DO_FORWARDING(source->source_flags); } /* igmp_source_forward_stop: stop fowarding, but keep the source igmp_source_delete: stop fowarding, and delete the source */ void igmp_source_forward_stop(struct igmp_source *source) { struct igmp_group *group; int result; if (PIM_DEBUG_IGMP_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d", __PRETTY_FUNCTION__, source_str, group_str, source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->interface->name, IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); } /* Prevent IGMP interface from removing multicast route multiple times */ if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { return; } group = source->source_group; /* It appears that in certain circumstances that igmp_source_forward_stop is called when IGMP forwarding was not enabled in oif_flags for this outgoing interface. Possibly because of multiple calls. When that happens, we enter the below if statement and this function returns early which in turn triggers the calling function to assert. Making the call to del_oif and ignoring the return code fixes the issue without ill effect, similar to pim_forward_stop below. */ result = del_oif(source->source_channel_oil, group->group_igmp_sock->interface, PIM_OIF_FLAG_PROTO_IGMP); if (result) { zlog_warn("%s: del_oif() failed with return=%d", __func__, result); return; } /* Feed IGMPv3-gathered local membership information into PIM per-interface (S,G) state. */ pim_ifchannel_local_membership_del(group->group_igmp_sock->interface, source->source_addr, group->group_addr); IGMP_SOURCE_DONT_FORWARDING(source->source_flags); } void pim_forward_start(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: (S,G)=(%s,%s) oif=%s", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name); } if (!up->channel_oil) { int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr); if (input_iface_vif_index < 1) { char source_str[100]; pim_inet4_dump("", up->source_addr, source_str, sizeof(source_str)); zlog_warn("%s %s: could not find input interface for source %s", __FILE__, __PRETTY_FUNCTION__, source_str); return; } up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr, input_iface_vif_index); if (!up->channel_oil) { char group_str[100]; char source_str[100]; pim_inet4_dump("", up->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", up->source_addr, source_str, sizeof(source_str)); zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); return; } } add_oif(up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM); } void pim_forward_stop(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: (S,G)=(%s,%s) oif=%s", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name); } if (!up->channel_oil) { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name); return; } del_oif(up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM); } quagga-1.2.4/pimd/pim_zebra.h000066400000000000000000000025631325323223500160430ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_ZEBRA_H #define PIM_ZEBRA_H #include "pim_igmp.h" #include "pim_ifchannel.h" void pim_zebra_init (struct thread_master *master, char *zebra_sock_path); void pim_scan_oil(void); void igmp_anysource_forward_start(struct igmp_group *group); void igmp_anysource_forward_stop(struct igmp_group *group); void igmp_source_forward_start(struct igmp_source *source); void igmp_source_forward_stop(struct igmp_source *source); void pim_forward_start(struct pim_ifchannel *ch); void pim_forward_stop(struct pim_ifchannel *ch); #endif /* PIM_ZEBRA_H */ quagga-1.2.4/pimd/pim_zlookup.c000066400000000000000000000304441325323223500164350ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "zebra/rib.h" #include "log.h" #include "prefix.h" #include "zclient.h" #include "stream.h" #include "network.h" #include "thread.h" #include "pimd.h" #include "pim_pim.h" #include "pim_str.h" #include "pim_zlookup.h" extern int zclient_debug; static void zclient_lookup_sched(struct zclient *zlookup, int delay); /* Connect to zebra for nexthop lookup. */ static int zclient_lookup_connect(struct thread *t) { struct zclient *zlookup; zlookup = THREAD_ARG(t); zlookup->t_connect = NULL; if (zlookup->sock >= 0) { return 0; } if (zclient_socket_connect(zlookup) < 0) { ++zlookup->fail; zlog_warn("%s: failure connecting zclient socket: failures=%d", __PRETTY_FUNCTION__, zlookup->fail); } else { zlookup->fail = 0; /* reset counter on connection */ } zassert(!zlookup->t_connect); if (zlookup->sock < 0) { /* Since last connect failed, retry within 10 secs */ zclient_lookup_sched(zlookup, 10); return -1; } return 0; } /* Schedule connection with delay. */ static void zclient_lookup_sched(struct zclient *zlookup, int delay) { zassert(!zlookup->t_connect); THREAD_TIMER_ON(master, zlookup->t_connect, zclient_lookup_connect, zlookup, delay); zlog_notice("%s: zclient lookup connection scheduled for %d seconds", __PRETTY_FUNCTION__, delay); } /* Schedule connection for now. */ static void zclient_lookup_sched_now(struct zclient *zlookup) { zassert(!zlookup->t_connect); zlookup->t_connect = thread_add_event(master, zclient_lookup_connect, zlookup, 0); zlog_notice("%s: zclient lookup immediate connection scheduled", __PRETTY_FUNCTION__); } /* Schedule reconnection, if needed. */ static void zclient_lookup_reconnect(struct zclient *zlookup) { if (zlookup->t_connect) { return; } zclient_lookup_sched_now(zlookup); } static void zclient_lookup_failed(struct zclient *zlookup) { if (zlookup->sock >= 0) { if (close(zlookup->sock)) { zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, zlookup->sock, errno, safe_strerror(errno)); } zlookup->sock = -1; } zclient_lookup_reconnect(zlookup); } struct zclient *zclient_lookup_new() { struct zclient *zlookup; zlookup = zclient_new (master); if (!zlookup) { zlog_err("%s: zclient_new() failure", __PRETTY_FUNCTION__); return 0; } zlookup->sock = -1; zlookup->ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ); zlookup->obuf = stream_new(ZEBRA_MAX_PACKET_SIZ); zlookup->t_connect = 0; zclient_lookup_sched_now(zlookup); zlog_notice("%s: zclient lookup socket initialized", __PRETTY_FUNCTION__); return zlookup; } static int zclient_read_nexthop(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr) { int num_ifindex = 0; struct stream *s; const uint16_t MIN_LEN = 10; /* getipv4=4 getc=1 getl=4 getc=1 */ uint16_t length; u_char marker; u_char version; uint16_t vrf_id; uint16_t command; struct in_addr raddr; uint8_t distance; uint32_t metric; int nexthop_num; int i, err; if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str); } s = zlookup->ibuf; stream_reset(s); err = zclient_read_header (s, zlookup->sock, &length, &marker, &version, &vrf_id, &command); if (err < 0) { zlog_err("%s %s: zclient_read_header() failed", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -1; } if (length < MIN_LEN) { zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d", __FILE__, __PRETTY_FUNCTION__, length, MIN_LEN); zclient_lookup_failed(zlookup); return -2; } if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) { zlog_err("%s: socket %d command mismatch: %d", __func__, zlookup->sock, command); return -5; } raddr.s_addr = stream_get_ipv4(s); if (raddr.s_addr != addr.s_addr) { char addr_str[100]; char raddr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", raddr, raddr_str, sizeof(raddr_str)); zlog_warn("%s: address mismatch: addr=%s raddr=%s", __PRETTY_FUNCTION__, addr_str, raddr_str); /* warning only */ } distance = stream_getc(s); metric = stream_getl(s); nexthop_num = stream_getc(s); if (nexthop_num < 1) { zlog_err("%s: socket %d bad nexthop_num=%d", __func__, zlookup->sock, nexthop_num); return -6; } length -= MIN_LEN; for (i = 0; i < nexthop_num; ++i) { enum nexthop_types_t nexthop_type; if (length < 1) { zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d", __func__, zlookup->sock, length); return -7; } nexthop_type = stream_getc(s); --length; switch (nexthop_type) { case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: case ZEBRA_NEXTHOP_IPV4_IFINDEX: if (num_ifindex >= tab_size) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", __FILE__, __PRETTY_FUNCTION__, (num_ifindex + 1), tab_size, addr_str); return num_ifindex; } if (nexthop_type == ZEBRA_NEXTHOP_IPV4_IFINDEX) { if (length < 4) { zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d", __func__, zlookup->sock, length); return -8; } nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); length -= 4; } else { nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY; } nexthop_tab[num_ifindex].ifindex = stream_getl(s); nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].route_metric = metric; ++num_ifindex; break; case ZEBRA_NEXTHOP_IPV4: if (num_ifindex >= tab_size) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", __FILE__, __PRETTY_FUNCTION__, (num_ifindex + 1), tab_size, addr_str); return num_ifindex; } nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); length -= 4; nexthop_tab[num_ifindex].ifindex = 0; nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].route_metric = metric; if (PIM_DEBUG_ZEBRA) { char addr_str[100]; char nexthop_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str)); zlog_debug("%s %s: zebra returned recursive nexthop %s for address %s", __FILE__, __PRETTY_FUNCTION__, nexthop_str, addr_str); } ++num_ifindex; break; default: /* do nothing */ { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s", __FILE__, __PRETTY_FUNCTION__, nexthop_type, addr_str); } break; } } return num_ifindex; } static int zclient_lookup_nexthop_once(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr) { struct stream *s; int ret; if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str); } /* Check socket. */ if (zlookup->sock < 0) { zlog_err("%s %s: zclient lookup socket is not connected", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -1; } s = zlookup->obuf; stream_reset(s); zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, VRF_DEFAULT); stream_put_in_addr(s, &addr); stream_putw_at(s, 0, stream_get_endp(s)); ret = writen(zlookup->sock, s->data, stream_get_endp(s)); if (ret < 0) { zlog_err("%s %s: writen() failure writing to zclient lookup socket", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -2; } if (ret == 0) { zlog_err("%s %s: connection closed on zclient lookup socket", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -3; } return zclient_read_nexthop(zlookup, nexthop_tab, tab_size, addr); } int zclient_lookup_nexthop(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr, int max_lookup) { int lookup; uint32_t route_metric = 0xFFFFFFFF; uint8_t protocol_distance = 0xFF; for (lookup = 0; lookup < max_lookup; ++lookup) { int num_ifindex; int first_ifindex; struct in_addr nexthop_addr; num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr); if ((num_ifindex < 1) && PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, addr_str); return -1; } if (lookup < 1) { /* this is the non-recursive lookup - save original metric/distance */ route_metric = nexthop_tab[0].route_metric; protocol_distance = nexthop_tab[0].protocol_distance; } /* FIXME: Non-recursive nexthop ensured only for first ifindex. However, recursive route lookup should really be fixed in zebra daemon. See also TODO T24. */ first_ifindex = nexthop_tab[0].ifindex; nexthop_addr = nexthop_tab[0].nexthop_addr; if (first_ifindex > 0) { /* found: first ifindex is non-recursive nexthop */ if ((lookup > 0) && PIM_DEBUG_ZEBRA) { /* Report non-recursive success after first lookup */ char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, first_ifindex, addr_str, nexthop_tab[0].protocol_distance, nexthop_tab[0].route_metric); /* use last address as nexthop address */ nexthop_tab[0].nexthop_addr = addr; /* report original route metric/distance */ nexthop_tab[0].route_metric = route_metric; nexthop_tab[0].protocol_distance = protocol_distance; } return num_ifindex; } if (PIM_DEBUG_ZEBRA) { char addr_str[100]; char nexthop_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", nexthop_addr, nexthop_str, sizeof(nexthop_str)); zlog_debug("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, nexthop_str, addr_str, nexthop_tab[0].protocol_distance, nexthop_tab[0].route_metric); } addr = nexthop_addr; /* use nexthop addr for recursive lookup */ } /* for (max_lookup) */ if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, addr_str); } return -2; } quagga-1.2.4/pimd/pim_zlookup.h000066400000000000000000000025641325323223500164440ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_ZLOOKUP_H #define PIM_ZLOOKUP_H #include #include "zclient.h" #define PIM_NEXTHOP_LOOKUP_MAX (3) /* max. recursive route lookup */ struct pim_zlookup_nexthop { struct in_addr nexthop_addr; ifindex_t ifindex; uint32_t route_metric; uint8_t protocol_distance; }; struct zclient *zclient_lookup_new(void); int zclient_lookup_nexthop(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr, int max_lookup); #endif /* PIM_ZLOOKUP_H */ quagga-1.2.4/pimd/pimd.c000066400000000000000000000116401325323223500150130ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "memory.h" #include "vrf.h" #include "pimd.h" #include "pim_cmd.h" #include "pim_iface.h" #include "pim_zebra.h" #include "pim_str.h" #include "pim_oil.h" #include "pim_pim.h" #include "pim_upstream.h" #include "pim_rpf.h" #include "pim_ssmpingd.h" #include "pim_static.h" const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; const char *const PIM_ALL_PIM_ROUTERS = MCAST_ALL_PIM_ROUTERS; const char *const PIM_ALL_IGMP_ROUTERS = MCAST_ALL_IGMP_ROUTERS; struct thread_master *master = 0; uint32_t qpim_debugs = 0; int qpim_mroute_socket_fd = -1; int64_t qpim_mroute_socket_creation = 0; /* timestamp of creation */ struct thread *qpim_mroute_socket_reader = 0; int qpim_mroute_oif_highest_vif_index = -1; struct list *qpim_channel_oil_list = 0; int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */ struct list *qpim_upstream_list = 0; struct zclient *qpim_zclient_update = 0; struct zclient *qpim_zclient_lookup = 0; struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec = 10000; struct thread *qpim_rpf_cache_refresher = 0; int64_t qpim_rpf_cache_refresh_requests = 0; int64_t qpim_rpf_cache_refresh_events = 0; int64_t qpim_rpf_cache_refresh_last = 0; struct in_addr qpim_inaddr_any; struct list *qpim_ssmpingd_list = 0; struct in_addr qpim_ssmpingd_group_addr; int64_t qpim_scan_oil_events = 0; int64_t qpim_scan_oil_last = 0; int64_t qpim_mroute_add_events = 0; int64_t qpim_mroute_add_last = 0; int64_t qpim_mroute_del_events = 0; int64_t qpim_mroute_del_last = 0; struct list *qpim_static_route_list = 0; static void pim_free() { pim_ssmpingd_destroy(); if (qpim_channel_oil_list) list_free(qpim_channel_oil_list); if (qpim_upstream_list) list_free(qpim_upstream_list); if (qpim_static_route_list) list_free(qpim_static_route_list); } void pim_init() { srandom(time(NULL)); if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { zlog_err("%s %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, PIM_ALL_PIM_ROUTERS, errno, safe_strerror(errno)); zassert(0); return; } qpim_channel_oil_list = list_new(); if (!qpim_channel_oil_list) { zlog_err("%s %s: failure: channel_oil_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return; } qpim_channel_oil_list->del = (void (*)(void *)) pim_channel_oil_free; qpim_upstream_list = list_new(); if (!qpim_upstream_list) { zlog_err("%s %s: failure: upstream_list=list_new()", __FILE__, __PRETTY_FUNCTION__); pim_free(); return; } qpim_upstream_list->del = (void (*)(void *)) pim_upstream_free; qpim_static_route_list = list_new(); if (!qpim_static_route_list) { zlog_err("%s %s: failure: static_route_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return; } qpim_static_route_list->del = (void (*)(void *)) pim_static_route_free; qpim_mroute_socket_fd = -1; /* mark mroute as disabled */ qpim_mroute_oif_highest_vif_index = -1; zassert(!qpim_debugs); zassert(!PIM_MROUTE_IS_ENABLED); qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY; /* RFC 4601: 4.6.3. Assert Metrics assert_metric infinite_assert_metric() { return {1,infinity,infinity,0} } */ qpim_infinite_assert_metric.rpt_bit_flag = 1; qpim_infinite_assert_metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX; qpim_infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; qpim_infinite_assert_metric.ip_address = qpim_inaddr_any; pim_cmd_init(); pim_ssmpingd_init(); } void pim_terminate() { vrf_terminate(); pim_free(); } quagga-1.2.4/pimd/pimd.conf.sample000066400000000000000000000017201325323223500167740ustar00rootroot00000000000000! ! pimd sample configuration file ! $QuaggaId: $Format:%an, %ai, %h$ $ ! hostname quagga-pimd-router password zebra !enable password zebra ! !log file pimd.log log stdout ! line vty exec-timeout 60 ! !debug igmp !debug pim !debug pim zebra ! ip multicast-routing ! ! ! You may want to enable ssmpingd for troubleshooting ! ! See http://www.venaas.no/multicast/ssmping/ ! ! ! ip ssmpingd 1.1.1.1 ! ip ssmpingd 2.2.2.2 ! ! ! HINTS: ! ! - Enable "ip pim ssm" on the interface directly attached to the ! ! multicast source host (if this is the first-hop router) ! ! - Enable "ip pim ssm" on pim-routers-facing interfaces ! ! - Enable "ip igmp" on IGMPv3-hosts-facing interfaces ! ! - In order to inject IGMPv3 local membership information in the ! ! PIM protocol state, enable both "ip pim ssm" and "ip igmp" on ! ! the same interface; otherwise PIM won't advertise ! ! IGMPv3-learned membership to other PIM routers ! interface eth0 ip pim ssm ip igmp ! -x- quagga-1.2.4/pimd/pimd.h000066400000000000000000000177371325323223500150350ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIMD_H #define PIMD_H #include #include "pim_mroute.h" #include "pim_assert.h" #define PIMD_PROGNAME "pimd" #define PIMD_DEFAULT_CONFIG "pimd.conf" #define PIMD_VTY_PORT 2611 #define PIMD_BUG_ADDRESS "https://github.com/udhos/qpimd" #define PIM_IP_HEADER_MIN_LEN (20) #define PIM_IP_HEADER_MAX_LEN (60) #define PIM_IP_PROTO_IGMP (2) #define PIM_IP_PROTO_PIM (103) #define PIM_IGMP_MIN_LEN (8) #define PIM_MSG_HEADER_LEN (4) #define PIM_PIM_MIN_LEN PIM_MSG_HEADER_LEN #define PIM_PROTO_VERSION (2) #define MCAST_ALL_SYSTEMS "224.0.0.1" #define MCAST_ALL_ROUTERS "224.0.0.2" #define MCAST_ALL_PIM_ROUTERS "224.0.0.13" #define MCAST_ALL_IGMP_ROUTERS "224.0.0.22" #define PIM_FORCE_BOOLEAN(expr) ((expr) != 0) #define PIM_NET_INADDR_ANY (htonl(INADDR_ANY)) #define PIM_INADDR_IS_ANY(addr) ((addr).s_addr == PIM_NET_INADDR_ANY) /* struct in_addr addr */ #define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */ #define PIM_MASK_PIM_EVENTS (1 << 0) #define PIM_MASK_PIM_PACKETS (1 << 1) #define PIM_MASK_PIM_PACKETDUMP_SEND (1 << 2) #define PIM_MASK_PIM_PACKETDUMP_RECV (1 << 3) #define PIM_MASK_PIM_TRACE (1 << 4) #define PIM_MASK_IGMP_EVENTS (1 << 5) #define PIM_MASK_IGMP_PACKETS (1 << 6) #define PIM_MASK_IGMP_TRACE (1 << 7) #define PIM_MASK_ZEBRA (1 << 8) #define PIM_MASK_SSMPINGD (1 << 9) #define PIM_MASK_MROUTE (1 << 10) #define PIM_MASK_PIM_HELLO (1 << 11) #define PIM_MASK_PIM_J_P (1 << 12) #define PIM_MASK_STATIC (1 << 13) const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; const char *const PIM_ALL_PIM_ROUTERS; const char *const PIM_ALL_IGMP_ROUTERS; struct thread_master *master; uint32_t qpim_debugs; int qpim_mroute_socket_fd; int64_t qpim_mroute_socket_creation; /* timestamp of creation */ struct thread *qpim_mroute_socket_reader; int qpim_mroute_oif_highest_vif_index; struct list *qpim_channel_oil_list; /* list of struct channel_oil */ struct in_addr qpim_all_pim_routers_addr; int qpim_t_periodic; /* Period between Join/Prune Messages */ struct list *qpim_upstream_list; /* list of struct pim_upstream */ struct zclient *qpim_zclient_update; struct zclient *qpim_zclient_lookup; struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec; struct thread *qpim_rpf_cache_refresher; int64_t qpim_rpf_cache_refresh_requests; int64_t qpim_rpf_cache_refresh_events; int64_t qpim_rpf_cache_refresh_last; struct in_addr qpim_inaddr_any; struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ struct in_addr qpim_ssmpingd_group_addr; int64_t qpim_scan_oil_events; int64_t qpim_scan_oil_last; int64_t qpim_mroute_add_events; int64_t qpim_mroute_add_last; int64_t qpim_mroute_del_events; int64_t qpim_mroute_del_last; struct list *qpim_static_route_list; /* list of routes added statically */ #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) #define PIM_MROUTE_IS_ENABLED (qpim_mroute_socket_fd >= 0) #define PIM_MROUTE_IS_DISABLED (qpim_mroute_socket_fd < 0) #define PIM_DEBUG_PIM_EVENTS (qpim_debugs & PIM_MASK_PIM_EVENTS) #define PIM_DEBUG_PIM_PACKETS (qpim_debugs & PIM_MASK_PIM_PACKETS) #define PIM_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs & PIM_MASK_PIM_PACKETDUMP_SEND) #define PIM_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs & PIM_MASK_PIM_PACKETDUMP_RECV) #define PIM_DEBUG_PIM_TRACE (qpim_debugs & PIM_MASK_PIM_TRACE) #define PIM_DEBUG_IGMP_EVENTS (qpim_debugs & PIM_MASK_IGMP_EVENTS) #define PIM_DEBUG_IGMP_PACKETS (qpim_debugs & PIM_MASK_IGMP_PACKETS) #define PIM_DEBUG_IGMP_TRACE (qpim_debugs & PIM_MASK_IGMP_TRACE) #define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) #define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_MROUTE (qpim_debugs & PIM_MASK_MROUTE) #define PIM_DEBUG_PIM_HELLO (qpim_debugs & PIM_MASK_PIM_HELLO) #define PIM_DEBUG_PIM_J_P (qpim_debugs & PIM_MASK_PIM_J_P) #define PIM_DEBUG_STATIC (qpim_debugs & PIM_MASK_STATIC) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) #define PIM_DEBUG_TRACE (qpim_debugs & (PIM_MASK_PIM_TRACE | PIM_MASK_IGMP_TRACE)) #define PIM_DO_DEBUG_PIM_EVENTS (qpim_debugs |= PIM_MASK_PIM_EVENTS) #define PIM_DO_DEBUG_PIM_PACKETS (qpim_debugs |= PIM_MASK_PIM_PACKETS) #define PIM_DO_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_SEND) #define PIM_DO_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_RECV) #define PIM_DO_DEBUG_PIM_TRACE (qpim_debugs |= PIM_MASK_PIM_TRACE) #define PIM_DO_DEBUG_IGMP_EVENTS (qpim_debugs |= PIM_MASK_IGMP_EVENTS) #define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS) #define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) #define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) #define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) #define PIM_DO_DEBUG_MROUTE (qpim_debugs |= PIM_MASK_MROUTE) #define PIM_DO_DEBUG_PIM_HELLO (qpim_debugs |= PIM_MASK_PIM_HELLO) #define PIM_DO_DEBUG_PIM_J_P (qpim_debugs |= PIM_MASK_PIM_J_P) #define PIM_DO_DEBUG_STATIC (qpim_debugs |= PIM_MASK_STATIC) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) #define PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_SEND) #define PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_RECV) #define PIM_DONT_DEBUG_PIM_TRACE (qpim_debugs &= ~PIM_MASK_PIM_TRACE) #define PIM_DONT_DEBUG_IGMP_EVENTS (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS) #define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS) #define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) #define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) #define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) #define PIM_DONT_DEBUG_MROUTE (qpim_debugs &= ~PIM_MASK_MROUTE) #define PIM_DONT_DEBUG_PIM_HELLO (qpim_debugs &= ~PIM_MASK_PIM_HELLO) #define PIM_DONT_DEBUG_PIM_J_P (qpim_debugs &= ~PIM_MASK_PIM_J_P) #define PIM_DONT_DEBUG_STATIC (qpim_debugs &= ~PIM_MASK_STATIC) void pim_init(void); void pim_terminate(void); extern void pim_route_map_init (void); #endif /* PIMD_H */ quagga-1.2.4/pimd/test_igmpv3_join.c000066400000000000000000000067711325323223500173560ustar00rootroot00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques 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; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include #include #include #include #include #include #include "pim_igmp_join.h" const char *prog_name = 0; static int iface_solve_index(const char *ifname) { struct if_nameindex *ini; ifindex_t ifindex = -1; int i; if (!ifname) return -1; ini = if_nameindex(); if (!ini) { int err = errno; fprintf(stderr, "%s: interface=%s: failure solving index: errno=%d: %s\n", prog_name, ifname, err, strerror(err)); errno = err; return -1; } for (i = 0; ini[i].if_index; ++i) { #if 0 fprintf(stderr, "%s: interface=%s matching against local ifname=%s ifindex=%d\n", prog_name, ifname, ini[i].if_name, ini[i].if_index); #endif if (!strcmp(ini[i].if_name, ifname)) { ifindex = ini[i].if_index; break; } } if_freenameindex(ini); return ifindex; } int main(int argc, const char *argv[]) { struct in_addr group_addr; struct in_addr source_addr; const char *ifname; const char *group; const char *source; ifindex_t ifindex; int result; int fd; prog_name = argv[0]; fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { fprintf(stderr, "%s: could not create socket: socket(): errno=%d: %s\n", prog_name, errno, strerror(errno)); exit(1); } if (argc != 4) { fprintf(stderr, "usage: %s interface group source\n" "example: %s eth0 232.1.1.1 1.1.1.1\n", prog_name, prog_name); exit(1); } ifname = argv[1]; group = argv[2]; source = argv[3]; ifindex = iface_solve_index(ifname); if (ifindex < 0) { fprintf(stderr, "%s: could not find interface: %s\n", prog_name, ifname); exit(1); } result = inet_pton(AF_INET, group, &group_addr); if (result <= 0) { fprintf(stderr, "%s: bad group address: %s\n", prog_name, group); exit(1); } result = inet_pton(AF_INET, source, &source_addr); if (result <= 0) { fprintf(stderr, "%s: bad source address: %s\n", prog_name, source); exit(1); } result = pim_igmp_join_source(fd, ifindex, group_addr, source_addr); if (result) { fprintf(stderr, "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s\n", prog_name, fd, group, source, ifindex, ifname, errno, strerror(errno)); exit(1); } printf("%s: joined channel (S,G)=(%s,%s) on interface %s\n", prog_name, source, group, ifname); printf("%s: waiting...\n", prog_name); getchar(); close(fd); printf("%s: left channel (S,G)=(%s,%s) on interface %s\n", prog_name, source, group, ifname); exit(0); } quagga-1.2.4/pkgsrc/000077500000000000000000000000001325323223500142545ustar00rootroot00000000000000quagga-1.2.4/pkgsrc/Makefile.am000066400000000000000000000001301325323223500163020ustar00rootroot00000000000000rcdir=@pkgsrcrcdir@ rc_SCRIPTS = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh zebra.sh quagga-1.2.4/pkgsrc/Makefile.in000066400000000000000000000417331325323223500163310ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = pkgsrc ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh \ zebra.sh CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(rcdir)" SCRIPTS = $(rc_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/bgpd.sh.in \ $(srcdir)/ospf6d.sh.in $(srcdir)/ospfd.sh.in \ $(srcdir)/ripd.sh.in $(srcdir)/ripngd.sh.in \ $(srcdir)/zebra.sh.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ rcdir = @pkgsrcrcdir@ rc_SCRIPTS = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh zebra.sh all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu pkgsrc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu pkgsrc/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): bgpd.sh: $(top_builddir)/config.status $(srcdir)/bgpd.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ospf6d.sh: $(top_builddir)/config.status $(srcdir)/ospf6d.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ospfd.sh: $(top_builddir)/config.status $(srcdir)/ospfd.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ripd.sh: $(top_builddir)/config.status $(srcdir)/ripd.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ripngd.sh: $(top_builddir)/config.status $(srcdir)/ripngd.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ zebra.sh: $(top_builddir)/config.status $(srcdir)/zebra.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-rcSCRIPTS: $(rc_SCRIPTS) @$(NORMAL_INSTALL) @list='$(rc_SCRIPTS)'; test -n "$(rcdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(rcdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(rcdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(rcdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(rcdir)$$dir" || exit $$?; \ } \ ; done uninstall-rcSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(rc_SCRIPTS)'; test -n "$(rcdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(rcdir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 $(SCRIPTS) installdirs: for dir in "$(DESTDIR)$(rcdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-rcSCRIPTS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-rcSCRIPTS .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-rcSCRIPTS install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-rcSCRIPTS .PRECIOUS: Makefile # 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: quagga-1.2.4/pkgsrc/bgpd.sh.in000066400000000000000000000012531325323223500161320ustar00rootroot00000000000000#!/bin/sh # # bgpd is part of the quagga routing beast # # PROVIDE: bgpd # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="bgpd" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-1.2.4/pkgsrc/ospf6d.sh.in000066400000000000000000000012611325323223500164160ustar00rootroot00000000000000#!/bin/sh # # ospf6d is part of the quagga routing beast # # PROVIDE: ospf6d # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="ospf6d" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-1.2.4/pkgsrc/ospfd.sh.in000066400000000000000000000012561325323223500163340ustar00rootroot00000000000000#!/bin/sh # # ospfd is part of the quagga routing beast # # PROVIDE: ospfd # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="ospfd" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-1.2.4/pkgsrc/ripd.sh.in000066400000000000000000000012531325323223500161540ustar00rootroot00000000000000#!/bin/sh # # ripd is part of the quagga routing beast # # PROVIDE: ripd # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="ripd" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-1.2.4/pkgsrc/ripngd.sh.in000066400000000000000000000012611325323223500165000ustar00rootroot00000000000000#!/bin/sh # # ripngd is part of the quagga routing beast # # PROVIDE: ripngd # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="ripngd" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-1.2.4/pkgsrc/zebra.sh.in000066400000000000000000000016211325323223500163200ustar00rootroot00000000000000#!/bin/sh # # zebra is the head of the quagga routing beast # # PROVIDE: zebra # REQUIRE: NETWORKING ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="zebra" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" stop_postcmd="zebra_postcmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { mkdir -p "${socket_dir}" chown quagga.quagga "${socket_dir}" chmod 750 "${socket_dir}" rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } zebra_postcmd() { if [ -d "${socketdir}" ]; then rmdir ${socketdir} fi } load_rc_config $name run_rc_command "$1" quagga-1.2.4/qpb/000077500000000000000000000000001325323223500135455ustar00rootroot00000000000000quagga-1.2.4/qpb/Makefile.am000066400000000000000000000012011325323223500155730ustar00rootroot00000000000000include ../common.am AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES) PROTOBUF_INCLUDES=-I$(top_srcdir) PROTOBUF_PACKAGE = qpb lib_LTLIBRARIES = libquagga_pb.la libquagga_pb_la_LDFLAGS = -version-info 0:0:0 if HAVE_PROTOBUF protobuf_srcs = \ qpb_allocator.c protobuf_srcs_nodist = \ qpb.pb-c.c endif libquagga_pb_la_SOURCES = \ linear_allocator.h \ qpb.h \ qpb.c \ qpb_allocator.h \ $(protobuf_srcs) nodist_libquagga_pb_la_SOURCES = $(protobuf_srcs_nodist) CLEANFILES = $(Q_CLEANFILES) BUILT_SOURCES = $(Q_PROTOBUF_SRCS) EXTRA_DIST = qpb.proto quagga-1.2.4/qpb/Makefile.in000066400000000000000000000575001325323223500156210ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ # # Automake fragment intended to be shared by Makefile.am files in the # tree. # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = qpb ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libquagga_pb_la_LIBADD = am__libquagga_pb_la_SOURCES_DIST = linear_allocator.h qpb.h qpb.c \ qpb_allocator.h qpb_allocator.c @HAVE_PROTOBUF_TRUE@am__objects_1 = qpb_allocator.lo am_libquagga_pb_la_OBJECTS = qpb.lo $(am__objects_1) @HAVE_PROTOBUF_TRUE@am__objects_2 = qpb.pb-c.lo nodist_libquagga_pb_la_OBJECTS = $(am__objects_2) libquagga_pb_la_OBJECTS = $(am_libquagga_pb_la_OBJECTS) \ $(nodist_libquagga_pb_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libquagga_pb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libquagga_pb_la_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libquagga_pb_la_SOURCES) $(nodist_libquagga_pb_la_SOURCES) DIST_SOURCES = $(am__libquagga_pb_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/../common.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # Uncomment to use an non-system version of libprotobuf-c. # # Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src # Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_INCLUDES = @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_LDOPTS = -lprotobuf-c @HAVE_PROTOBUF_TRUE@Q_PROTOC = protoc @HAVE_PROTOBUF_TRUE@Q_PROTOC_C = protoc-c @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_CFILES = $(filter %.pb-c.c,$(SOURCES)) @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_SRCS = $(Q_PROTOBUF_CFILES) $(Q_PROTOBUF_HFILES) # # Information about how to link to various libraries. # @HAVE_PROTOBUF_TRUE@Q_QUAGGA_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libquagga_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS) @HAVE_PROTOBUF_TRUE@Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfpm_pb.la $(Q_QUAGGA_PB_CLIENT_LDOPTS) Q_CLEANFILES = $(Q_PROTOBUF_SRCS) Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS) AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES) PROTOBUF_INCLUDES = -I$(top_srcdir) PROTOBUF_PACKAGE = qpb lib_LTLIBRARIES = libquagga_pb.la libquagga_pb_la_LDFLAGS = -version-info 0:0:0 @HAVE_PROTOBUF_TRUE@protobuf_srcs = \ @HAVE_PROTOBUF_TRUE@ qpb_allocator.c @HAVE_PROTOBUF_TRUE@protobuf_srcs_nodist = \ @HAVE_PROTOBUF_TRUE@ qpb.pb-c.c libquagga_pb_la_SOURCES = \ linear_allocator.h \ qpb.h \ qpb.c \ qpb_allocator.h \ $(protobuf_srcs) nodist_libquagga_pb_la_SOURCES = $(protobuf_srcs_nodist) CLEANFILES = $(Q_CLEANFILES) BUILT_SOURCES = $(Q_PROTOBUF_SRCS) EXTRA_DIST = qpb.proto all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../common.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu qpb/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu qpb/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(srcdir)/../common.am $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libquagga_pb.la: $(libquagga_pb_la_OBJECTS) $(libquagga_pb_la_DEPENDENCIES) $(EXTRA_libquagga_pb_la_DEPENDENCIES) $(AM_V_CCLD)$(libquagga_pb_la_LINK) -rpath $(libdir) $(libquagga_pb_la_OBJECTS) $(libquagga_pb_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qpb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qpb.pb-c.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qpb_allocator.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES .PRECIOUS: Makefile # Rules @HAVE_PROTOBUF_TRUE@%.pb.h: %.proto @HAVE_PROTOBUF_TRUE@ $(Q_PROTOC) $(PROTOBUF_INCLUDES) --cpp_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ @HAVE_PROTOBUF_TRUE@%.pb-c.c %.pb-c.h: %.proto @HAVE_PROTOBUF_TRUE@ $(Q_PROTOC_C) $(PROTOBUF_INCLUDES) --c_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ # 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: quagga-1.2.4/qpb/linear_allocator.h000066400000000000000000000112521325323223500172310ustar00rootroot00000000000000/* * linear_allocator.h * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Header file for the linear allocator. * * An allocator that allocates memory by walking down towards the end * of a buffer. No attempt is made to reuse blocks that are freed * subsequently. The assumption is that the buffer is big enough to * cover allocations for a given purpose. */ #include #include #include #include /* * Alignment for block allocated by the allocator. Must be a power of 2. */ #define LINEAR_ALLOCATOR_ALIGNMENT 8 #define LINEAR_ALLOCATOR_ALIGN(value) \ (((value) + LINEAR_ALLOCATOR_ALIGNMENT - 1) & ~(LINEAR_ALLOCATOR_ALIGNMENT - 1)); /* * linear_allocator_align_ptr */ static inline char * linear_allocator_align_ptr (char *ptr) { return (char *) LINEAR_ALLOCATOR_ALIGN ((intptr_t) ptr); } typedef struct linear_allocator_t_ { char *buf; /* * Current location in the buffer. */ char *cur; /* * End of buffer. */ char *end; /* * Version number of the allocator, this is bumped up when the allocator * is reset and helps identifies bad frees. */ uint32_t version; /* * The number of blocks that are currently allocated. */ int num_allocated; } linear_allocator_t; /* * linear_allocator_block_t * * Header structure at the begining of each block. */ typedef struct linear_allocator_block_t_ { uint32_t flags; /* * The version of the allocator when this block was allocated. */ uint32_t version; char data[0]; } linear_allocator_block_t; #define LINEAR_ALLOCATOR_BLOCK_IN_USE 0x01 #define LINEAR_ALLOCATOR_HDR_SIZE (sizeof(linear_allocator_block_t)) /* * linear_allocator_block_size * * The total amount of space a block will take in the buffer, * including the size of the header. */ static inline size_t linear_allocator_block_size (size_t user_size) { return LINEAR_ALLOCATOR_ALIGN (LINEAR_ALLOCATOR_HDR_SIZE + user_size); } /* * linear_allocator_ptr_to_block */ static inline linear_allocator_block_t * linear_allocator_ptr_to_block (void *ptr) { void *block_ptr; block_ptr = ((char *) ptr) - offsetof (linear_allocator_block_t, data); return block_ptr; } /* * linear_allocator_init */ static inline void linear_allocator_init (linear_allocator_t * allocator, char *buf, size_t buf_len) { memset (allocator, 0, sizeof (*allocator)); assert (linear_allocator_align_ptr (buf) == buf); allocator->buf = buf; allocator->cur = buf; allocator->end = buf + buf_len; } /* * linear_allocator_reset * * Prepare an allocator for reuse. * * *** NOTE ** This implicitly frees all the blocks in the allocator. */ static inline void linear_allocator_reset (linear_allocator_t *allocator) { allocator->num_allocated = 0; allocator->version++; allocator->cur = allocator->buf; } /* * linear_allocator_alloc */ static inline void * linear_allocator_alloc (linear_allocator_t *allocator, size_t user_size) { size_t block_size; linear_allocator_block_t *block; block_size = linear_allocator_block_size (user_size); if (allocator->cur + block_size > allocator->end) { return NULL; } block = (linear_allocator_block_t *) allocator->cur; allocator->cur += block_size; block->flags = LINEAR_ALLOCATOR_BLOCK_IN_USE; block->version = allocator->version; allocator->num_allocated++; return block->data; } /* * linear_allocator_free */ static inline void linear_allocator_free (linear_allocator_t *allocator, void *ptr) { linear_allocator_block_t *block; if (((char *) ptr) < allocator->buf || ((char *) ptr) >= allocator->end) { assert (0); return; } block = linear_allocator_ptr_to_block (ptr); if (block->version != allocator->version) { assert (0); return; } block->flags = block->flags & ~LINEAR_ALLOCATOR_BLOCK_IN_USE; if (--allocator->num_allocated < 0) { assert (0); } } quagga-1.2.4/qpb/qpb.c000066400000000000000000000016231325323223500144750ustar00rootroot00000000000000/* * qpb.c * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Main file for the qpb library. */ quagga-1.2.4/qpb/qpb.h000066400000000000000000000166541325323223500145140ustar00rootroot00000000000000/* * qpb.h * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Main public header file for the quagga protobuf library. */ #ifndef _QPB_H #define _QPB_H #include "prefix.h" #include "qpb/qpb.pb-c.h" #include "qpb/qpb_allocator.h" /* * qpb__address_family__set */ #define qpb_address_family_set qpb__address_family__set static inline int qpb__address_family__set (Qpb__AddressFamily *pb_family, u_char family) { switch (family) { case AF_INET: *pb_family = QPB__ADDRESS_FAMILY__IPV4; return 1; case AF_INET6: *pb_family = QPB__ADDRESS_FAMILY__IPV6; return 1; default: *pb_family = QPB__ADDRESS_FAMILY__UNKNOWN_AF; } return 0; } /* * qpb__address_family__get */ #define qpb_address_family_get qpb__address_family__get static inline int qpb__address_family__get (Qpb__AddressFamily pb_family, u_char *family) { switch (pb_family) { case QPB__ADDRESS_FAMILY__IPV4: *family = AF_INET; return 1; case QPB__ADDRESS_FAMILY__IPV6: *family = AF_INET6; return 1; case QPB__ADDRESS_FAMILY__UNKNOWN_AF: return 0; } return 0; } /* * qpb__l3_prefix__create */ #define qpb_l3_prefix_create qpb__l3_prefix__create static inline Qpb__L3Prefix * qpb__l3_prefix__create (qpb_allocator_t *allocator, struct prefix *p) { Qpb__L3Prefix *prefix; prefix = QPB_ALLOC(allocator, typeof(*prefix)); if (!prefix) { return NULL; } qpb__l3_prefix__init(prefix); prefix->length = p->prefixlen; prefix->bytes.len = (p->prefixlen + 7)/8; prefix->bytes.data = qpb_alloc(allocator, prefix->bytes.len); if (!prefix->bytes.data) { return NULL; } memcpy(prefix->bytes.data, &p->u.prefix, prefix->bytes.len); return prefix; } /* * qpb__l3_prefix__get */ #define qpb_l3_prefix_get qpb__l3_prefix__get static inline int qpb__l3_prefix__get (const Qpb__L3Prefix *pb_prefix, u_char family, struct prefix *prefix) { switch (family) { case AF_INET: memset(prefix, 0, sizeof(struct prefix_ipv4)); break; case AF_INET6: memset(prefix, 0, sizeof(struct prefix_ipv6)); break; default: memset(prefix, 0, sizeof(*prefix)); } prefix->prefixlen = pb_prefix->length; prefix->family = family; memcpy(&prefix->u.prefix, pb_prefix->bytes.data, pb_prefix->bytes.len); return 1; } /* * qpb__protocol__set * * Translate a quagga route type to a protobuf protocol. */ #define qpb_protocol_set qpb__protocol__set static inline int qpb__protocol__set (Qpb__Protocol *pb_proto, int route_type) { switch (route_type) { case ZEBRA_ROUTE_KERNEL: *pb_proto = QPB__PROTOCOL__KERNEL; break; case ZEBRA_ROUTE_CONNECT: *pb_proto = QPB__PROTOCOL__CONNECTED; break; case ZEBRA_ROUTE_STATIC: *pb_proto = QPB__PROTOCOL__STATIC; break; case ZEBRA_ROUTE_RIP: *pb_proto = QPB__PROTOCOL__RIP; break; case ZEBRA_ROUTE_RIPNG: *pb_proto = QPB__PROTOCOL__RIPNG; break; case ZEBRA_ROUTE_OSPF: case ZEBRA_ROUTE_OSPF6: *pb_proto = QPB__PROTOCOL__OSPF; break; case ZEBRA_ROUTE_ISIS: *pb_proto = QPB__PROTOCOL__ISIS; break; case ZEBRA_ROUTE_BGP: *pb_proto = QPB__PROTOCOL__BGP; break; case ZEBRA_ROUTE_HSLS: case ZEBRA_ROUTE_OLSR: case ZEBRA_ROUTE_BABEL: case ZEBRA_ROUTE_MAX: case ZEBRA_ROUTE_SYSTEM: default: *pb_proto = QPB__PROTOCOL__OTHER; } return 1; } /* * qpb__ipv4_address__create */ static inline Qpb__Ipv4Address * qpb__ipv4_address__create (qpb_allocator_t *allocator, struct in_addr *addr) { Qpb__Ipv4Address *v4; v4 = QPB_ALLOC(allocator, typeof(*v4)); if (!v4) { return NULL; } qpb__ipv4_address__init(v4); v4->value = ntohl(addr->s_addr); return v4; } /* * qpb__ipv4_address__get */ static inline int qpb__ipv4_address__get (const Qpb__Ipv4Address *v4, struct in_addr *addr) { addr->s_addr = htonl(v4->value); return 1; } /* * qpb__ipv6_address__create */ static inline Qpb__Ipv6Address * qpb__ipv6_address__create (qpb_allocator_t *allocator, struct in6_addr *addr) { Qpb__Ipv6Address *v6; v6 = QPB_ALLOC(allocator, typeof(*v6)); if (!v6) return NULL; qpb__ipv6_address__init(v6); v6->bytes.len = 16; v6->bytes.data = qpb_alloc(allocator, 16); if (!v6->bytes.data) return NULL; memcpy(v6->bytes.data, addr->s6_addr, v6->bytes.len); return v6; } /* * qpb__ipv6_address__get * * Read out information from a protobuf ipv6 address structure. */ static inline int qpb__ipv6_address__get (const Qpb__Ipv6Address *v6, struct in6_addr *addr) { if (v6->bytes.len != 16) return 0; memcpy(addr->s6_addr, v6->bytes.data, v6->bytes.len); return 1; } /* * qpb__l3_address__create */ #define qpb_l3_address_create qpb__l3_address__create static inline Qpb__L3Address * qpb__l3_address__create (qpb_allocator_t *allocator, union g_addr *addr, u_char family) { Qpb__L3Address *l3_addr; l3_addr = QPB_ALLOC(allocator, typeof(*l3_addr)); if (!l3_addr) return NULL; qpb__l3_address__init(l3_addr); switch (family) { case AF_INET: l3_addr->v4 = qpb__ipv4_address__create (allocator, &addr->ipv4); if (!l3_addr->v4) return NULL; break; case AF_INET6: l3_addr->v6 = qpb__ipv6_address__create (allocator, &addr->ipv6); if (!l3_addr->v6) return NULL; break; } return l3_addr; } /* * qpb__l3_address__get * * Read out a gateway address from a protobuf l3 address. */ #define qpb_l3_address_get qpb__l3_address__get static inline int qpb__l3_address__get (const Qpb__L3Address *l3_addr, u_char *family, union g_addr *addr) { if (l3_addr->v4) { qpb__ipv4_address__get (l3_addr->v4, &addr->ipv4); *family = AF_INET; return 1; } if (l3_addr->v6) { qpb__ipv6_address__get(l3_addr->v6, &addr->ipv6); *family = AF_INET6; return 1; } return 0; } /* * qpb__if_identifier__create */ #define qpb_if_identifier_create qpb__if_identifier__create static inline Qpb__IfIdentifier * qpb__if_identifier__create (qpb_allocator_t *allocator, uint if_index) { Qpb__IfIdentifier *if_id; if_id = QPB_ALLOC(allocator, typeof(*if_id)); if (!if_id) { return NULL; } qpb__if_identifier__init(if_id); if_id->has_index = 1; if_id->index = if_index; return if_id; } /* * qpb__if_identifier__get * * Get interface name and/or if_index from an if identifier. */ #define qpb_if_identifier_get qpb__if_identifier__get static inline int qpb__if_identifier__get (Qpb__IfIdentifier *if_id, uint *if_index, char **name) { char *str; uint ix; if (!if_index) if_index = &ix; if (!name) name = &str; if (if_id->has_index) *if_index = if_id->index; else *if_index = 0; *name = if_id->name; return 1; } #endif quagga-1.2.4/qpb/qpb.proto000066400000000000000000000037571325323223500154300ustar00rootroot00000000000000/* * qpb.proto * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * Permission to use, copy, modify, and/or distribute this software * for any purpose with or without fee is hereby granted, provided * that the above copyright notice and this permission notice appear * in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Protobuf definitions pertaining to the Quagga Protobuf component. */ package qpb; enum AddressFamily { UNKNOWN_AF = 0; IPV4 = 1; // IP version 4 IPV6 = 2; // IP version 6 }; enum SubAddressFamily { UNKNOWN_SAF = 0; UNICAST = 1; MULTICAST = 2; }; // // An IP version 4 address, such as 10.1.1.1. // message Ipv4Address { required fixed32 value = 1 ; }; message Ipv6Address { // 16 bytes. required bytes bytes = 1; }; // // An IP version 4 or IP version 6 address. // message L3Address { optional Ipv4Address v4 = 1; optional Ipv6Address v6 = 2; }; // // An IP prefix, such as 10.1/16. // We use the message below to represent both IPv4 and IPv6 prefixes. message L3Prefix { required uint32 length = 1; required bytes bytes = 2; }; // // Something that identifies an interface on a machine. It can either // be a name (for instance, 'eth0') or a number currently. // message IfIdentifier { optional uint32 index = 1; optional string name = 2; }; enum Protocol { UNKNOWN_PROTO = 0; LOCAL = 1; CONNECTED = 2; KERNEL = 3; STATIC = 4; RIP = 5; RIPNG = 6; OSPF = 7; ISIS = 8; BGP = 9; OTHER = 10; }quagga-1.2.4/qpb/qpb_allocator.c000066400000000000000000000031111325323223500165270ustar00rootroot00000000000000/* * qpb_allocator.c * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include "linear_allocator.h" #include "qpb_allocator.h" /* * _qpb_alloc */ static void * _qpb_alloc (void *allocator_data, size_t size) { return linear_allocator_alloc (allocator_data, size); } /* * _qpb_free */ static void _qpb_free (void *allocator_data, void *ptr) { linear_allocator_free (allocator_data, ptr); } static ProtobufCAllocator allocator_template = { _qpb_alloc, _qpb_free, NULL, 8192, NULL }; /* * qpb_allocator_init_linear * * Initialize qpb_allocator_t with the given linear allocator. */ void qpb_allocator_init_linear (qpb_allocator_t *allocator, linear_allocator_t *linear_allocator) { *allocator = allocator_template; allocator->allocator_data = linear_allocator; } quagga-1.2.4/qpb/qpb_allocator.h000066400000000000000000000056451325323223500165520ustar00rootroot00000000000000/* * qpb_allocator.h * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Header file for quagga protobuf memory management code. */ #ifndef _QPB_ALLOCATOR_H_ #define _QPB_ALLOCATOR_H_ #include struct linear_allocator_t_; /* * Alias for ProtobufCAllocator that is easier on the fingers. */ typedef ProtobufCAllocator qpb_allocator_t; /* * qpb_alloc */ static inline void * qpb_alloc (qpb_allocator_t *allocator, size_t size) { return allocator->alloc (allocator->allocator_data, size); } /* * qpb_alloc_ptr_array * * Allocate space for the specified number of pointers. */ static inline void * qpb_alloc_ptr_array (qpb_allocator_t *allocator, size_t num_ptrs) { return qpb_alloc (allocator, num_ptrs * sizeof (void *)); } /* * qpb_free */ static inline void qpb_free (qpb_allocator_t *allocator, void *ptr) { allocator->free (allocator->allocator_data, ptr); } /* * QPB_ALLOC * * Convenience macro to reduce the probability of allocating memory of * incorrect size. It returns enough memory to store the given type, * and evaluates to an appropriately typed pointer. */ #define QPB_ALLOC(allocator, type) \ (type *) qpb_alloc(allocator, sizeof(type)) /* * Externs. */ extern void qpb_allocator_init_linear (qpb_allocator_t *, struct linear_allocator_t_ *); /* * The following macros are for the common case where a qpb allocator * is being used alongside a linear allocator that allocates memory * off of the stack. */ #define QPB_DECLARE_STACK_ALLOCATOR(allocator, size) \ qpb_allocator_t allocator; \ linear_allocator_t lin_ ## allocator; \ char lin_ ## allocator ## _buf[size] #define QPB_INIT_STACK_ALLOCATOR(allocator) \ do \ { \ linear_allocator_init(&(lin_ ## allocator), \ lin_ ## allocator ## _buf, \ sizeof(lin_ ## allocator ## _buf)); \ qpb_allocator_init_linear(&allocator, &(lin_ ## allocator)); \ } while (0) #define QPB_RESET_STACK_ALLOCATOR(allocator) \ do \ { \ linear_allocator_reset (&(lin_ ## allocator)); \ } while (0) #endif /* _QPB_ALLOCATOR_H_ */ quagga-1.2.4/redhat/000077500000000000000000000000001325323223500142325ustar00rootroot00000000000000quagga-1.2.4/redhat/Makefile.am000066400000000000000000000006061325323223500162700ustar00rootroot00000000000000 EXTRA_DIST = bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init pimd.init pimd.service zebra.init zebra.service \ nhrpd.service \ quagga-filter-perl-requires.sh quagga-tmpfs.conf \ README.rpm_build.md quagga-1.2.4/redhat/Makefile.in000066400000000000000000000336401325323223500163050ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = redhat ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = quagga.spec quagga.sysconfig CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/quagga.spec.in \ $(srcdir)/quagga.sysconfig.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init pimd.init pimd.service zebra.init zebra.service \ nhrpd.service \ quagga-filter-perl-requires.sh quagga-tmpfs.conf \ README.rpm_build.md all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu redhat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu redhat/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): quagga.spec: $(top_builddir)/config.status $(srcdir)/quagga.spec.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ quagga.sysconfig: $(top_builddir)/config.status $(srcdir)/quagga.sysconfig.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # 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: quagga-1.2.4/redhat/README.rpm_build.md000066400000000000000000000076371325323223500175020ustar00rootroot00000000000000Building your own Quagga RPM ============================ (Tested on CentOS 6, CentOS 7 and Fedora 22.) 1. Install the following packages to build the RPMs: yum install git autoconf automake libtool make gawk readline-devel \ texinfo dejagnu net-snmp-devel groff rpm-build net-snmp-devel \ libcap-devel texi2html (use `dnf install` on new Fedora instead of `yum install `) 2. Checkout Quagga under a **unpriviledged** user account git clone git://git.savannah.nongnu.org/quagga.git quagga 3. Run Bootstrap and make distribution tar.gz cd quagga ./bootstrap.sh ./configure --with-pkg-extra-version=-MyRPMVersion make dist Note: configure parameters are not important for the RPM building - except the `with-pkg-extra-version` if you want to give the RPM a specific name to mark your own unoffical build 4. Create RPM directory structure and populate with sources mkdir rpmbuild mkdir rpmbuild/SOURCES mkdir rpmbuild/SPECS cp redhat/*.spec rpmbuild/SPECS/ cp quagga*.tar.gz rpmbuild/SOURCES/ 5. Edit rpm/SPECS/quagga.spec with configuration as needed Look at the beginning of the file and adjust the following parameters to enable or disable features as required: ################# Quagga configure options #################### # with-feature options %{!?with_snmp: %global with_snmp 1 } %{!?with_vtysh: %global with_vtysh 1 } %{!?with_ospf_te: %global with_ospf_te 1 } %{!?with_opaque_lsa: %global with_opaque_lsa 1 } %{!?with_tcp_zebra: %global with_tcp_zebra 0 } %{!?with_vtysh: %global with_vtysh 1 } %{!?with_pam: %global with_pam 1 } %{!?with_ospfclient: %global with_ospfclient 1 } %{!?with_ospfapi: %global with_ospfapi 1 } %{!?with_irdp: %global with_irdp 1 } %{!?with_rtadv: %global with_rtadv 1 } %{!?with_isisd: %global with_isisd 1 } %{!?with_pimd: %global with_pimd 1 } %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 64 } %{!?quagga_user: %global quagga_user quagga } %{!?vty_group: %global vty_group quaggavt } %{!?with_fpm: %global with_fpm 0 } %{!?with_watchquagga: %global with_watchquagga 1 } 6. Build the RPM rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/quagga.spec DONE. If all works correctly, then you should end up with the RPMs under `rpmbuild/RPMS` and the Source RPM under `rpmbuild/SRPMS` Enabling daemons after installation of the package: --------------------------------------------------- ### init.d based systems (ie CentOS 6): 1. Enable the daemons as needed to run after boot (Zebra is mandatory) chkconfig zebra on chkconfig ospfd on chkconfig ospf6d on chkconfig bgpd on ... etc 2. If you want to run `watchquagga`, then configure `/etc/sysconfig/quagga` and uncomment the line with the daemons for `watchquagga` to monitor, then enable watchquagga chkconfig watchquagga on 3. Check your firewall / IPtables to make sure the routing protocols are allowed. 4. Start the daemons (or reboot) service zebra start service bgpd start service ospfd start ... etc Configuration is stored in `/etc/quagga/*.conf` files. ### systemd based systems (ie CentOS 7, Fedora 22) 1. Enable the daemons as needed to run after boot (Zebra is mandatory) systemctl enable zebra systemctl enable ospfd systemctl enable ospf6d systemctl enable bgpd ... etc Note: There is no watchquagga on systemd based systems. Systemd contains the functionality of monitoring and restarting daemons. 2. Check your firewall / IPtables to make sure the routing protocols are allowed. 3. Start the daemons (or reboot) systemctl start zebra systemctl start bgpd systemctl start ospfd ... etc Configuration is stored in `/etc/quagga/*.conf` files. quagga-1.2.4/redhat/bgpd.init000066400000000000000000000023771325323223500160440ustar00rootroot00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/bgpd.conf ### BEGIN INIT INFO # Provides: bgpd # Short-Description: BGP routing engine # Description: BGP routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="bgpd" cmd=bgpd LOCK_FILE=/var/lock/subsys/bgpd CONF_FILE=/etc/quagga/bgpd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $BGPD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/bgpd.service000066400000000000000000000010071325323223500165260ustar00rootroot00000000000000[Unit] Description=BGP routing daemon BindsTo=zebra.service Wants=network.target After=zebra.service network-pre.target Before=network.target ConditionPathExists=/etc/quagga/bgpd.conf Documentation=man:bgpd [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStartPre=-/bin/chmod -f 640 /etc/quagga/bgpd.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /etc/quagga/bgpd.conf ExecStart=/usr/sbin/bgpd -d $BGPD_OPTS -f /etc/quagga/bgpd.conf Restart=on-abort [Install] WantedBy=multi-user.target quagga-1.2.4/redhat/isisd.init000066400000000000000000000024121325323223500162310ustar00rootroot00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/isisd.conf ### BEGIN INIT INFO # Provides: isisd # Short-Description: IS-IS routing engine # Description: IS-IS routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="isisd" cmd=isisd LOCK_FILE=/var/lock/subsys/isisd CONF_FILE=/etc/quagga/isisd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $ISISD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/isisd.service000066400000000000000000000010201325323223500167200ustar00rootroot00000000000000[Unit] Description=IS-IS routing daemon BindsTo=zebra.service Wants=network.target After=zebra.service network-pre.target Before=network.target ConditionPathExists=/etc/quagga/isisd.conf Documentation=man:isisd [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStartPre=-/bin/chmod -f 640 /etc/quagga/isisd.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /etc/quagga/isisd.conf ExecStart=/usr/sbin/isisd -d $ISISD_OPTS -f /etc/quagga/isisd.conf Restart=on-abort [Install] WantedBy=multi-user.target quagga-1.2.4/redhat/nhrpd.service000066400000000000000000000010171325323223500167260ustar00rootroot00000000000000[Unit] Description=Quagga NHRP daemon BindsTo=zebra.service Wants=network.target After=zebra.service network-pre.target Before=network.target ConditionPathExists=/etc/quagga/nhrpd.conf Documentation=man:nhrpd [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStartPre=-/bin/chmod -f 640 /etc/quagga/nhrpd.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /etc/quagga/nhrpd.conf ExecStart=/usr/sbin/nhrpd -d $NHRPD_OPTS -f /etc/quagga/nhrpdd.conf Restart=on-abort [Install] WantedBy=multi-user.target quagga-1.2.4/redhat/ospf6d.init000066400000000000000000000024411325323223500163210ustar00rootroot00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/ospf6d.conf ### BEGIN INIT INFO # Provides: ospf6d # Short-Description: OSPF routing engine for IPv6 # Description: OSPF routing engine for use with Zebra and IPv6 ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="ospf6d" cmd=ospf6d LOCK_FILE=/var/lock/subsys/ospf6d CONF_FILE=/etc/quagga/ospf6d.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $OSPF6D_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/ospf6d.service000066400000000000000000000010371325323223500170160ustar00rootroot00000000000000[Unit] Description=OSPF routing daemon for IPv6 BindsTo=zebra.service Wants=network.target After=zebra.service network-pre.target Before=network.target ConditionPathExists=/etc/quagga/ospf6d.conf Documentation=man:ospf6d [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStartPre=-/bin/chmod -f 640 /etc/quagga/ospf6d.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /etc/quagga/ospf6d.conf ExecStart=/usr/sbin/ospf6d -d $OSPF6D_OPTS -f /etc/quagga/ospf6d.conf Restart=on-abort [Install] WantedBy=multi-user.target quagga-1.2.4/redhat/ospfd.init000066400000000000000000000024101325323223500162270ustar00rootroot00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/ospfd.conf ### BEGIN INIT INFO # Provides: ospfd # Short-Description: OSPF routing engine # Description: OSPF routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="ospfd" cmd=ospfd LOCK_FILE=/var/lock/subsys/ospfd CONF_FILE=/etc/quagga/ospfd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $OSPFD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/ospfd.service000066400000000000000000000010171325323223500167260ustar00rootroot00000000000000[Unit] Description=OSPF routing daemon BindsTo=zebra.service Wants=network.target After=zebra.service network-pre.target Before=network.target ConditionPathExists=/etc/quagga/ospfd.conf Documentation=man:ospfd [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStartPre=-/bin/chmod -f 640 /etc/quagga/ospfd.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /etc/quagga/ospfd.conf ExecStart=/usr/sbin/ospfd -d $OSPFD_OPTS -f /etc/quagga/ospfd.conf Restart=on-abort [Install] WantedBy=multi-user.target quagga-1.2.4/redhat/pimd.init000066400000000000000000000024111325323223500160460ustar00rootroot00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/pimd.conf ### BEGIN INIT INFO # Provides: pimd # Short-Description: PIM multicast routing engine # Description: PIM routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="pimd" cmd=pimd LOCK_FILE=/var/lock/subsys/pimd CONF_FILE=/etc/quagga/pimd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $PIMD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/pimd.service000066400000000000000000000007541325323223500165530ustar00rootroot00000000000000[Unit] Description=PIM multicast routing engine BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/pimd.conf Documentation=man:pimd [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStartPre=-/bin/chmod -f 640 /etc/quagga/pimd.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /etc/quagga/pimd.conf ExecStart=/usr/sbin/pimd -d $PIMD_OPTS -f /etc/quagga/pimd.conf Restart=on-abort [Install] WantedBy=network.target quagga-1.2.4/redhat/quagga-filter-perl-requires.sh000077500000000000000000000000741325323223500221170ustar00rootroot00000000000000#!/bin/sh /usr/lib/rpm/perl.req $* | grep -v "Net::Telnet" quagga-1.2.4/redhat/quagga-tmpfs.conf000066400000000000000000000000451325323223500174740ustar00rootroot00000000000000d /var/run/quagga 0755 quagga quagga quagga-1.2.4/redhat/quagga.logrotate000066400000000000000000000022631325323223500174240ustar00rootroot00000000000000/var/log/quagga/zebra.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/zebra.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/bgpd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/bgpd.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/isisd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/isisd.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/ospfd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/ospfd.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/ospf6d.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/ospf6d.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/ripd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/ripd.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/ripngd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/ripngd.pid 2> /dev/null` 2> /dev/null || true endscript } quagga-1.2.4/redhat/quagga.pam000066400000000000000000000017171325323223500162040ustar00rootroot00000000000000#%PAM-1.0 # ##### if running quagga as root: # Only allow root (and possibly wheel) to use this because enable access # is unrestricted. auth sufficient pam_rootok.so # Uncomment the following line to implicitly trust users in the "wheel" group. #auth sufficient pam_wheel.so trust use_uid # Uncomment the following line to require a user to be in the "wheel" group. #auth required pam_wheel.so use_uid ########################################################### # If using quagga privileges and with a seperate group for vty access, then # access can be controlled via the vty access group, and pam can simply # check for valid user/password, eg: # # only allow local users. #auth required pam_securetty.so #auth include system-auth #auth required pam_nologin.so #account include system-auth #password include system-auth #session include system-auth #session optional pam_console.so quagga-1.2.4/redhat/quagga.spec000066400000000000000000000542031325323223500163570ustar00rootroot00000000000000# configure options # # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' # (use any value, ie 1 for flag "with_XXXX" definitions) # # E.g. rpmbuild --define 'release_rev 02' may be useful if building # rpms again and again on the same day, so the newer rpms can be installed. # bumping the number each time. ####################### Quagga configure options ######################### # with-feature options %{!?with_snmp: %global with_snmp 1 } %{!?with_vtysh: %global with_vtysh 1 } %{!?with_tcp_zebra: %global with_tcp_zebra 0 } %{!?with_vtysh: %global with_vtysh 1 } %{!?with_pam: %global with_pam 1 } %{!?with_ospfclient: %global with_ospfclient 1 } %{!?with_ospfapi: %global with_ospfapi 1 } %{!?with_irdp: %global with_irdp 1 } %{!?with_rtadv: %global with_rtadv 1 } %{!?with_isisd: %global with_isisd 1 } %{!?with_pimd: %global with_pimd 1 } %{!?with_nhrpd: %global with_nhrpd 1 } %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 64 } %{!?quagga_user: %global quagga_user quagga } %{!?vty_group: %global vty_group quaggavt } %{!?with_fpm: %global with_fpm 0 } %{!?with_watchquagga: %global with_watchquagga 1 } # whether to build doc/quagga.html - requires a lot of TeX packages %{!?with_texi2html: %global with_texi2html 0 } # path defines %define _sysconfdir /etc/quagga %define zeb_src %{_builddir}/%{name}-%{quaggaversion} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc # defines for configure %define _localstatedir /var/run/quagga ############################################################################ #### Version String tweak # Remove invalid characters form version string and replace with _ %{expand: %%global rpmversion %(echo '1.2.4' | tr [:blank:]- _ )} %define quaggaversion 1.2.4 #### Check version of texi2html # Old versions don't support "--number-footnotes" option. %if %{with_texi2html} %{expand: %%global texi2htmlversion %(type texi2html >/dev/null 2>&1 && (rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1) || echo 0 )} %endif #### Check for systemd or init.d (upstart) # Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7) %{expand: %%global initsystem %(if [[ `/sbin/init --version 2> /dev/null` =~ upstart ]]; then echo upstart; elif [[ `systemctl` =~ -\.mount ]]; then echo systemd; fi)} # # If init system is systemd, then always disable watchquagga # %if "%{initsystem}" == "systemd" # Note: For systems with systemd, watchquagga will NOT be built. Systemd # takes over the role of restarting crashed processes. Value will # be overwritten with 0 below for systemd independent on the setting here %global with_watchquagga 0 %endif # if FPM is enabled, then enable tcp_zebra as well # %if %{with_fpm} %global with_tcp_zebra 1 %endif # misc internal defines %{!?quagga_uid: %global quagga_uid 92 } %{!?quagga_gid: %global quagga_gid 92 } %{!?vty_gid: %global vty_gid 85 } %define daemon_list zebra ripd ospfd bgpd %define daemonv6_list ripngd ospf6d %if %{with_isisd} %define daemon_isisd isisd %else %define daemon_isisd "" %endif %if %{with_pimd} %define daemon_pimd pimd %else %define daemon_pimd "" %endif %if %{with_nhrpd} %define daemon_nhrpd nhrpd %else %define daemon_nhrpd "" %endif %if %{with_watchquagga} %define daemon_watchquagga watchquagga %else %define daemon_watchquagga "" %endif %define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_isisd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_watchquagga} # allow build dir to be kept %{!?keep_build: %global keep_build 0 } #release sub-revision (the two digits after the CONFDATE) %{!?release_rev: %global release_rev 01 } Summary: Routing daemon Name: quagga Version: %{rpmversion} Release: 20180219%{release_rev}%{?dist} License: GPLv2+ Group: System Environment/Daemons Source0: https://download.savannah.gnu.org/releases/quagga/%{name}-%{quaggaversion}.tar.gz URL: https://www.quagga.net Requires: ncurses Requires(pre): /sbin/install-info Requires(preun): /sbin/install-info Requires(post): /sbin/install-info BuildRequires: autoconf patch libcap-devel groff BuildRequires: perl-generators pkgconfig %if %{with_texi2html} BuildRequires: texi2html %endif %if %{with_snmp} BuildRequires: net-snmp-devel Requires: net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel Requires: ncurses %endif %if %{with_pam} BuildRequires: pam-devel Requires: pam %endif %if %{with_nhrpd} BuildRequires: c-ares-devel Requires: c-ares %endif %if "%{initsystem}" == "systemd" BuildRequires: systemd Requires(post): systemd Requires(preun): systemd Requires(postun): systemd %else # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 %endif Provides: routingdaemon = %{version}-%{release} BuildRoot: %{_tmppath}/%{name}-%{version}-root #Obsoletes: mrt zebra quagga-sysvinit %define __perl_requires %{zeb_rh_src}/quagga-filter-perl-requires.sh %description Quagga is a free software routing protocol suite. Quagga supports BGP, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM-SSM and NHRP. %package contrib Summary: contrib tools for quagga Group: System Environment/Daemons %description contrib Contributed/3rd party tools which may be of use with quagga. %package devel Summary: Header and object files for quagga development Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} %description devel The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep %setup -q -n quagga-%{quaggaversion} %build %configure \ --sysconfdir=%{_sysconfdir} \ --libdir=%{_libdir}/quagga \ --libexecdir=%{_libexecdir} \ --localstatedir=%{_localstatedir} \ --disable-werror \ %if !%{with_shared} --disable-shared \ %endif %if %{with_snmp} --enable-snmp \ %endif %if %{with_multipath} --enable-multipath=%{with_multipath} \ %endif %if %{with_tcp_zebra} --enable-tcp-zebra \ %endif %if %{with_vtysh} --enable-vtysh \ %endif %if %{with_ospfclient} --enable-ospfclient=yes \ %else --enable-ospfclient=no\ %endif %if %{with_ospfapi} --enable-ospfapi=yes \ %else --enable-ospfapi=no \ %endif %if %{with_irdp} --enable-irdp=yes \ %else --enable-irdp=no \ %endif %if %{with_rtadv} --enable-rtadv=yes \ %else --enable-rtadv=no \ %endif %if %{with_isisd} --enable-isisd \ %else --disable-isisd \ %endif %if %{with_nhrpd} --enable-nhrpd \ %else --disable-nhrpd \ %endif %if %{with_pam} --with-libpam \ %endif %if 0%{?quagga_user:1} --enable-user=%quagga_user \ --enable-group=%quagga_user \ %endif %if 0%{?vty_group:1} --enable-vty-group=%vty_group \ %endif %if %{with_fpm} --enable-fpm \ %else --disable-fpm \ %endif %if %{with_watchquagga} --enable-watchquagga \ %else --disable-watchquagga \ %endif --enable-gcc-rdynamic make %{?_smp_mflags} %if %{with_texi2html} pushd doc %if %{texi2htmlversion} < 5 texi2html --number-sections quagga.texi %else texi2html --number-footnotes --number-sections quagga.texi %endif popd %endif %install mkdir -p %{buildroot}/etc/{quagga,sysconfig,logrotate.d,pam.d} \ %{buildroot}/var/log/quagga %{buildroot}%{_infodir} make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install # Remove this file, as it is uninstalled and causes errors when building on RH9 rm -rf %{buildroot}/usr/share/info/dir # install /etc sources %if "%{initsystem}" == "systemd" mkdir -p %{buildroot}%{_unitdir} for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.service \ %{buildroot}%{_unitdir}/${daemon}.service fi done %else mkdir -p %{buildroot}/etc/rc.d/init.d for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.init \ %{buildroot}/etc/rc.d/init.d/${daemon} fi done %endif install -m644 %{zeb_rh_src}/quagga.pam \ %{buildroot}/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ %{buildroot}/etc/logrotate.d/quagga install -m644 %{zeb_rh_src}/quagga.sysconfig \ %{buildroot}/etc/sysconfig/quagga install -d -m750 %{buildroot}/var/run/quagga %if 0%{?_tmpfilesdir:1} install -d -m 755 %{buildroot}/%{_tmpfilesdir} install -p -m 644 %{zeb_rh_src}/quagga-tmpfs.conf \ %{buildroot}/%{_tmpfilesdir}/quagga.conf %endif %pre # add vty_group %if 0%{?vty_group:1} if getent group %vty_group > /dev/null ; then : ; else \ /usr/sbin/groupadd -r -g %vty_gid %vty_group > /dev/null || : ; fi %endif # add quagga user and group %if 0%{?quagga_user:1} # Ensure that quagga_gid gets correctly allocated if getent group %quagga_user >/dev/null; then : ; else \ /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ fi if getent passwd %quagga_user >/dev/null ; then : ; else \ /usr/sbin/useradd -u %quagga_uid -g %quagga_gid -G %vty_group \ -M -r -s /sbin/nologin -c "Quagga routing suite" \ -d %_localstatedir %quagga_user 2> /dev/null || : ; \ fi %endif %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 ] && \ ! %__sed -e 's/#.*$//' /etc/services | %__grep -wq $1 ; 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" %if %{with_ospfapi} zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %endif %if %{with_isisd} zebra_spec_add_service isisd 2608/tcp "ISISd vty" %endif %if %{with_pimd} zebra_spec_add_service pimd 2611/tcp "PIMd vty" %endif %if %{with_nhrpd} zebra_spec_add_service nhrpd 2612/tcp "NHRPd vty" %endif %if "%{initsystem}" == "systemd" for daemon in %all_daemons ; do %systemd_post ${daemon}.service done %else for daemon in %all_daemons ; do /sbin/chkconfig --add ${daemon} done %endif if [ -f %{_infodir}/%{name}.inf* ]; then /sbin/install-info %{_infodir}/quagga.info %{_infodir}/dir fi # Create dummy files if they don't exist so basic functions can be used. if [ ! -e %{_sysconfdir}/zebra.conf ]; then echo "hostname `hostname`" > %{_sysconfdir}/zebra.conf %if 0%{?quagga_user:1} chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf* %endif chmod 640 %{_sysconfdir}/zebra.conf fi for daemon in %{all_daemons} ; do if [ ! -e %{_sysconfdir}/${daemon}.conf ]; then touch %{_sysconfdir}/${daemon}.conf %if 0%{?quagga_user:1} chown %quagga_user:%quagga_user %{_sysconfdir}/${daemon}.conf* %endif fi done %if %{with_watchquagga} # No config for watchquagga - this is part of /etc/sysconfig/quagga rm -f %{_sysconfdir}/watchquagga.* %endif if [ ! -e %{_sysconfdir}/vtysh.conf ]; then touch %{_sysconfdir}/vtysh.conf chmod 640 %{_sysconfdir}/vtysh.conf %if 0%{?vty_group:1} chown quagga:%{vty_group} %{_sysconfdir}/vtysh.conf* %endif fi %postun if [ "$1" -ge 1 ]; then # Find out which daemons need to be restarted. for daemon in %all_daemons ; do if [ -f /var/lock/subsys/${daemon} ]; then eval restart_${daemon}=yes else eval restart_${daemon}=no fi done # Rename restart flags for daemons handled specially. running_zebra="$restart_zebra" restart_zebra=no %if %{with_watchquagga} running_watchquagga="$restart_watchquagga" restart_watchquagga=no %endif %if "%{initsystem}" == "systemd" ## ## Systemd Version ## # No watchquagga for systemd version # # Stop all daemons other than zebra. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ %systemd_postun_with_restart ${daemon}.service done # Restart zebra. [ "$running_zebra" = yes ] && \ %systemd_postun_with_restart $daemon.service # Start all daemons other than zebra. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ %systemd_post ${daemon}.service done %else ## ## init.d Version ## %if %{with_watchquagga} # Stop watchquagga first. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 %endif # Stop all daemons other than zebra and watchquagga. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 done # Restart zebra. [ "$running_zebra" = yes ] && \ /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 # Start all daemons other than zebra and watchquagga. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/${daemon} start >/dev/null 2>&1 done %if %{with_watchquagga} # Start watchquagga last. # Avoid postun scriptlet error if watchquagga is not running. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : %endif %endif fi if [ -f %{_infodir}/%{name}.inf* ]; then /sbin/install-info --delete %{_infodir}/quagga.info %{_infodir}/dir fi %preun %if "%{initsystem}" == "systemd" ## ## Systemd Version ## if [ "$1" = "0" ]; then for daemon in %all_daemons ; do %systemd_preun ${daemon}.service done fi %else ## ## init.d Version ## if [ "$1" = "0" ]; then for daemon in %all_daemons ; do /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 /sbin/chkconfig --del ${daemon} done fi %endif %clean %if !0%{?keep_build:1} rm -rf %{buildroot} %endif %files %defattr(-,root,root) %doc */*.sample* AUTHORS COPYING %if %{with_texi2html} %doc doc/quagga.html %endif %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO %if 0%{?quagga_user:1} %dir %attr(751,%quagga_user,%quagga_user) %{_sysconfdir} %dir %attr(750,%quagga_user,%quagga_user) /var/log/quagga %dir %attr(751,%quagga_user,%quagga_user) /var/run/quagga %else %dir %attr(750,root,root) %{_sysconfdir} %dir %attr(750,root,root) /var/log/quagga %dir %attr(750,root,root) /var/run/quagga %endif %if 0%{?vty_group:1} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif %{_infodir}/quagga.info*.gz %{_mandir}/man*/* %if %{with_watchquagga} %{_mandir}/man*/watchquagga.* %endif %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd %if %{with_watchquagga} %{_sbindir}/watchquagga %endif %{_sbindir}/ripngd %{_sbindir}/ospf6d %if %{with_pimd} %{_sbindir}/pimd %endif %if %{with_isisd} %{_sbindir}/isisd %endif %if %{with_nhrpd} %{_sbindir}/nhrpd %endif %if %{with_shared} %{_libdir}/quagga/lib*.so %{_libdir}/quagga/lib*.so.? %attr(755,root,root) %{_libdir}/quagga/lib*.so.?.?.? %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* %if "%{initsystem}" == "systemd" %{_unitdir}/*.service %else %config /etc/rc.d/init.d/zebra %if %{with_watchquagga} %config /etc/rc.d/init.d/watchquagga %endif %config /etc/rc.d/init.d/ripd %config /etc/rc.d/init.d/ospfd %config /etc/rc.d/init.d/bgpd %config /etc/rc.d/init.d/ripngd %config /etc/rc.d/init.d/ospf6d %if %{with_isisd} %config /etc/rc.d/init.d/isisd %endif %if %{with_pimd} %config /etc/rc.d/init.d/pimd %endif %if %{with_nhrpd} %config /etc/rc.d/init.d/nhrpd %endif %endif %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* %{_tmpfilesdir}/quagga.conf %files contrib %defattr(-,root,root) %doc AUTHORS COPYING %attr(0644,root,root) tools %files devel %defattr(-,root,root) %doc AUTHORS COPYING %if %{with_ospfclient} %{_sbindir}/ospfclient %endif %dir %{_libdir}/quagga/ %{_libdir}/quagga/*.a %{_libdir}/quagga/*.la %dir %attr(755,root,root) %{_includedir}/%{name} %{_includedir}/%name/*.h %dir %attr(755,root,root) %{_includedir}/%{name}/ospfd %{_includedir}/%name/ospfd/*.h %if %{with_ospfapi} %dir %attr(755,root,root) %{_includedir}/%{name}/ospfapi %{_includedir}/%name/ospfapi/*.h %endif %changelog * Sun Mar 5 2017 Paul Jakma - Fix lint errors - Make texi2html conditional, disable by default to avoid needing TeX by default * Mon Feb 27 2017 Paul Jakma - Apply 0001-systemd-various-service-file-improvements.patch from Fedora - Review Fedora spec file and sync up with any useful differences, inc: - Add tmpfiles.d config for Quagga from Fedora - Add quagga-filter-perl-requires.sh from Fedora. - Move libs to %%{_libdir}/quagga as per Fedora - use systemd_postun_with_restart for postun * Tue Feb 14 2017 Timo Teräs - add nhrpd * Thu Feb 11 2016 Paul Jakma - remove with_ipv6 conditionals, always build v6 - Fix UTF-8 char in spec changelog - remove quagga.pam.stack, long deprecated. * Thu Oct 22 2015 Martin Winter - Cleanup configure: remove --enable-ipv6 (default now), --enable-nssa, --enable-netlink - Remove support for old fedora 4/5 - Fix for package nameing - Fix Weekdays of previous changelogs (bogus dates) - Add conditional logic to only build tex footnotes with supported texi2html - Added pimd to files section and fix double listing of /var/lib*/quagga - Numerous fixes to unify upstart/systemd startup into same spec file - Only allow use of watchquagga for non-systemd systems. no need with systemd * Fri Sep 4 2015 Paul Jakma - buildreq updates - add a default define for with_pimd * Mon Sep 12 2005 Paul Jakma - Steal some changes from Fedora spec file: - Add with_rtadv variable - Test for groups/users with getent before group/user adding - Readline need not be an explicit prerequisite - install-info delete should be postun, not preun * Wed Jan 12 2005 Andrew J. Schorr - on package upgrade, implement careful, phased restart logic - use gcc -rdynamic flag when linking for better backtraces * Wed Dec 22 2004 Andrew J. Schorr - daemonv6_list should contain only IPv6 daemons * Wed Dec 22 2004 Andrew J. Schorr - watchquagga added - on upgrade, all daemons should be condrestart'ed - on removal, all daemons should be stopped * Mon Nov 08 2004 Paul Jakma - Use makeinfo --html to generate quagga.html * Sun Nov 07 2004 Paul Jakma - Fix with_ipv6 set to 0 build * Sat Oct 23 2004 Paul Jakma - Update to 0.97.2 * Sat Oct 23 2004 Andrew J. Schorr - Make directories be owned by the packages concerned - Update logrotate scripts to use correct path to killall and use pid files * Fri Oct 08 2004 Paul Jakma - Update to 0.97.0 * Wed Sep 15 2004 Paul Jakma - build snmp support by default - build irdp support - build with shared libs - devel subpackage for archives and headers * Thu Jan 08 2004 Paul Jakma - updated sysconfig files to specify local dir - added ospf_dump.c crash quick fix patch - added ospfd persistent interface configuration patch * Tue Dec 30 2003 Paul Jakma - sync to CVS - integrate RH sysconfig patch to specify daemon options (RH) - default to have vty listen only to 127.1 (RH) - add user with fixed UID/GID (RH) - create user with shell /sbin/nologin rather than /bin/false (RH) - stop daemons on uninstall (RH) - delete info file on preun, not postun to avoid deletion on upgrade. (RH) - isisd added - cleanup tasks carried out for every daemon * Sun Nov 2 2003 Paul Jakma - Fix -devel package to include all files - Sync to 0.96.4 * Tue Aug 12 2003 Paul Jakma - Renamed to Quagga - Sync to Quagga release 0.96 * Thu Mar 20 2003 Paul Jakma - zebra privileges support * Tue Mar 18 2003 Paul Jakma - Fix mem leak in 'show thread cpu' - Ralph Keller's OSPF-API - Amir: Fix configure.ac for net-snmp * Sat Mar 1 2003 Paul Jakma - ospfd IOS prefix to interface matching for 'network' statement - temporary fix for PtP and IPv6 - sync to zebra.org CVS * Mon Jan 20 2003 Paul Jakma - update to latest cvs - Yon's "show thread cpu" patch - 17217 - walk up tree - 17218 - ospfd NSSA fixes - 16681 - ospfd nsm fixes - 16824 - ospfd OLSA fixes and new feature - 16823 - KAME and ifindex fixes - 16525 - spec file changes to allow redhat files to be in tree * Sat Dec 28 2002 Alexander Hoogerhuis - Added conditionals for building with(out) IPv6, vtysh, RIP, BGP - Fixed up some build requirements (patch) - Added conditional build requirements for vtysh / snmp - Added conditional to files for _bindir depending on vtysh * Mon Nov 11 2002 Paul Jakma - update to latest CVS - add Greg Troxel's md5 buffer copy/dup fix - add RIPv1 fix - add Frank's multicast flag fix * Wed Oct 09 2002 Paul Jakma - update to latest CVS - timestamped crypt_seqnum patch - oi->on_write_q fix * Mon Sep 30 2002 Paul Jakma - update to latest CVS - add vtysh 'write-config (integrated|daemon)' patch - always 'make rebuild' in vtysh/ to catch new commands * Fri Sep 13 2002 Paul Jakma - update to 0.93b * Wed Sep 11 2002 Paul Jakma - update to latest CVS - add "/sbin/ip route flush proto zebra" to zebra RH init on startup * Sat Aug 24 2002 Paul Jakma - update to current CVS - add OSPF point to multipoint patch - add OSPF bugfixes - add BGP hash optimisation patch * Fri Jun 14 2002 Paul Jakma - update to 0.93-pre1 / CVS - add link state detection support - add generic PtP and RFC3021 support - various bug fixes * Thu Aug 09 2001 Elliot Lee 0.91a-6 - Fix bug #51336 * Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) * Fri Jul 27 2001 Elliot Lee 0.91a-4 - Bump the release when rebuilding into the dist. * Tue Feb 6 2001 Tim Powers - built for Powertools * Sun Feb 4 2001 Pekka Savola - Hacked up from PLD Linux 0.90-1, Mandrake 0.90-1mdk and one from zebra.org. - Update to 0.91a - Very heavy modifications to init.d/*, .spec, pam, i18n, logrotate, etc. - Should be quite Red Hat'isque now. quagga-1.2.4/redhat/quagga.spec.in000066400000000000000000000542151325323223500167670ustar00rootroot00000000000000# configure options # # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' # (use any value, ie 1 for flag "with_XXXX" definitions) # # E.g. rpmbuild --define 'release_rev 02' may be useful if building # rpms again and again on the same day, so the newer rpms can be installed. # bumping the number each time. ####################### Quagga configure options ######################### # with-feature options %{!?with_snmp: %global with_snmp 1 } %{!?with_vtysh: %global with_vtysh 1 } %{!?with_tcp_zebra: %global with_tcp_zebra 0 } %{!?with_vtysh: %global with_vtysh 1 } %{!?with_pam: %global with_pam 1 } %{!?with_ospfclient: %global with_ospfclient 1 } %{!?with_ospfapi: %global with_ospfapi 1 } %{!?with_irdp: %global with_irdp 1 } %{!?with_rtadv: %global with_rtadv 1 } %{!?with_isisd: %global with_isisd 1 } %{!?with_pimd: %global with_pimd 1 } %{!?with_nhrpd: %global with_nhrpd 1 } %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 64 } %{!?quagga_user: %global quagga_user quagga } %{!?vty_group: %global vty_group quaggavt } %{!?with_fpm: %global with_fpm 0 } %{!?with_watchquagga: %global with_watchquagga 1 } # whether to build doc/quagga.html - requires a lot of TeX packages %{!?with_texi2html: %global with_texi2html 0 } # path defines %define _sysconfdir /etc/quagga %define zeb_src %{_builddir}/%{name}-%{quaggaversion} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc # defines for configure %define _localstatedir /var/run/quagga ############################################################################ #### Version String tweak # Remove invalid characters form version string and replace with _ %{expand: %%global rpmversion %(echo '@VERSION@' | tr [:blank:]- _ )} %define quaggaversion @VERSION@ #### Check version of texi2html # Old versions don't support "--number-footnotes" option. %if %{with_texi2html} %{expand: %%global texi2htmlversion %(type texi2html >/dev/null 2>&1 && (rpm -q --qf '%%{VERSION}' texi2html | cut -d. -f1) || echo 0 )} %endif #### Check for systemd or init.d (upstart) # Check for init.d (upstart) as used in CentOS 6 or systemd (ie CentOS 7) %{expand: %%global initsystem %(if [[ `/sbin/init --version 2> /dev/null` =~ upstart ]]; then echo upstart; elif [[ `systemctl` =~ -\.mount ]]; then echo systemd; fi)} # # If init system is systemd, then always disable watchquagga # %if "%{initsystem}" == "systemd" # Note: For systems with systemd, watchquagga will NOT be built. Systemd # takes over the role of restarting crashed processes. Value will # be overwritten with 0 below for systemd independent on the setting here %global with_watchquagga 0 %endif # if FPM is enabled, then enable tcp_zebra as well # %if %{with_fpm} %global with_tcp_zebra 1 %endif # misc internal defines %{!?quagga_uid: %global quagga_uid 92 } %{!?quagga_gid: %global quagga_gid 92 } %{!?vty_gid: %global vty_gid 85 } %define daemon_list zebra ripd ospfd bgpd %define daemonv6_list ripngd ospf6d %if %{with_isisd} %define daemon_isisd isisd %else %define daemon_isisd "" %endif %if %{with_pimd} %define daemon_pimd pimd %else %define daemon_pimd "" %endif %if %{with_nhrpd} %define daemon_nhrpd nhrpd %else %define daemon_nhrpd "" %endif %if %{with_watchquagga} %define daemon_watchquagga watchquagga %else %define daemon_watchquagga "" %endif %define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_isisd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_watchquagga} # allow build dir to be kept %{!?keep_build: %global keep_build 0 } #release sub-revision (the two digits after the CONFDATE) %{!?release_rev: %global release_rev 01 } Summary: Routing daemon Name: quagga Version: %{rpmversion} Release: @CONFDATE@%{release_rev}%{?dist} License: GPLv2+ Group: System Environment/Daemons Source0: https://download.savannah.gnu.org/releases/quagga/%{name}-%{quaggaversion}.tar.gz URL: https://www.quagga.net Requires: ncurses Requires(pre): /sbin/install-info Requires(preun): /sbin/install-info Requires(post): /sbin/install-info BuildRequires: autoconf patch libcap-devel groff BuildRequires: perl-generators pkgconfig %if %{with_texi2html} BuildRequires: texi2html %endif %if %{with_snmp} BuildRequires: net-snmp-devel Requires: net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel Requires: ncurses %endif %if %{with_pam} BuildRequires: pam-devel Requires: pam %endif %if %{with_nhrpd} BuildRequires: c-ares-devel Requires: c-ares %endif %if "%{initsystem}" == "systemd" BuildRequires: systemd Requires(post): systemd Requires(preun): systemd Requires(postun): systemd %else # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 %endif Provides: routingdaemon = %{version}-%{release} BuildRoot: %{_tmppath}/%{name}-%{version}-root #Obsoletes: mrt zebra quagga-sysvinit %define __perl_requires %{zeb_rh_src}/quagga-filter-perl-requires.sh %description Quagga is a free software routing protocol suite. Quagga supports BGP, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM-SSM and NHRP. %package contrib Summary: contrib tools for quagga Group: System Environment/Daemons %description contrib Contributed/3rd party tools which may be of use with quagga. %package devel Summary: Header and object files for quagga development Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} %description devel The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep %setup -q -n quagga-%{quaggaversion} %build %configure \ --sysconfdir=%{_sysconfdir} \ --libdir=%{_libdir}/quagga \ --libexecdir=%{_libexecdir} \ --localstatedir=%{_localstatedir} \ --disable-werror \ %if !%{with_shared} --disable-shared \ %endif %if %{with_snmp} --enable-snmp \ %endif %if %{with_multipath} --enable-multipath=%{with_multipath} \ %endif %if %{with_tcp_zebra} --enable-tcp-zebra \ %endif %if %{with_vtysh} --enable-vtysh \ %endif %if %{with_ospfclient} --enable-ospfclient=yes \ %else --enable-ospfclient=no\ %endif %if %{with_ospfapi} --enable-ospfapi=yes \ %else --enable-ospfapi=no \ %endif %if %{with_irdp} --enable-irdp=yes \ %else --enable-irdp=no \ %endif %if %{with_rtadv} --enable-rtadv=yes \ %else --enable-rtadv=no \ %endif %if %{with_isisd} --enable-isisd \ %else --disable-isisd \ %endif %if %{with_nhrpd} --enable-nhrpd \ %else --disable-nhrpd \ %endif %if %{with_pam} --with-libpam \ %endif %if 0%{?quagga_user:1} --enable-user=%quagga_user \ --enable-group=%quagga_user \ %endif %if 0%{?vty_group:1} --enable-vty-group=%vty_group \ %endif %if %{with_fpm} --enable-fpm \ %else --disable-fpm \ %endif %if %{with_watchquagga} --enable-watchquagga \ %else --disable-watchquagga \ %endif --enable-gcc-rdynamic make %{?_smp_mflags} %if %{with_texi2html} pushd doc %if %{texi2htmlversion} < 5 texi2html --number-sections quagga.texi %else texi2html --number-footnotes --number-sections quagga.texi %endif popd %endif %install mkdir -p %{buildroot}/etc/{quagga,sysconfig,logrotate.d,pam.d} \ %{buildroot}/var/log/quagga %{buildroot}%{_infodir} make DESTDIR=%{buildroot} INSTALL="install -p" CP="cp -p" install # Remove this file, as it is uninstalled and causes errors when building on RH9 rm -rf %{buildroot}/usr/share/info/dir # install /etc sources %if "%{initsystem}" == "systemd" mkdir -p %{buildroot}%{_unitdir} for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.service \ %{buildroot}%{_unitdir}/${daemon}.service fi done %else mkdir -p %{buildroot}/etc/rc.d/init.d for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.init \ %{buildroot}/etc/rc.d/init.d/${daemon} fi done %endif install -m644 %{zeb_rh_src}/quagga.pam \ %{buildroot}/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ %{buildroot}/etc/logrotate.d/quagga install -m644 %{zeb_rh_src}/quagga.sysconfig \ %{buildroot}/etc/sysconfig/quagga install -d -m750 %{buildroot}/var/run/quagga %if 0%{?_tmpfilesdir:1} install -d -m 755 %{buildroot}/%{_tmpfilesdir} install -p -m 644 %{zeb_rh_src}/quagga-tmpfs.conf \ %{buildroot}/%{_tmpfilesdir}/quagga.conf %endif %pre # add vty_group %if 0%{?vty_group:1} if getent group %vty_group > /dev/null ; then : ; else \ /usr/sbin/groupadd -r -g %vty_gid %vty_group > /dev/null || : ; fi %endif # add quagga user and group %if 0%{?quagga_user:1} # Ensure that quagga_gid gets correctly allocated if getent group %quagga_user >/dev/null; then : ; else \ /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ fi if getent passwd %quagga_user >/dev/null ; then : ; else \ /usr/sbin/useradd -u %quagga_uid -g %quagga_gid -G %vty_group \ -M -r -s /sbin/nologin -c "Quagga routing suite" \ -d %_localstatedir %quagga_user 2> /dev/null || : ; \ fi %endif %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 ] && \ ! %__sed -e 's/#.*$//' /etc/services | %__grep -wq $1 ; 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" %if %{with_ospfapi} zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %endif %if %{with_isisd} zebra_spec_add_service isisd 2608/tcp "ISISd vty" %endif %if %{with_pimd} zebra_spec_add_service pimd 2611/tcp "PIMd vty" %endif %if %{with_nhrpd} zebra_spec_add_service nhrpd 2612/tcp "NHRPd vty" %endif %if "%{initsystem}" == "systemd" for daemon in %all_daemons ; do %systemd_post ${daemon}.service done %else for daemon in %all_daemons ; do /sbin/chkconfig --add ${daemon} done %endif if [ -f %{_infodir}/%{name}.inf* ]; then /sbin/install-info %{_infodir}/quagga.info %{_infodir}/dir fi # Create dummy files if they don't exist so basic functions can be used. if [ ! -e %{_sysconfdir}/zebra.conf ]; then echo "hostname `hostname`" > %{_sysconfdir}/zebra.conf %if 0%{?quagga_user:1} chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf* %endif chmod 640 %{_sysconfdir}/zebra.conf fi for daemon in %{all_daemons} ; do if [ ! -e %{_sysconfdir}/${daemon}.conf ]; then touch %{_sysconfdir}/${daemon}.conf %if 0%{?quagga_user:1} chown %quagga_user:%quagga_user %{_sysconfdir}/${daemon}.conf* %endif fi done %if %{with_watchquagga} # No config for watchquagga - this is part of /etc/sysconfig/quagga rm -f %{_sysconfdir}/watchquagga.* %endif if [ ! -e %{_sysconfdir}/vtysh.conf ]; then touch %{_sysconfdir}/vtysh.conf chmod 640 %{_sysconfdir}/vtysh.conf %if 0%{?vty_group:1} chown quagga:%{vty_group} %{_sysconfdir}/vtysh.conf* %endif fi %postun if [ "$1" -ge 1 ]; then # Find out which daemons need to be restarted. for daemon in %all_daemons ; do if [ -f /var/lock/subsys/${daemon} ]; then eval restart_${daemon}=yes else eval restart_${daemon}=no fi done # Rename restart flags for daemons handled specially. running_zebra="$restart_zebra" restart_zebra=no %if %{with_watchquagga} running_watchquagga="$restart_watchquagga" restart_watchquagga=no %endif %if "%{initsystem}" == "systemd" ## ## Systemd Version ## # No watchquagga for systemd version # # Stop all daemons other than zebra. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ %systemd_postun_with_restart ${daemon}.service done # Restart zebra. [ "$running_zebra" = yes ] && \ %systemd_postun_with_restart $daemon.service # Start all daemons other than zebra. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ %systemd_post ${daemon}.service done %else ## ## init.d Version ## %if %{with_watchquagga} # Stop watchquagga first. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 %endif # Stop all daemons other than zebra and watchquagga. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 done # Restart zebra. [ "$running_zebra" = yes ] && \ /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 # Start all daemons other than zebra and watchquagga. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/${daemon} start >/dev/null 2>&1 done %if %{with_watchquagga} # Start watchquagga last. # Avoid postun scriptlet error if watchquagga is not running. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : %endif %endif fi if [ -f %{_infodir}/%{name}.inf* ]; then /sbin/install-info --delete %{_infodir}/quagga.info %{_infodir}/dir fi %preun %if "%{initsystem}" == "systemd" ## ## Systemd Version ## if [ "$1" = "0" ]; then for daemon in %all_daemons ; do %systemd_preun ${daemon}.service done fi %else ## ## init.d Version ## if [ "$1" = "0" ]; then for daemon in %all_daemons ; do /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 /sbin/chkconfig --del ${daemon} done fi %endif %clean %if !0%{?keep_build:1} rm -rf %{buildroot} %endif %files %defattr(-,root,root) %doc */*.sample* AUTHORS COPYING %if %{with_texi2html} %doc doc/quagga.html %endif %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO %if 0%{?quagga_user:1} %dir %attr(751,%quagga_user,%quagga_user) %{_sysconfdir} %dir %attr(750,%quagga_user,%quagga_user) /var/log/quagga %dir %attr(751,%quagga_user,%quagga_user) /var/run/quagga %else %dir %attr(750,root,root) %{_sysconfdir} %dir %attr(750,root,root) /var/log/quagga %dir %attr(750,root,root) /var/run/quagga %endif %if 0%{?vty_group:1} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif %{_infodir}/quagga.info*.gz %{_mandir}/man*/* %if %{with_watchquagga} %{_mandir}/man*/watchquagga.* %endif %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd %if %{with_watchquagga} %{_sbindir}/watchquagga %endif %{_sbindir}/ripngd %{_sbindir}/ospf6d %if %{with_pimd} %{_sbindir}/pimd %endif %if %{with_isisd} %{_sbindir}/isisd %endif %if %{with_nhrpd} %{_sbindir}/nhrpd %endif %if %{with_shared} %{_libdir}/quagga/lib*.so %{_libdir}/quagga/lib*.so.? %attr(755,root,root) %{_libdir}/quagga/lib*.so.?.?.? %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* %if "%{initsystem}" == "systemd" %{_unitdir}/*.service %else %config /etc/rc.d/init.d/zebra %if %{with_watchquagga} %config /etc/rc.d/init.d/watchquagga %endif %config /etc/rc.d/init.d/ripd %config /etc/rc.d/init.d/ospfd %config /etc/rc.d/init.d/bgpd %config /etc/rc.d/init.d/ripngd %config /etc/rc.d/init.d/ospf6d %if %{with_isisd} %config /etc/rc.d/init.d/isisd %endif %if %{with_pimd} %config /etc/rc.d/init.d/pimd %endif %if %{with_nhrpd} %config /etc/rc.d/init.d/nhrpd %endif %endif %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* %{_tmpfilesdir}/quagga.conf %files contrib %defattr(-,root,root) %doc AUTHORS COPYING %attr(0644,root,root) tools %files devel %defattr(-,root,root) %doc AUTHORS COPYING %if %{with_ospfclient} %{_sbindir}/ospfclient %endif %dir %{_libdir}/quagga/ %{_libdir}/quagga/*.a %{_libdir}/quagga/*.la %dir %attr(755,root,root) %{_includedir}/%{name} %{_includedir}/%name/*.h %dir %attr(755,root,root) %{_includedir}/%{name}/ospfd %{_includedir}/%name/ospfd/*.h %if %{with_ospfapi} %dir %attr(755,root,root) %{_includedir}/%{name}/ospfapi %{_includedir}/%name/ospfapi/*.h %endif %changelog * Sun Mar 5 2017 Paul Jakma - Fix lint errors - Make texi2html conditional, disable by default to avoid needing TeX by default * Mon Feb 27 2017 Paul Jakma - Apply 0001-systemd-various-service-file-improvements.patch from Fedora - Review Fedora spec file and sync up with any useful differences, inc: - Add tmpfiles.d config for Quagga from Fedora - Add quagga-filter-perl-requires.sh from Fedora. - Move libs to %%{_libdir}/quagga as per Fedora - use systemd_postun_with_restart for postun * Tue Feb 14 2017 Timo Teräs - add nhrpd * Thu Feb 11 2016 Paul Jakma - remove with_ipv6 conditionals, always build v6 - Fix UTF-8 char in spec changelog - remove quagga.pam.stack, long deprecated. * Thu Oct 22 2015 Martin Winter - Cleanup configure: remove --enable-ipv6 (default now), --enable-nssa, --enable-netlink - Remove support for old fedora 4/5 - Fix for package nameing - Fix Weekdays of previous changelogs (bogus dates) - Add conditional logic to only build tex footnotes with supported texi2html - Added pimd to files section and fix double listing of /var/lib*/quagga - Numerous fixes to unify upstart/systemd startup into same spec file - Only allow use of watchquagga for non-systemd systems. no need with systemd * Fri Sep 4 2015 Paul Jakma - buildreq updates - add a default define for with_pimd * Mon Sep 12 2005 Paul Jakma - Steal some changes from Fedora spec file: - Add with_rtadv variable - Test for groups/users with getent before group/user adding - Readline need not be an explicit prerequisite - install-info delete should be postun, not preun * Wed Jan 12 2005 Andrew J. Schorr - on package upgrade, implement careful, phased restart logic - use gcc -rdynamic flag when linking for better backtraces * Wed Dec 22 2004 Andrew J. Schorr - daemonv6_list should contain only IPv6 daemons * Wed Dec 22 2004 Andrew J. Schorr - watchquagga added - on upgrade, all daemons should be condrestart'ed - on removal, all daemons should be stopped * Mon Nov 08 2004 Paul Jakma - Use makeinfo --html to generate quagga.html * Sun Nov 07 2004 Paul Jakma - Fix with_ipv6 set to 0 build * Sat Oct 23 2004 Paul Jakma - Update to 0.97.2 * Sat Oct 23 2004 Andrew J. Schorr - Make directories be owned by the packages concerned - Update logrotate scripts to use correct path to killall and use pid files * Fri Oct 08 2004 Paul Jakma - Update to 0.97.0 * Wed Sep 15 2004 Paul Jakma - build snmp support by default - build irdp support - build with shared libs - devel subpackage for archives and headers * Thu Jan 08 2004 Paul Jakma - updated sysconfig files to specify local dir - added ospf_dump.c crash quick fix patch - added ospfd persistent interface configuration patch * Tue Dec 30 2003 Paul Jakma - sync to CVS - integrate RH sysconfig patch to specify daemon options (RH) - default to have vty listen only to 127.1 (RH) - add user with fixed UID/GID (RH) - create user with shell /sbin/nologin rather than /bin/false (RH) - stop daemons on uninstall (RH) - delete info file on preun, not postun to avoid deletion on upgrade. (RH) - isisd added - cleanup tasks carried out for every daemon * Sun Nov 2 2003 Paul Jakma - Fix -devel package to include all files - Sync to 0.96.4 * Tue Aug 12 2003 Paul Jakma - Renamed to Quagga - Sync to Quagga release 0.96 * Thu Mar 20 2003 Paul Jakma - zebra privileges support * Tue Mar 18 2003 Paul Jakma - Fix mem leak in 'show thread cpu' - Ralph Keller's OSPF-API - Amir: Fix configure.ac for net-snmp * Sat Mar 1 2003 Paul Jakma - ospfd IOS prefix to interface matching for 'network' statement - temporary fix for PtP and IPv6 - sync to zebra.org CVS * Mon Jan 20 2003 Paul Jakma - update to latest cvs - Yon's "show thread cpu" patch - 17217 - walk up tree - 17218 - ospfd NSSA fixes - 16681 - ospfd nsm fixes - 16824 - ospfd OLSA fixes and new feature - 16823 - KAME and ifindex fixes - 16525 - spec file changes to allow redhat files to be in tree * Sat Dec 28 2002 Alexander Hoogerhuis - Added conditionals for building with(out) IPv6, vtysh, RIP, BGP - Fixed up some build requirements (patch) - Added conditional build requirements for vtysh / snmp - Added conditional to files for _bindir depending on vtysh * Mon Nov 11 2002 Paul Jakma - update to latest CVS - add Greg Troxel's md5 buffer copy/dup fix - add RIPv1 fix - add Frank's multicast flag fix * Wed Oct 09 2002 Paul Jakma - update to latest CVS - timestamped crypt_seqnum patch - oi->on_write_q fix * Mon Sep 30 2002 Paul Jakma - update to latest CVS - add vtysh 'write-config (integrated|daemon)' patch - always 'make rebuild' in vtysh/ to catch new commands * Fri Sep 13 2002 Paul Jakma - update to 0.93b * Wed Sep 11 2002 Paul Jakma - update to latest CVS - add "/sbin/ip route flush proto zebra" to zebra RH init on startup * Sat Aug 24 2002 Paul Jakma - update to current CVS - add OSPF point to multipoint patch - add OSPF bugfixes - add BGP hash optimisation patch * Fri Jun 14 2002 Paul Jakma - update to 0.93-pre1 / CVS - add link state detection support - add generic PtP and RFC3021 support - various bug fixes * Thu Aug 09 2001 Elliot Lee 0.91a-6 - Fix bug #51336 * Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) * Fri Jul 27 2001 Elliot Lee 0.91a-4 - Bump the release when rebuilding into the dist. * Tue Feb 6 2001 Tim Powers - built for Powertools * Sun Feb 4 2001 Pekka Savola - Hacked up from PLD Linux 0.90-1, Mandrake 0.90-1mdk and one from zebra.org. - Update to 0.91a - Very heavy modifications to init.d/*, .spec, pam, i18n, logrotate, etc. - Should be quite Red Hat'isque now. quagga-1.2.4/redhat/quagga.sysconfig000066400000000000000000000020051325323223500174220ustar00rootroot00000000000000# # Default: Bind all daemon vtys to the loopback(s) only # BABELD_OPTS="-A 127.0.0.1" BGPD_OPTS="-A 127.0.0.1" ISISD_OPTS="-A ::1" OSPF6D_OPTS="-A ::1" OSPFD_OPTS="-A 127.0.0.1" RIPD_OPTS="-A 127.0.0.1" RIPNGD_OPTS="-A ::1" ZEBRA_OPTS="-A 127.0.0.1" PIMD_OPTS="-A 127.0.0.1" # Default: The compiled in default user and group(s), useful to # system startup to chmod config files. QUAGGA_USER=quagga QUAGGA_GROUP=quagga VTY_GROUP= # Watchquagga configuration for LSB initscripts # # (Not needed with systemd: the service files are configured to automatically # restart any daemon on failure. If zebra fails, all running daemons will be # stopped; zebra will be started again; and then the previously running daemons # will be started again.) # # Uncomment and edit this line to reflect the daemons you are actually using: #WATCH_DAEMONS="zebra bgpd ospfd ospf6d ripd ripngd" # # Timer values can be adjusting by editing this line: WATCH_OPTS="-Az -b_ -r/sbin/service_%s_restart -s/sbin/service_%s_start -k/sbin/service_%s_stop" quagga-1.2.4/redhat/quagga.sysconfig.in000066400000000000000000000020461325323223500200340ustar00rootroot00000000000000# # Default: Bind all daemon vtys to the loopback(s) only # BABELD_OPTS="-A 127.0.0.1" BGPD_OPTS="-A 127.0.0.1" ISISD_OPTS="-A ::1" OSPF6D_OPTS="-A ::1" OSPFD_OPTS="-A 127.0.0.1" RIPD_OPTS="-A 127.0.0.1" RIPNGD_OPTS="-A ::1" ZEBRA_OPTS="-A 127.0.0.1" PIMD_OPTS="-A 127.0.0.1" # Default: The compiled in default user and group(s), useful to # system startup to chmod config files. QUAGGA_USER=@enable_user@ QUAGGA_GROUP=@enable_group@ VTY_GROUP=@enable_vty_group@ # Watchquagga configuration for LSB initscripts # # (Not needed with systemd: the service files are configured to automatically # restart any daemon on failure. If zebra fails, all running daemons will be # stopped; zebra will be started again; and then the previously running daemons # will be started again.) # # Uncomment and edit this line to reflect the daemons you are actually using: #WATCH_DAEMONS="zebra bgpd ospfd ospf6d ripd ripngd" # # Timer values can be adjusting by editing this line: WATCH_OPTS="-Az -b_ -r/sbin/service_%s_restart -s/sbin/service_%s_start -k/sbin/service_%s_stop" quagga-1.2.4/redhat/ripd.init000066400000000000000000000023771325323223500160660ustar00rootroot00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/ripd.conf ### BEGIN INIT INFO # Provides: ripd # Short-Description: RIP routing engine # Description: RIP routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="ripd" cmd=ripd LOCK_FILE=/var/lock/subsys/ripd CONF_FILE=/etc/quagga/ripd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $RIPD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/ripd.service000066400000000000000000000010071325323223500165500ustar00rootroot00000000000000[Unit] Description=RIP routing daemon BindsTo=zebra.service Wants=network.target After=zebra.service network-pre.target Before=network.target ConditionPathExists=/etc/quagga/ripd.conf Documentation=man:ripd [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStartPre=-/bin/chmod -f 640 /etc/quagga/ripd.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /etc/quagga/ripd.conf ExecStart=/usr/sbin/ripd -d $RIPD_OPTS -f /etc/quagga/ripd.conf Restart=on-abort [Install] WantedBy=multi-user.target quagga-1.2.4/redhat/ripngd.init000066400000000000000000000024371325323223500164100ustar00rootroot00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/ripngd.conf ### BEGIN INIT INFO # Provides: ripngd # Short-Description: RIP routing engine for IPv6 # Description: RIP routing engine for use with Zebra and IPv6 ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="ripngd" cmd=ripngd LOCK_FILE=/var/lock/subsys/ripngd CONF_FILE=/etc/quagga/ripngd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $RIPNGD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/ripngd.service000066400000000000000000000010361325323223500170770ustar00rootroot00000000000000[Unit] Description=RIP routing daemon for IPv6 BindsTo=zebra.service Wants=network.target After=zebra.service network-pre.target Before=network.target ConditionPathExists=/etc/quagga/ripngd.conf Documentation=man:ripngd [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStartPre=-/bin/chmod -f 640 /etc/quagga/ripngd.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /etc/quagga/ripngd.conf ExecStart=/usr/sbin/ripngd -d $RIPNGD_OPTS -f /etc/quagga/ripngd.conf Restart=on-abort [Install] WantedBy=multi-user.target quagga-1.2.4/redhat/watchquagga.init000066400000000000000000000022311325323223500174110ustar00rootroot00000000000000#!/bin/bash # chkconfig: 2345 17 83 ### BEGIN INIT INFO # Provides: watchquagga # Short-Description: Quagga watchdog # Description: Quagga watchdog for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="watchquagga" cmd=watchquagga LOCK_FILE=/var/lock/subsys/watchquagga case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # Check that there are daemons to be monitored. [ -z "$WATCH_DAEMONS" ] && exit 1 echo -n $"Starting $PROG: " daemon $cmd -d $WATCH_OPTS $WATCH_DAEMONS RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/zebra.init000066400000000000000000000024431325323223500162250ustar00rootroot00000000000000#!/bin/bash # chkconfig: - 15 85 # config: /etc/quagga/zebra.conf ### BEGIN INIT INFO # Provides: zebra # Short-Description: GNU Zebra routing manager # Description: GNU Zebra routing manager ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="zebra" cmd=zebra LOCK_FILE=/var/lock/subsys/zebra CONF_FILE=/etc/quagga/zebra.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " /sbin/ip route flush proto zebra daemon $cmd -d $ZEBRA_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-1.2.4/redhat/zebra.service000066400000000000000000000012521325323223500167170ustar00rootroot00000000000000[Unit] Description=GNU Zebra routing manager Wants=network.target Before=network.target After=network-pre.target ConditionPathExists=/etc/quagga/zebra.conf Documentation=man:zebra [Service] Type=forking EnvironmentFile=-/etc/sysconfig/quagga ExecStartPre=/sbin/ip route flush proto zebra ExecStartPre=-/bin/chmod -f 640 /etc/quagga/vtysh.conf /etc/quagga/zebra.conf ExecStartPre=-/bin/chown -f $QUAGGA_USER:$QUAGGA_GROUP /run/quagga /etc/quagga/zebra.conf ExecStartPre=-/bin/chown -f ${QUAGGA_USER}${VTY_GROUP:+":$VTY_GROUP"} quaggavty /etc/quagga/vtysh.conf ExecStart=/usr/sbin/zebra -d $ZEBRA_OPTS -f /etc/quagga/zebra.conf Restart=on-abort [Install] WantedBy=multi-user.target quagga-1.2.4/ripd/000077500000000000000000000000001325323223500137215ustar00rootroot00000000000000quagga-1.2.4/ripd/Makefile.am000066400000000000000000000012161325323223500157550ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) 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 rip_interface.h ripd_SOURCES = \ rip_main.c $(librip_a_SOURCES) ripd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ripd.conf.sample EXTRA_DIST = RIPv2-MIB.txt quagga-1.2.4/ripd/Makefile.in000066400000000000000000000612401325323223500157710ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ripd$(EXEEXT) subdir = ripd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = librip_a_AR = $(AR) $(ARFLAGS) 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) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" 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.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(librip_a_SOURCES) $(ripd_SOURCES) DIST_SOURCES = $(librip_a_SOURCES) $(ripd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = librip.a 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 rip_interface.h ripd_SOURCES = \ rip_main.c $(librip_a_SOURCES) ripd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ripd.conf.sample EXTRA_DIST = RIPv2-MIB.txt all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ripd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ripd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) librip.a: $(librip_a_OBJECTS) $(librip_a_DEPENDENCIES) $(EXTRA_librip_a_DEPENDENCIES) $(AM_V_at)-rm -f librip.a $(AM_V_AR)$(librip_a_AR) librip.a $(librip_a_OBJECTS) $(librip_a_LIBADD) $(AM_V_at)$(RANLIB) librip.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ripd$(EXEEXT): $(ripd_OBJECTS) $(ripd_DEPENDENCIES) $(EXTRA_ripd_DEPENDENCIES) @rm -f ripd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ripd_OBJECTS) $(ripd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) 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@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/ripd/RIPv2-MIB.txt000066400000000000000000000405131325323223500157740ustar00rootroot00000000000000 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 quagga-1.2.4/ripd/rip_debug.c000066400000000000000000000157151325323223500160360ustar00rootroot00000000000000/* 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 (show_debugging_rip, show_debugging_rip_cmd, "show debugging rip", SHOW_STR DEBUG_STR RIP_STR) { vty_out (vty, "RIP 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 debugging is on%s", VTY_NEWLINE); } else { if (IS_RIP_DEBUG_SEND) vty_out (vty, " RIP packet send debugging is on%s", VTY_NEWLINE); else vty_out (vty, " RIP packet receive debugging is on%s", VTY_NEWLINE); } } if (IS_RIP_DEBUG_ZEBRA) vty_out (vty, " RIP zebra debugging is on%s", VTY_NEWLINE); return CMD_SUCCESS; } 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; return CMD_SUCCESS; } /* N.B. the "detail" modifier is a no-op. we leave this command for legacy compatibility. */ DEFUN_DEPRECATED (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; 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; } /* Debug node. */ static struct cmd_node debug_node = { DEBUG_NODE, "", /* Debug node has no interface. */ 1 }; static 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", VTY_NEWLINE); write++; } else { if (IS_RIP_DEBUG_SEND) vty_out (vty, "debug rip packet send%s", VTY_NEWLINE); else vty_out (vty, "debug rip packet recv%s", VTY_NEWLINE); write++; } } if (IS_RIP_DEBUG_ZEBRA) { vty_out (vty, "debug rip zebra%s", VTY_NEWLINE); write++; } return write; } void rip_debug_reset (void) { rip_debug_event = 0; rip_debug_packet = 0; rip_debug_zebra = 0; } void rip_debug_init (void) { rip_debug_event = 0; rip_debug_packet = 0; rip_debug_zebra = 0; install_node (&debug_node, config_write_debug); install_element (ENABLE_NODE, &show_debugging_rip_cmd); 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); } quagga-1.2.4/ripd/rip_debug.h000066400000000000000000000033271325323223500160370ustar00rootroot00000000000000/* 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_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; extern void rip_debug_init (void); extern void rip_debug_reset (void); #endif /* _ZEBRA_RIP_DEBUG_H */ quagga-1.2.4/ripd/rip_interface.c000066400000000000000000001440121325323223500167010ustar00rootroot00000000000000/* 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 "privs.h" #include "zebra/connected.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" /* static prototypes */ static void rip_enable_apply (struct interface *); static void rip_passive_interface_apply (struct interface *); static int rip_if_down(struct interface *ifp); static int rip_enable_if_lookup (const char *ifname); static int rip_enable_network_lookup2 (struct connected *connected); static void rip_enable_apply_all (void); const struct message ri_version_msg[] = { {RI_RIP_VERSION_1, "1"}, {RI_RIP_VERSION_2, "2"}, {RI_RIP_VERSION_1_AND_2, "1 2"}, }; extern struct zebra_privs_t ripd_privs; /* RIP enabled network vector. */ vector rip_enable_interface; /* RIP enabled interface table. */ struct route_table *rip_enable_network; /* Vector to store passive-interface name. */ static int passive_default; /* are we in passive-interface default mode? */ vector Vrip_passive_nondefault; /* Join to the RIP version 2 multicast group. */ static int ipv4_multicast_join (int sock, struct in_addr group, struct in_addr ifa, ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (sock, IP_ADD_MEMBERSHIP, group.s_addr, ifindex); if (ret < 0) zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP %s", safe_strerror (errno)); return ret; } /* Leave from the RIP version 2 multicast group. */ static int ipv4_multicast_leave (int sock, struct in_addr group, struct in_addr ifa, ifindex_t ifindex) { int ret; ret = setsockopt_ipv4_multicast (sock, IP_DROP_MEMBERSHIP, group.s_addr, ifindex); if (ret < 0) zlog (NULL, LOG_INFO, "can't setsockopt IP_DROP_MEMBERSHIP"); return ret; } static void rip_interface_reset (struct rip_interface *); /* Allocate new RIP's interface configuration. */ static struct rip_interface * rip_interface_new (void) { struct rip_interface *ri; ri = XCALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface)); rip_interface_reset (ri); return ri; } void rip_interface_multicast_set (int sock, struct connected *connected) { assert (connected != NULL); if (setsockopt_ipv4_multicast_if (sock, connected->ifp->ifindex) < 0) { zlog_warn ("Can't setsockopt IP_MULTICAST_IF on fd %d to " "ifindex %d for interface %s", sock, connected->ifp->ifindex, connected->ifp->name); } return; } /* Send RIP request packet to specified interface. */ static 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_debug ("multicast request on %s", ifp->name); rip_request_send (NULL, ifp, version, NULL); return; } /* RIPv1 and non multicast interface. */ if (if_is_pointopoint (ifp) || if_is_broadcast (ifp)) { struct listnode *cnode, *cnnode; struct connected *connected; if (IS_RIP_DEBUG_EVENT) zlog_debug ("broadcast request to %s", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, cnode, cnnode, connected)) { if (connected->address->family == AF_INET) { memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_port = htons (RIP_PORT_DEFAULT); if (connected->destination) /* use specified broadcast or peer destination addr */ to.sin_addr = connected->destination->u.prefix4; else if (connected->address->prefixlen < IPV4_MAX_PREFIXLEN) /* calculate the appropriate broadcast address */ to.sin_addr.s_addr = ipv4_broadcast_addr(connected->address->u.prefix4.s_addr, connected->address->prefixlen); else /* do not know where to send the packet */ continue; if (IS_RIP_DEBUG_EVENT) zlog_debug ("SEND request to %s", inet_ntoa (to.sin_addr)); rip_request_send (&to, ifp, version, connected); } } } } /* This will be executed when interface goes up. */ static 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_operative (ifp)) return; /* Fetch RIP interface information. */ ri = ifp->info; /* If there is no version configuration in the interface, use rip's version setting. */ { int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? rip->version_send : ri->ri_send); if (vsend & RIPv1) rip_request_interface_send (ifp, RIPv1); if (vsend & RIPv2) rip_request_interface_send (ifp, RIPv2); } } #if 0 /* Send RIP request to the neighbor. */ static 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_send, NULL); } /* Request routes at all interfaces. */ static void rip_request_neighbor_all (void) { struct route_node *rp; if (! rip) return; if (IS_RIP_DEBUG_EVENT) zlog_debug ("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); } #endif /* Multicast packet receive socket. */ static int rip_multicast_join (struct interface *ifp, int sock) { struct listnode *cnode; struct connected *ifc; if (if_is_operative (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast join at %s", ifp->name); for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc)) { struct prefix_ipv4 *p; struct in_addr group; p = (struct prefix_ipv4 *) ifc->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 return 0; } } return 0; } /* Leave from multicast group. */ static void rip_multicast_leave (struct interface *ifp, int sock) { struct listnode *cnode; struct connected *connected; if (if_is_up (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast leave from %s", ifp->name); for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { struct prefix_ipv4 *p; struct in_addr group; 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 ? */ static int rip_if_ipv4_address_check (struct interface *ifp) { struct listnode *nn; struct connected *connected; int count = 0; for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected)) { 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) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct listnode *cnode; struct connected *connected; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0) return 1; } } return 0; } /* Inteface link down message processing. */ int rip_interface_down (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist. */ ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; rip_if_down(ifp); if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface %s index %d flags %llx metric %d mtu %d is down", ifp->name, ifp->ifindex, (unsigned long long)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, vrf_id_t vrf_id) { struct interface *ifp; /* zebra_interface_state_read () updates interface structure in iflist. */ ifp = zebra_interface_state_read (zclient->ibuf, vrf_id); if (ifp == NULL) return 0; if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface %s index %d flags %#llx metric %d mtu %d is up", ifp->name, ifp->ifindex, (unsigned long long) 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, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface add %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) 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); /* rip_request_neighbor_all (); */ /* Check interface routemap. */ rip_if_rmap_update_interface (ifp); return 0; } int rip_interface_delete (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; if (if_is_up (ifp)) { rip_if_down(ifp); } zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ ifp->ifindex = IFINDEX_INTERNAL; return 0; } static void rip_interface_clean (struct rip_interface *ri) { 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_interfaces_clean (void) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) rip_interface_clean (ifp->info); } static void rip_interface_reset (struct rip_interface *ri) { /* Default authentication type is simple password for Cisco compatibility. */ ri->auth_type = RIP_NO_AUTH; ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE; /* 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 = RIP_SPLIT_HORIZON; ri->split_horizon = ri->split_horizon_default; ri->ri_send = RI_RIP_UNSPEC; ri->ri_receive = RI_RIP_UNSPEC; 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->list[RIP_FILTER_IN] = NULL; ri->list[RIP_FILTER_OUT] = NULL; ri->prefix[RIP_FILTER_IN] = NULL; ri->prefix[RIP_FILTER_OUT] = NULL; ri->recv_badpackets = 0; ri->recv_badroutes = 0; ri->sent_updates = 0; ri->passive = 0; rip_interface_clean (ri); } void rip_interfaces_reset (void) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) rip_interface_reset (ifp->info); } int rip_if_down(struct interface *ifp) { struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri = NULL; struct list *list = NULL; struct listnode *listnode = NULL, *nextnode = NULL; if (rip) for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS (list, listnode, nextnode, rinfo)) if (rinfo->ifindex == ifp->ifindex) rip_ecmp_delete (rinfo); ri = ifp->info; if (ri->running) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("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; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_if_down (ifp); } static void rip_apply_address_add (struct connected *ifc) { struct prefix_ipv4 address; struct prefix *p; if (!rip) return; if (! if_is_up(ifc->ifp)) return; p = ifc->address; memset (&address, 0, sizeof (address)); address.family = p->family; address.prefix = p->u.prefix4; address.prefixlen = p->prefixlen; apply_mask_ipv4(&address); /* Check if this interface is RIP enabled or not or Check if this address's prefix is RIP enabled */ if ((rip_enable_if_lookup(ifc->ifp->name) >= 0) || (rip_enable_network_lookup2(ifc) >= 0)) rip_redistribute_add(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, ifc->ifp->ifindex, NULL, 0, 0, 0); } int rip_interface_address_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; struct prefix *p; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf, vrf_id); if (ifc == NULL) return 0; p = ifc->address; if (p->family == AF_INET) { if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("connected address %s/%d is added", inet_ntoa (p->u.prefix4), p->prefixlen); rip_enable_apply(ifc->ifp); /* Check if this prefix needs to be redistributed */ rip_apply_address_add(ifc); #ifdef HAVE_SNMP rip_ifaddr_add (ifc->ifp, ifc); #endif /* HAVE_SNMP */ } return 0; } static void rip_apply_address_del (struct connected *ifc) { struct prefix_ipv4 address; struct prefix *p; if (!rip) return; if (! if_is_up(ifc->ifp)) return; p = ifc->address; memset (&address, 0, sizeof (address)); address.family = p->family; address.prefix = p->u.prefix4; address.prefixlen = p->prefixlen; apply_mask_ipv4(&address); rip_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, ifc->ifp->ifindex); } int rip_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; struct prefix *p; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf, vrf_id); if (ifc) { p = ifc->address; if (p->family == AF_INET) { if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("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 */ /* Chech wether this prefix needs to be removed */ rip_apply_address_del(ifc); } connected_free (ifc); } return 0; } /* Check interface is enabled by network statement. */ /* Check wether the interface has at least a connected prefix that * is within the ripng_enable_network table. */ static int rip_enable_network_lookup_if (struct interface *ifp) { struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv4 address; for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) { 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; } /* Check wether connected is within the ripng_enable_network table. */ int rip_enable_network_lookup2 (struct connected *connected) { struct prefix_ipv4 address; struct prefix *p; p = connected->address; if (p->family == AF_INET) { struct route_node *node; address.family = p->family; address.prefix = p->u.prefix4; address.prefixlen = IPV4_MAX_BITLEN; /* LPM on p->family, p->u.prefix4/IPV4_MAX_BITLEN within rip_enable_network */ node = route_node_match (rip_enable_network, (struct prefix *)&address); if (node) { route_unlock_node (node); return 1; } } return -1; } /* Add RIP enable network. */ static 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 = (char *) "enabled"; /* XXX: One should find a better solution than a generic one */ rip_enable_apply_all(); return 1; } /* Delete RIP enable network. */ static 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); /* XXX: One should find a better solution than a generic one */ rip_enable_apply_all (); return 1; } return -1; } /* Check interface is enabled by ifname statement. */ static int rip_enable_if_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (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. */ static int rip_enable_if_add (const char *ifname) { int ret; ret = rip_enable_if_lookup (ifname); if (ret >= 0) return -1; vector_set (rip_enable_interface, strdup (ifname)); rip_enable_apply_all(); /* TODOVJ */ return 1; } /* Delete interface from rip_enable_if. */ static int rip_enable_if_delete (const 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); rip_enable_apply_all(); /* TODOVJ */ return 1; } /* Join to multicast group and send request to the interface. */ static 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; } static void rip_connect_set (struct interface *ifp, int set) { struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv4 address; for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) { 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) { /* Check once more wether this prefix is within a "network IF_OR_PREF" one */ if ((rip_enable_if_lookup(connected->ifp->name) >= 0) || (rip_enable_network_lookup2(connected) >= 0)) rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, connected->ifp->ifindex, NULL, 0, 0, 0); } 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, 0, 0, 0); } } } /* Update interface status. */ void rip_enable_apply (struct interface *ifp) { int ret; struct rip_interface *ri = NULL; /* Check interface. */ if (! if_is_operative (ifp)) return; ri = ifp->info; /* Check network configuration. */ ret = rip_enable_network_lookup_if (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 (IS_RIP_DEBUG_EVENT) zlog_debug ("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) { /* Might as well clean up the route table as well * rip_if_down sets to 0 ri->running, and displays "turn off %s" **/ rip_if_down(ifp); rip_connect_set (ifp, 0); } } } /* Apply network configuration to all interface. */ void rip_enable_apply_all () { struct interface *ifp; struct listnode *node, *nnode; /* Check each interface. */ for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) 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. */ static 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. */ static 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 () { unsigned 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_active (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. */ static int rip_passive_nondefault_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (Vrip_passive_nondefault); i++) if ((str = vector_slot (Vrip_passive_nondefault, i)) != NULL) if (strcmp (str, ifname) == 0) return i; return -1; } void rip_passive_interface_apply (struct interface *ifp) { struct rip_interface *ri; ri = ifp->info; ri->passive = ((rip_passive_nondefault_lookup (ifp->name) < 0) ? passive_default : !passive_default); if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface %s: passive = %d",ifp->name,ri->passive); } static void rip_passive_interface_apply_all (void) { struct interface *ifp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_passive_interface_apply (ifp); } /* Passive interface. */ static int rip_passive_nondefault_set (struct vty *vty, const char *ifname) { if (rip_passive_nondefault_lookup (ifname) >= 0) return CMD_WARNING; vector_set (Vrip_passive_nondefault, strdup (ifname)); rip_passive_interface_apply_all (); return CMD_SUCCESS; } static int rip_passive_nondefault_unset (struct vty *vty, const char *ifname) { int i; char *str; i = rip_passive_nondefault_lookup (ifname); if (i < 0) return CMD_WARNING; str = vector_slot (Vrip_passive_nondefault, i); free (str); vector_unset (Vrip_passive_nondefault, i); rip_passive_interface_apply_all (); return CMD_SUCCESS; } /* Free all configured RIP passive-interface settings. */ void rip_passive_nondefault_clean (void) { unsigned int i; char *str; for (i = 0; i < vector_active (Vrip_passive_nondefault); i++) if ((str = vector_slot (Vrip_passive_nondefault, i)) != NULL) { free (str); vector_slot (Vrip_passive_nondefault, 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; } 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; } 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; int auth_type; ifp = (struct interface *)vty->index; ri = ifp->info; if ( (argc < 1) || (argc > 2) ) { vty_out (vty, "incorrect argument count%s", VTY_NEWLINE); return CMD_WARNING; } if (strncmp ("md5", argv[0], strlen (argv[0])) == 0) auth_type = RIP_AUTH_MD5; else if (strncmp ("text", argv[0], strlen (argv[0])) == 0) auth_type = RIP_AUTH_SIMPLE_PASSWORD; else { vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 1) { ri->auth_type = auth_type; return CMD_SUCCESS; } if ( (argc == 2) && (auth_type != RIP_AUTH_MD5) ) { vty_out (vty, "auth length argument only valid for md5%s", VTY_NEWLINE); return CMD_WARNING; } if (strncmp ("r", argv[1], 1) == 0) ri->md5_auth_len = RIP_AUTH_MD5_SIZE; else if (strncmp ("o", argv[1], 1) == 0) ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE; else return CMD_WARNING; ri->auth_type = auth_type; return CMD_SUCCESS; } ALIAS (ip_rip_authentication_mode, ip_rip_authentication_mode_authlen_cmd, "ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)", IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n" "MD5 authentication data length\n" "RFC compatible\n" "Old ripd compatible\n") 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->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE; 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") ALIAS (no_ip_rip_authentication_mode, no_ip_rip_authentication_mode_type_authlen_cmd, "no ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)", NO_STR IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n" "MD5 authentication data length\n" "RFC compatible\n" "Old ripd compatible\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") /* CHANGED: ip rip split-horizon Cisco and Zebra's command is ip split-horizon */ DEFUN (ip_rip_split_horizon, ip_rip_split_horizon_cmd, "ip rip split-horizon", IP_STR "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; struct rip_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIP_SPLIT_HORIZON; return CMD_SUCCESS; } DEFUN (ip_rip_split_horizon_poisoned_reverse, ip_rip_split_horizon_poisoned_reverse_cmd, "ip rip split-horizon poisoned-reverse", IP_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") { struct interface *ifp; struct rip_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIP_SPLIT_HORIZON_POISONED_REVERSE; return CMD_SUCCESS; } /* CHANGED: no ip rip split-horizon Cisco and Zebra's command is no ip split-horizon */ DEFUN (no_ip_rip_split_horizon, no_ip_rip_split_horizon_cmd, "no ip rip split-horizon", NO_STR IP_STR "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; struct rip_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIP_NO_SPLIT_HORIZON; return CMD_SUCCESS; } DEFUN (no_ip_rip_split_horizon_poisoned_reverse, no_ip_rip_split_horizon_poisoned_reverse_cmd, "no ip rip split-horizon poisoned-reverse", NO_STR IP_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") { struct interface *ifp; struct rip_interface *ri; ifp = vty->index; ri = ifp->info; switch( ri->split_horizon ) { case RIP_SPLIT_HORIZON_POISONED_REVERSE: ri->split_horizon = RIP_SPLIT_HORIZON; default: break; } return CMD_SUCCESS; } DEFUN (rip_passive_interface, rip_passive_interface_cmd, "passive-interface (IFNAME|default)", "Suppress routing updates on an interface\n" "Interface name\n" "default for all interfaces\n") { const char *ifname = argv[0]; if (!strcmp(ifname,"default")) { passive_default = 1; rip_passive_nondefault_clean(); return CMD_SUCCESS; } if (passive_default) return rip_passive_nondefault_unset (vty, ifname); else return rip_passive_nondefault_set (vty, ifname); } DEFUN (no_rip_passive_interface, no_rip_passive_interface_cmd, "no passive-interface (IFNAME|default)", NO_STR "Suppress routing updates on an interface\n" "Interface name\n" "default for all interfaces\n") { const char *ifname = argv[0]; if (!strcmp(ifname,"default")) { passive_default = 0; rip_passive_nondefault_clean(); return CMD_SUCCESS; } if (passive_default) return rip_passive_nondefault_set (vty, ifname); else return rip_passive_nondefault_unset (vty, ifname); } /* Write rip configuration of each interface. */ static int rip_interface_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct rip_interface *ri; ri = ifp->info; /* Do not display the interface if there is no * configuration about it. **/ if ((!ifp->desc) && (ri->split_horizon == ri->split_horizon_default) && (ri->ri_send == RI_RIP_UNSPEC) && (ri->ri_receive == RI_RIP_UNSPEC) && (ri->auth_type != RIP_AUTH_MD5) && (ri->md5_auth_len != RIP_AUTH_MD5_SIZE) && (!ri->auth_str) && (!ri->key_chain) ) continue; 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) { switch (ri->split_horizon) { case RIP_SPLIT_HORIZON: vty_out (vty, " ip rip split-horizon%s", VTY_NEWLINE); break; case RIP_SPLIT_HORIZON_POISONED_REVERSE: vty_out (vty, " ip rip split-horizon poisoned-reverse%s", VTY_NEWLINE); break; case RIP_NO_SPLIT_HORIZON: default: vty_out (vty, " no ip rip split-horizon%s", VTY_NEWLINE); break; } } /* 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_SIMPLE_PASSWORD) vty_out (vty, " ip rip authentication mode text%s", VTY_NEWLINE); if (ri->auth_type == RIP_AUTH_MD5) { vty_out (vty, " ip rip authentication mode md5"); if (ri->md5_auth_len == RIP_AUTH_MD5_COMPAT_SIZE) vty_out (vty, " auth-length old-ripd"); else vty_out (vty, " auth-length rfc"); vty_out (vty, "%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) { unsigned 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_active (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) { if (passive_default) vty_out (vty, " passive-interface default%s", VTY_NEWLINE); for (i = 0; i < vector_active (Vrip_passive_nondefault); i++) if ((ifname = vector_slot (Vrip_passive_nondefault, i)) != NULL) vty_out (vty, " %spassive-interface %s%s", (passive_default ? "no " : ""), ifname, VTY_NEWLINE); } return 0; } static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1, }; /* Called when interface structure allocated. */ static int rip_interface_new_hook (struct interface *ifp) { ifp->info = rip_interface_new (); return 0; } /* Called when interface structure deleted. */ static int rip_interface_delete_hook (struct interface *ifp) { XFREE (MTYPE_RIP_INTERFACE, ifp->info); ifp->info = NULL; return 0; } /* Allocate and initialize interface vector. */ void rip_if_init (void) { /* Default initial size of interface vector. */ 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_nondefault = vector_init (1); /* Install interface node. */ install_node (&interface_node, rip_interface_config_write); /* Install commands. */ install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_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, &ip_rip_authentication_mode_authlen_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, &no_ip_rip_authentication_mode_type_authlen_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, &ip_rip_split_horizon_cmd); install_element (INTERFACE_NODE, &ip_rip_split_horizon_poisoned_reverse_cmd); install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_cmd); install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_poisoned_reverse_cmd); } quagga-1.2.4/ripd/rip_interface.h000066400000000000000000000025701325323223500167100ustar00rootroot00000000000000/* RIP interface routines * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_RIP_INTERFACE_H #define _QUAGGA_RIP_INTERFACE_H extern int rip_interface_down (int , struct zclient *, zebra_size_t, vrf_id_t); extern int rip_interface_up (int , struct zclient *, zebra_size_t, vrf_id_t); extern int rip_interface_add (int , struct zclient *, zebra_size_t, vrf_id_t); extern int rip_interface_delete (int , struct zclient *, zebra_size_t, vrf_id_t); extern int rip_interface_address_add (int , struct zclient *, zebra_size_t, vrf_id_t); extern int rip_interface_address_delete (int , struct zclient *, zebra_size_t, vrf_id_t); #endif /* _QUAGGA_RIP_INTERFACE_H */ quagga-1.2.4/ripd/rip_main.c000066400000000000000000000157041325323223500156720ustar00rootroot00000000000000/* 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 #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 "privs.h" #include "sigevent.h" #include "zclient.h" #include "vrf.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'}, { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "dryrun", no_argument, NULL, 'C'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { 0 } }; /* ripd privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND }; struct zebra_privs_t ripd_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = 2, .cap_num_i = 0 }; /* Configuration file and directory. */ 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 */ const 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\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -C, --dryrun Check configuration for validity and exit\n\ -r, --retain When program terminates, retain added route by ripd.\n\ -u, --user User to run as\n\ -g, --group Group to run as\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. */ static void sighup (void) { zlog_info ("SIGHUP received"); rip_clean (); rip_reset (); zlog_info ("ripd restarting!"); /* Reload config file. */ vty_read_config (config_file, config_default); /* Create VTY's socket */ vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); /* Try to return to normal operation. */ } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); if (! retain_mode) rip_clean (); exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } static struct quagga_signal_t ripd_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* Main routine of ripd. */ int main (int argc, char **argv) { char *p; int daemon_mode = 0; int dryrun = 0; char *progname; /* 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_RIP, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* Command line option parse. */ while (1) { int opt; opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:rvC", 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 'z': zclient_serv_path_set (optarg); break; case 'P': /* Deal with atoi() returning 0 on failure, and ripd not listening on rip port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = RIP_VTY_PORT; break; case 'r': retain_mode = 1; break; case 'C': dryrun = 1; break; case 'u': ripd_privs.user = optarg; break; case 'g': ripd_privs.group = optarg; 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. */ zprivs_init (&ripd_privs); signal_init (master, array_size(ripd_signals), ripd_signals); cmd_init (1); vty_init (master); memory_init (); keychain_init (); vrf_init (); /* RIP related initialization. */ rip_init (); rip_if_init (); rip_zclient_init (master); rip_peer_init (); /* Get configuration file. */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if(dryrun) return (0); /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("RIPd daemon failed: %s", strerror(errno)); exit (1); } /* Pid file create. */ pid_output (pid_file); /* Create VTY's socket */ vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); /* Print banner. */ zlog_notice ("RIPd %s starting: vty@%d", QUAGGA_VERSION, vty_port); /* Execute each thread. */ thread_main (master); /* Not reached. */ return (0); } quagga-1.2.4/ripd/rip_offset.c000066400000000000000000000252461325323223500162360ustar00rootroot00000000000000/* 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" #include "ripd/ripd.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; static int strcmp_safe (const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) return 0; if (s1 == NULL) return -1; if (s2 == NULL) return 1; return strcmp (s1, s2); } static struct rip_offset_list * rip_offset_list_new (void) { return XCALLOC (MTYPE_RIP_OFFSET_LIST, sizeof (struct rip_offset_list)); } static void rip_offset_list_free (struct rip_offset_list *offset) { XFREE (MTYPE_RIP_OFFSET_LIST, offset); } static struct rip_offset_list * rip_offset_list_lookup (const char *ifname) { struct rip_offset_list *offset; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (rip_offset_list_master, node, nnode, offset)) { if (strcmp_safe (offset->ifname, ifname) == 0) return offset; } return NULL; } static struct rip_offset_list * rip_offset_list_get (const 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; } static int rip_offset_list_set (struct vty *vty, const char *alist, const char *direct_str, const char *metric_str, const 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; } static int rip_offset_list_unset (struct vty *vty, const char *alist, const char *direct_str, const char *metric_str, const 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]); } static int offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2) { return strcmp_safe (o1->ifname, o2->ifname); } static 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 *node, *nnode; struct rip_offset_list *offset; for (ALL_LIST_ELEMENTS (rip_offset_list_master, node, nnode, offset)) { 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; } quagga-1.2.4/ripd/rip_peer.c000066400000000000000000000111441325323223500156730ustar00rootroot00000000000000/* 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; static struct rip_peer * rip_peer_new (void) { return XCALLOC (MTYPE_RIP_PEER, sizeof (struct rip_peer)); } static 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 *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { 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 *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (htonl (peer->addr.s_addr) > htonl (addr->s_addr)) return peer; } return NULL; } /* RIP peer is timeout. */ static 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. */ static 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. */ static 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 *node, *nnode; #define RIP_UPTIME_LEN 25 char timebuf[RIP_UPTIME_LEN]; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { 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); } } static 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 (void) { peer_list = list_new (); peer_list->cmp = (int (*)(void *, void *)) rip_peer_list_cmp; } quagga-1.2.4/ripd/rip_routemap.c000066400000000000000000000665601325323223500166100ustar00rootroot00000000000000/* RIPv2 routemap. * Copyright (C) 2005 6WIND * 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" struct rip_metric_modifier { enum { metric_increment, metric_decrement, metric_absolute } type; u_char metric; }; /* Add rip route map rule. */ static int rip_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete rip route map rule. */ static int rip_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Add rip route map rule. */ static int rip_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: /* rip, ripng and other protocols share the set metric command but only values from 0 to 16 are valid for rip and ripng if metric is out of range for rip and ripng, it is not for other protocols. Do not return an error */ if (strcmp(command, "metric")) { vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } } return CMD_SUCCESS; } /* Delete rip route map rule. */ static int rip_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% RIP Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% RIP Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Hook function for updating route_map assignment. */ /* ARGSUSED */ static void rip_route_map_update (const char *notused) { 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. */ static route_map_result_t route_match_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *metric; u_int32_t check; struct rip_info *rinfo; if (type == RMAP_RIP) { metric = rule; rinfo = object; /* If external metric is available, the route-map should work on this one (for redistribute purpose) */ check = (rinfo->external_metric) ? rinfo->external_metric : rinfo->metric; if (check == *metric) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match metric' match statement. `arg' is METRIC value */ static void * route_match_metric_compile (const 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. */ static 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. */ static 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 || rinfo->ifindex == 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? */ static void * route_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `match interface' value. */ static 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. */ static 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.s_addr) ? rinfo->nexthop : rinfo->from; 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. */ static void * route_match_ip_next_hop_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `. */ static void route_match_ip_next_hop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip next-hop matching. */ static 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' */ static 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.s_addr) ? rinfo->nexthop : rinfo->from; 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; } static void * route_match_ip_next_hop_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_next_hop_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static 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. */ static 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. */ static void * route_match_ip_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_address_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ static 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' */ static 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; } static void * route_match_ip_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_address_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static 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 tag TAG' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; struct rip_info *rinfo; if (type == RMAP_RIP) { tag = rule; rinfo = object; /* The information stored by rinfo is host ordered. */ if (rinfo->tag == *tag) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map commands for tag matching. */ static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_map_rule_tag_compile, route_map_rule_tag_free, }; /* `set metric METRIC' */ /* Set metric to attribute. */ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { if (type == RMAP_RIP) { struct rip_metric_modifier *mod; struct rip_info *rinfo; mod = rule; rinfo = object; if (mod->type == metric_increment) rinfo->metric_out += mod->metric; else if (mod->type == metric_decrement) rinfo->metric_out -= mod->metric; else if (mod->type == metric_absolute) rinfo->metric_out = mod->metric; if ((signed int)rinfo->metric_out < 1) rinfo->metric_out = 1; if (rinfo->metric_out > RIP_METRIC_INFINITY) rinfo->metric_out = RIP_METRIC_INFINITY; rinfo->metric_set = 1; } return RMAP_OKAY; } /* set metric compilation. */ static void * route_set_metric_compile (const char *arg) { int len; const 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; if (metric < 0 || metric > RIP_METRIC_INFINITY) return NULL; mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rip_metric_modifier)); mod->type = type; mod->metric = metric; return mod; } /* Free route map's compiled `set metric' value. */ static void route_set_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set metric rule structure. */ static 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. */ static 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. */ static void * route_set_ip_nexthop_compile (const 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. */ static void route_set_ip_nexthop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip nexthop set. */ static 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 tag TAG' */ /* Set tag to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; struct rip_info *rinfo; if(type == RMAP_RIP) { /* Fetch routemap's rule information. */ tag = rule; rinfo = object; /* Set next hop value. */ rinfo->tag_out = *tag; } return RMAP_OKAY; } /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, route_map_rule_tag_compile, route_map_rule_tag_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") DEFUN (match_tag, match_tag_cmd, "match tag <1-4294967295>", MATCH_STR "Match tag of route\n" "Metric value\n") { return rip_route_match_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_match_tag, no_match_tag_cmd, "no match tag", NO_STR MATCH_STR "Match tag of route\n") { if (argc == 0) return rip_route_match_delete (vty, vty->index, "tag", NULL); return rip_route_match_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_match_tag, no_match_tag_val_cmd, "no match tag <1-4294967295>", NO_STR MATCH_STR "Match tag of route\n" "Metric value\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]); } ALIAS (set_metric, set_metric_addsub_cmd, "set metric <+/-metric>", SET_STR "Metric value for destination routing protocol\n" "Add or subtract 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 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") ALIAS (no_set_metric, no_set_metric_addsub_cmd, "no set metric <+/-metric>", NO_STR SET_STR "Metric value for destination routing protocol\n" "Add or subtract metric\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") DEFUN (set_tag, set_tag_cmd, "set tag <1-4294967295>", SET_STR "Tag value for routing protocol\n" "Tag value\n") { return rip_route_set_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_set_tag, no_set_tag_cmd, "no set tag", NO_STR SET_STR "Tag value for routing protocol\n") { if (argc == 0) return rip_route_set_delete (vty, vty->index, "tag", NULL); return rip_route_set_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_set_tag, no_set_tag_val_cmd, "no set tag <1-4294967295>", NO_STR SET_STR "Tag value for routing protocol\n" "Tag value\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_match (&route_match_tag_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_ip_nexthop_cmd); route_map_install_set (&route_set_tag_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, &match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_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, &no_set_metric_addsub_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); install_element (RMAP_NODE, &set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_val_cmd); } quagga-1.2.4/ripd/rip_snmp.c000066400000000000000000000351451325323223500157240ustar00rootroot00000000000000/* 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 #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 /* 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 }; /* Interface cache table sorted by interface's address. */ struct route_table *rip_ifaddr_table; /* Hook functions. */ static u_char *rip2Globals (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2IfStatEntry (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2IfConfAddress (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2PeerTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); 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, STRING, 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}} }; extern struct thread_master *master; 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); } } static 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 == (int)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 < (int)sizeof (struct in_addr) + 1) || (peer->domain > (int)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; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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_send == RIPv2) return ripVersion2; else if (rip->version_send == RIPv1) return ripVersion1; } return doNotSend; } static long rip2IfConfReceive (struct rip_interface *ri) { #define rip1 1 #define rip2 2 #define rip1OrRip2 3 #define doNotReceive 4 int recvv; if (! ri->running) return doNotReceive; recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv : ri->ri_receive; if (recvv == RI_RIP_VERSION_1_AND_2) return rip1OrRip2; else if (recvv & RIPv2) return rip2; else if (recvv & RIPv1) return rip1; 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; if (smux_header_table(v, name, length, exact, val_len, write_method) == MATCH_FAILED) return NULL; 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 domain = 0; static int version; /* static time_t uptime; */ struct rip_peer *peer; if (smux_header_table(v, name, length, exact, val_len, write_method) == MATCH_FAILED) return NULL; 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 = 2; return (u_char *) &domain; case RIP2PEERLASTUPDATE: #if 0 /* We don't know the SNMP agent startup time. We have two choices here: * - assume ripd startup time equals SNMP agent startup time * - don't support this variable, at all * Currently, we do the latter... */ *val_len = sizeof (time_t); uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */ return (u_char *) &uptime; #else return (u_char *) NULL; #endif 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 (master); REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid); } #endif /* HAVE_SNMP */ quagga-1.2.4/ripd/rip_zebra.c000066400000000000000000000467461325323223500160630ustar00rootroot00000000000000/* 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 "table.h" #include "stream.h" #include "memory.h" #include "routemap.h" #include "zclient.h" #include "log.h" #include "vrf.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" /* All information about zebra. */ struct zclient *zclient = NULL; /* Send ECMP routes to zebra. */ static void rip_zebra_ipv4_send (struct route_node *rp, u_char cmd) { static struct in_addr **nexthops = NULL; static unsigned int nexthops_len = 0; struct list *list = (struct list *)rp->info; struct zapi_ipv4 api; struct listnode *listnode = NULL; struct rip_info *rinfo = NULL; int count = 0; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_RIP], VRF_DEFAULT)) { api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_RIP; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; if (nexthops_len < listcount (list)) { nexthops_len = listcount (list); nexthops = XREALLOC (MTYPE_TMP, nexthops, nexthops_len * sizeof (struct in_addr *)); } SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { nexthops[count++] = &rinfo->nexthop; if (cmd == ZEBRA_IPV4_ROUTE_ADD) SET_FLAG (rinfo->flags, RIP_RTF_FIB); else UNSET_FLAG (rinfo->flags, RIP_RTF_FIB); } api.nexthop = nexthops; api.nexthop_num = count; api.ifindex_num = 0; rinfo = listgetdata (listhead (list)); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = rinfo->metric; if (rinfo->distance && rinfo->distance != ZEBRA_RIP_DISTANCE_DEFAULT) { SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = rinfo->distance; } if (rinfo->tag) { SET_FLAG (api.message, ZAPI_MESSAGE_TAG); api.tag = rinfo->tag; } zapi_ipv4_route (cmd, zclient, (struct prefix_ipv4 *)&rp->p, &api); if (IS_RIP_DEBUG_ZEBRA) { if (rip->ecmp) zlog_debug ("%s: %s/%d nexthops %d", (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ "Install into zebra" : "Delete from zebra", inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen, count); else zlog_debug ("%s: %s/%d", (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ "Install into zebra" : "Delete from zebra", inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); } rip_global_route_changes++; } } /* Add/update ECMP routes to zebra. */ void rip_zebra_ipv4_add (struct route_node *rp) { rip_zebra_ipv4_send (rp, ZEBRA_IPV4_ROUTE_ADD); } /* Delete ECMP routes from zebra. */ void rip_zebra_ipv4_delete (struct route_node *rp) { rip_zebra_ipv4_send (rp, ZEBRA_IPV4_ROUTE_DELETE); } /* Zebra route add and delete treatment. */ static int rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; unsigned char plength = 0; 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; plength = stream_getc (s); p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength); 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); else api.distance = 255; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) api.tag = stream_getl (s); else api.tag = 0; /* Then fetch IPv4 prefixes. */ if (command == ZEBRA_IPV4_ROUTE_ADD) rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop, api.metric, api.distance, api.tag); else rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex); return 0; } void rip_zclient_reset (void) { zclient_reset (zclient); } /* RIP route-map set for redistribution */ static void rip_routemap_set (int type, const 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); } static void rip_redistribute_metric_set (int type, unsigned int metric) { rip->route_map[type].metric_config = 1; rip->route_map[type].metric = metric; } static int rip_metric_unset (int type, unsigned 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 */ static int rip_routemap_unset (int type, const 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; const 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, 2, "bgp"}, {ZEBRA_ROUTE_BABEL, 2, "babel"}, {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; } #if 0 static int rip_redistribute_set (int type) { if (vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_SUCCESS; vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } #endif static int rip_redistribute_unset (int type) { if (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_SUCCESS; vrf_bitmap_unset (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT); /* Remove the routes from RIP table. */ rip_redistribute_withdraw (type); return CMD_SUCCESS; } int rip_redistribute_check (int type) { return vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT); } void rip_redistribute_clean (void) { int i; for (i = 0; redist_type[i].str; i++) { if (vrf_bitmap_check (zclient->redist[redist_type[i].type], VRF_DEFAULT)) { if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, redist_type[i].type, VRF_DEFAULT); vrf_bitmap_unset (zclient->redist[redist_type[i].type], VRF_DEFAULT); /* 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") { vrf_bitmap_set (zclient->redist[ZEBRA_ROUTE_RIP], VRF_DEFAULT); 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") { vrf_bitmap_unset (zclient->redist[ZEBRA_ROUTE_RIP], VRF_DEFAULT); return CMD_SUCCESS; } DEFUN (rip_redistribute_type, rip_redistribute_type_cmd, "redistribute " QUAGGA_REDIST_STR_RIPD, REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD) { 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 (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type, VRF_DEFAULT); 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 " QUAGGA_REDIST_STR_RIPD, NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD) { 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 " QUAGGA_REDIST_STR_RIPD " route-map WORD", REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "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 (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type, VRF_DEFAULT); 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 " QUAGGA_REDIST_STR_RIPD " route-map WORD", NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "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 " QUAGGA_REDIST_STR_RIPD " metric <0-16>", REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "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 (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type, VRF_DEFAULT); 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 " QUAGGA_REDIST_STR_RIPD " metric <0-16>", NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "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 (rip_redistribute_type_metric_routemap, rip_redistribute_type_metric_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_RIPD " metric <0-16> route-map WORD", REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\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); rip_routemap_set (redist_type[i].type, argv[2]); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type, VRF_DEFAULT); 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 " QUAGGA_REDIST_STR_RIPD " metric <0-16> route-map WORD", NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "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_DEFAULT, &p, 0, NULL, 0, 0, 0); } 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_DEFAULT, &p, 0); } return CMD_SUCCESS; } /* RIP configuration write function. */ static int config_write_zebra (struct vty *vty) { if (! zclient->enable) { vty_out (vty, "no router zebra%s", VTY_NEWLINE); return 1; } else if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_RIP], VRF_DEFAULT)) { 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; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && vrf_bitmap_check (zclient->redist[i], VRF_DEFAULT)) { 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", zebra_route_string(i), rip->route_map[i].metric, rip->route_map[i].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s metric %d%s", zebra_route_string(i), rip->route_map[i].metric, VTY_NEWLINE); } else { if (rip->route_map[i].name) vty_out (vty, " redistribute %s route-map %s%s", zebra_route_string(i), rip->route_map[i].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s%s", zebra_route_string(i), VTY_NEWLINE); } } else vty_out (vty, " %s", zebra_route_string(i)); } return 0; } /* Zebra node structure. */ static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# ", }; static void rip_zebra_connected (struct zclient *zclient) { zclient_send_requests (zclient, VRF_DEFAULT); } void rip_zclient_init (struct thread_master *master) { /* Set default value to the zebra client structure. */ zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_RIP); zclient->zebra_connected = rip_zebra_connected; 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, &rip_redistribute_type_metric_routemap_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); } quagga-1.2.4/ripd/ripd.c000066400000000000000000003370321325323223500150330ustar00rootroot00000000000000/* RIP version 1 and 2. * Copyright (C) 2005 6WIND * 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 "sockopt.h" #include "routemap.h" #include "if_rmap.h" #include "plist.h" #include "distribute.h" #include "md5.h" #include "keychain.h" #include "privs.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" /* UDP receive buffer size */ #define RIP_UDP_RCV_BUF 41600 /* privileges global */ extern struct zebra_privs_t ripd_privs; /* 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. */ static void rip_event (enum rip_event, int); static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char); static int rip_triggered_update (struct thread *); static int rip_update_jitter (unsigned long); /* RIP output routes type. */ enum { rip_all_route, rip_changed_route }; /* RIP command strings. */ static const 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}, }; /* Utility function to set boradcast option to the socket. */ static 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", sock); return -1; } return 0; } static int rip_route_rte (struct rip_info *rinfo) { return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE); } static struct rip_info * rip_info_new (void) { return XCALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info)); } void rip_info_free (struct rip_info *rinfo) { XFREE (MTYPE_RIP_INFO, rinfo); } /* RIP route garbage collect timer. */ static 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. */ listnode_delete (rp->info, rinfo); if (list_isempty ((struct list *)rp->info)) { list_free (rp->info); rp->info = NULL; route_unlock_node (rp); } /* Free RIP routing information. */ rip_info_free (rinfo); return 0; } static void rip_timeout_update (struct rip_info *rinfo); /* Add new route to the ECMP list. * RETURN: the new entry added in the list, or NULL if it is not the first * entry and ECMP is not allowed. */ struct rip_info * rip_ecmp_add (struct rip_info *rinfo_new) { struct route_node *rp = rinfo_new->rp; struct rip_info *rinfo = NULL; struct list *list = NULL; if (rp->info == NULL) rp->info = list_new (); list = (struct list *)rp->info; /* If ECMP is not allowed and some entry already exists in the list, * do nothing. */ if (listcount (list) && !rip->ecmp) return NULL; rinfo = rip_info_new (); memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); listnode_add (list, rinfo); if (rip_route_rte (rinfo)) { rip_timeout_update (rinfo); rip_zebra_ipv4_add (rp); } /* Set the route change flag on the first entry. */ rinfo = listgetdata (listhead (list)); SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* Signal the output process to trigger an update (see section 2.5). */ rip_event (RIP_TRIGGERED_UPDATE, 0); return rinfo; } /* Replace the ECMP list with the new route. * RETURN: the new entry added in the list */ struct rip_info * rip_ecmp_replace (struct rip_info *rinfo_new) { struct route_node *rp = rinfo_new->rp; struct list *list = (struct list *)rp->info; struct rip_info *rinfo = NULL, *tmp_rinfo = NULL; struct listnode *node = NULL, *nextnode = NULL; if (list == NULL || listcount (list) == 0) return rip_ecmp_add (rinfo_new); /* Get the first entry */ rinfo = listgetdata (listhead (list)); /* Learnt route replaced by a local one. Delete it from zebra. */ if (rip_route_rte (rinfo) && !rip_route_rte (rinfo_new)) if (CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) rip_zebra_ipv4_delete (rp); /* Re-use the first entry, and delete the others. */ for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) if (tmp_rinfo != rinfo) { RIP_TIMER_OFF (tmp_rinfo->t_timeout); RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); list_delete_node (list, node); rip_info_free (tmp_rinfo); } RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); if (rip_route_rte (rinfo)) { rip_timeout_update (rinfo); /* The ADD message implies an update. */ rip_zebra_ipv4_add (rp); } /* Set the route change flag. */ SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* Signal the output process to trigger an update (see section 2.5). */ rip_event (RIP_TRIGGERED_UPDATE, 0); return rinfo; } /* Delete one route from the ECMP list. * RETURN: * null - the entry is freed, and other entries exist in the list * the entry - the entry is the last one in the list; its metric is set * to INFINITY, and the garbage collector is started for it */ struct rip_info * rip_ecmp_delete (struct rip_info *rinfo) { struct route_node *rp = rinfo->rp; struct list *list = (struct list *)rp->info; RIP_TIMER_OFF (rinfo->t_timeout); if (listcount (list) > 1) { /* Some other ECMP entries still exist. Just delete this entry. */ RIP_TIMER_OFF (rinfo->t_garbage_collect); listnode_delete (list, rinfo); if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) /* The ADD message implies the update. */ rip_zebra_ipv4_add (rp); rip_info_free (rinfo); rinfo = NULL; } else { assert (rinfo == listgetdata (listhead (list))); /* This is the only entry left in the list. We must keep it in * the list for garbage collection time, with INFINITY metric. */ rinfo->metric = RIP_METRIC_INFINITY; RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) rip_zebra_ipv4_delete (rp); } /* Set the route change flag on the first entry. */ rinfo = listgetdata (listhead (list)); SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* Signal the output process to trigger an update (see section 2.5). */ rip_event (RIP_TRIGGERED_UPDATE, 0); return rinfo; } /* Timeout RIP routes. */ static int rip_timeout (struct thread *t) { rip_ecmp_delete ((struct rip_info *)THREAD_ARG (t)); return 0; } static 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); } } static int rip_filter (int rip_distribute, struct prefix_ipv4 *p, struct rip_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; int distribute = rip_distribute == RIP_FILTER_OUT ? DISTRIBUTE_V4_OUT : DISTRIBUTE_V4_IN; const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in"; /* Input distribute-list filtering. */ if (ri->list[rip_distribute]) { if (access_list_apply (ri->list[rip_distribute], (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute %s", inet_ntoa (p->prefix), p->prefixlen, inout); return -1; } } if (ri->prefix[rip_distribute]) { if (prefix_list_apply (ri->prefix[rip_distribute], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list %s", inet_ntoa (p->prefix), p->prefixlen, inout); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[distribute]) { alist = access_list_lookup (AFI_IP, dist->list[distribute]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute %s", inet_ntoa (p->prefix), p->prefixlen, inout); return -1; } } } if (dist->prefix[distribute]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[distribute]); if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list %s", inet_ntoa (p->prefix), p->prefixlen, inout); return -1; } } } } return 0; } /* Check nexthop address validity. */ static int rip_nexthop_check (struct in_addr *addr) { struct listnode *node; struct listnode *cnode; struct interface *ifp; struct connected *ifc; struct prefix *p; /* If nexthop address matches local configured address then it is invalid nexthop. */ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc)) { 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. */ static 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 = NULL, newinfo; struct rip_interface *ri; struct in_addr *nexthop; int same = 0; unsigned char old_dist, new_dist; struct list *list = NULL; struct listnode *node = NULL; /* 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_filter (RIP_FILTER_IN, &p, ri); if (ret < 0) return; memset (&newinfo, 0, sizeof (newinfo)); newinfo.type = ZEBRA_ROUTE_RIP; newinfo.sub_type = RIP_ROUTE_RTE; newinfo.nexthop = rte->nexthop; newinfo.from = from->sin_addr; newinfo.ifindex = ifp->ifindex; newinfo.metric = rte->metric; newinfo.metric_out = rte->metric; /* XXX */ newinfo.tag = ntohs (rte->tag); /* XXX */ /* Modify entry according to the interface routemap. */ if (ri->routemap[RIP_FILTER_IN]) { int ret; /* The object should be of the type of rip_info */ ret = route_map_apply (ri->routemap[RIP_FILTER_IN], (struct prefix *) &p, RMAP_RIP, &newinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIP %s/%d is filtered by route-map in", inet_ntoa (p.prefix), p.prefixlen); return; } /* Get back the object */ rte->nexthop = newinfo.nexthop_out; rte->tag = htons (newinfo.tag_out); /* XXX */ rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */ } /* 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 ? ifp->metric : 1; 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 if nexthop address is myself, then do nothing. */ if (rip_nexthop_check (nexthop) < 0) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop)); return; } /* Get index for the prefix. */ rp = route_node_get (rip->table, (struct prefix *) &p); newinfo.rp = rp; newinfo.nexthop = *nexthop; newinfo.metric = rte->metric; newinfo.tag = ntohs (rte->tag); newinfo.distance = rip_distance_apply (&newinfo); new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT; /* Check to see whether there is already RIP route on the table. */ if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) { /* Need to compare with redistributed entry or local entry */ if (!rip_route_rte (rinfo)) break; if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) && IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) break; if (!listnextnode (node)) { /* Not found in the list */ if (rte->metric > rinfo->metric) { /* New route has a greater metric. Discard it. */ route_unlock_node (rp); return; } if (rte->metric < rinfo->metric) /* New route has a smaller metric. Replace the ECMP list * with the new one in below. */ break; /* Metrics are same. We compare the distances. */ old_dist = rinfo->distance ? \ rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; if (new_dist > old_dist) { /* New route has a greater distance. Discard it. */ route_unlock_node (rp); return; } if (new_dist < old_dist) /* New route has a smaller distance. Replace the ECMP list * with the new one in below. */ break; /* Metrics and distances are both same. Keep "rinfo" null and * the new route is added in the ECMP list in below. */ } } if (rinfo) { /* Local static route. */ if (rinfo->type == ZEBRA_ROUTE_RIP && ((rinfo->sub_type == RIP_ROUTE_STATIC) || (rinfo->sub_type == RIP_ROUTE_DEFAULT)) && rinfo->metric != RIP_METRIC_INFINITY) { route_unlock_node (rp); return; } /* Redistributed route check. */ if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->metric != RIP_METRIC_INFINITY) { old_dist = rinfo->distance; /* Only routes directly connected to an interface (nexthop == 0) * may have a valid NULL distance */ if (rinfo->nexthop.s_addr != 0) old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT; /* If imported route does not have STRICT precedence, mark it as a ghost */ if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY) rip_ecmp_replace (&newinfo); route_unlock_node (rp); return; } } if (!rinfo) { if (rp->info) route_unlock_node (rp); /* 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) rip_ecmp_add (&newinfo); } else { /* Route is there but we are not sure the route is RIP or not. */ /* 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) && (rinfo->ifindex == ifp->ifindex)); old_dist = rinfo->distance ? \ rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; /* 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, or if the tag has been changed; or if there is a route with a lower administrave distance; or an update of the distance on the actual route; do the following actions: */ if ((same && rinfo->metric != rte->metric) || (rte->metric < rinfo->metric) || ((same) && (rinfo->metric == rte->metric) && (newinfo.tag != rinfo->tag)) || (old_dist > new_dist) || ((old_dist != new_dist) && same)) { if (listcount (list) == 1) { if (newinfo.metric != RIP_METRIC_INFINITY) rip_ecmp_replace (&newinfo); else rip_ecmp_delete (rinfo); } else { if (newinfo.metric < rinfo->metric) rip_ecmp_replace (&newinfo); else if (newinfo.metric > rinfo->metric) rip_ecmp_delete (rinfo); else if (new_dist < old_dist) rip_ecmp_replace (&newinfo); else if (new_dist > old_dist) rip_ecmp_delete (rinfo); else { int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0; assert (newinfo.metric != RIP_METRIC_INFINITY); RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); memcpy (rinfo, &newinfo, sizeof (struct rip_info)); rip_timeout_update (rinfo); if (update) rip_zebra_ipv4_add (rp); /* - Set the route change flag on the first entry. */ rinfo = listgetdata (listhead (list)); SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); rip_event (RIP_TRIGGERED_UPDATE, 0); } } } else /* same & no change */ rip_timeout_update (rinfo); /* Unlock tempolary lock of the route. */ route_unlock_node (rp); } } /* Dump RIP packet */ static void rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv) { caddr_t lim; struct rte *rte; const 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_debug ("%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 (rte->family == htons (RIP_FAMILY_AUTH)) { if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD)) { p = (u_char *)&rte->prefix; zlog_debug (" family 0x%X type %d auth string: %s", ntohs (rte->family), ntohs (rte->tag), p); } else if (rte->tag == htons (RIP_AUTH_MD5)) { struct rip_md5_info *md5; md5 = (struct rip_md5_info *) &packet->rte; zlog_debug (" family 0x%X type %d (MD5 authentication)", ntohs (md5->family), ntohs (md5->type)); zlog_debug (" RIP-2 packet len %d Key ID %d" " Auth Data len %d", ntohs (md5->packet_len), md5->keyid, md5->auth_len); zlog_debug (" Sequence Number %ld", (u_long) ntohl (md5->sequence)); } else if (rte->tag == htons (RIP_AUTH_DATA)) { p = (u_char *)&rte->prefix; zlog_debug (" family 0x%X type %d (MD5 data)", ntohs (rte->family), ntohs (rte->tag)); zlog_debug (" MD5: %02X%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[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); } else { zlog_debug (" family 0x%X type %d (Unknown auth type)", ntohs (rte->family), ntohs (rte->tag)); } } else zlog_debug (" %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_debug (" %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. */ static 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. */ static 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_debug ("RIPv2 simple password authentication from %s", inet_ntoa (from->sin_addr)); ri = ifp->info; if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD || rte->tag != htons(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. */ static int rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from, int length, struct interface *ifp) { struct rip_interface *ri; struct rip_md5_info *md5; struct rip_md5_data *md5data; struct keychain *keychain; struct key *key; MD5_CTX ctx; u_char digest[RIP_AUTH_MD5_SIZE]; u_int16_t packet_len; char auth_str[RIP_AUTH_MD5_SIZE]; if (IS_RIP_DEBUG_EVENT) zlog_debug ("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 || md5->type != htons(RIP_AUTH_MD5)) return 0; /* If the authentication length is less than 16, then it must be wrong for * any interpretation of rfc2082. Some implementations also interpret * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE. */ if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE) || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE))) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("RIPv2 MD5 authentication, strange authentication " "length field %d", md5->auth_len); return 0; } /* grab and verify check packet length */ packet_len = ntohs (md5->packet_len); if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("RIPv2 MD5 authentication, packet length field %d " "greater than received length %d!", md5->packet_len, length); return 0; } /* retrieve authentication data */ md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len); memset (auth_str, 0, RIP_AUTH_MD5_SIZE); 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; strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE); } else if (ri->auth_str) strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE); if (auth_str[0] == 0) return 0; /* MD5 digest authentication. */ memset (&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE); MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); MD5Final(digest, &ctx); if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0) return packet_len; else return 0; } /* Pick correct auth string for sends, prepare auth_str buffer for use. * (left justified and padded). * * presumes one of ri or key is valid, and that the auth strings they point * to are nul terminated. If neither are present, auth_str will be fully * zero padded. * */ static void rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key, char *auth_str, int len) { assert (ri || key); memset (auth_str, 0, len); if (key && key->string) strncpy (auth_str, key->string, len); else if (ri->auth_str) strncpy (auth_str, ri->auth_str, len); return; } /* Write RIPv2 simple password authentication information * * auth_str is presumed to be 2 bytes and correctly prepared * (left justified and zero padded). */ static void rip_auth_simple_write (struct stream *s, char *auth_str, int len) { assert (s && len == RIP_AUTH_SIMPLE_SIZE); stream_putw (s, RIP_FAMILY_AUTH); stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE); return; } /* write RIPv2 MD5 "authentication header" * (uses the auth key data field) * * Digest offset field is set to 0. * * returns: offset of the digest offset field, which must be set when * length to the auth-data MD5 digest is known. */ static size_t rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri, struct key *key) { size_t doff = 0; assert (s && ri && ri->auth_type == RIP_AUTH_MD5); /* MD5 authentication. */ stream_putw (s, RIP_FAMILY_AUTH); stream_putw (s, RIP_AUTH_MD5); /* MD5 AH digest offset field. * * Set to placeholder value here, to true value when RIP-2 Packet length * is known. Actual value is set in .....(). */ doff = stream_get_endp(s); stream_putw (s, 0); /* Key ID. */ if (key) stream_putc (s, key->index % 256); else stream_putc (s, 1); /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this * to be configurable. */ stream_putc (s, ri->md5_auth_len); /* 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); return doff; } /* If authentication is in used, write the appropriate header * returns stream offset to which length must later be written * or 0 if this is not required */ static size_t rip_auth_header_write (struct stream *s, struct rip_interface *ri, struct key *key, char *auth_str, int len) { assert (ri->auth_type != RIP_NO_AUTH); switch (ri->auth_type) { case RIP_AUTH_SIMPLE_PASSWORD: rip_auth_prepare_str_send (ri, key, auth_str, len); rip_auth_simple_write (s, auth_str, len); return 0; case RIP_AUTH_MD5: return rip_auth_md5_ah_write (s, ri, key); } assert (1); return 0; } /* Write RIPv2 MD5 authentication data trailer */ static void rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff, char *auth_str, int authlen) { unsigned long len; MD5_CTX ctx; unsigned char digest[RIP_AUTH_MD5_SIZE]; /* Make it sure this interface is configured as MD5 authentication. */ assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE)); assert (doff > 0); /* Get packet length. */ len = stream_get_endp(s); /* 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; } /* Set the digest offset length in the header */ stream_putw_at (s, doff, len); /* Set authentication data. */ stream_putw (s, RIP_FAMILY_AUTH); stream_putw (s, RIP_AUTH_DATA); /* Generate a digest for the RIP packet. */ memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s)); MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); MD5Final(digest, &ctx); /* Copy the digest to the packet. */ stream_write (s, digest, RIP_AUTH_MD5_SIZE); } /* RIP routing information. */ static void rip_response_process (struct rip_packet *packet, int size, struct sockaddr_in *from, struct connected *ifc) { caddr_t lim; struct rte *rte; struct prefix_ipv4 ifaddr; struct prefix_ipv4 ifaddrclass; int subnetted; memset(&ifaddr, 0, sizeof(ifaddr)); /* We don't know yet. */ subnetted = -1; /* The Response must be ignored if it is not from the RIP port. (RFC2453 - Sec. 3.9.2)*/ if (from->sin_port != htons(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 (RFC2453 - Sec. 3.9.2) */ if (if_lookup_address(from->sin_addr) == NULL) { 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 == htons(RIP_FAMILY_AUTH)) continue; if (rte->family != htons(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_debug ("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_debug ("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_debug ("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; if (subnetted == -1) { memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4)); memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4)); apply_classful_mask_ipv4 (&ifaddrclass); subnetted = 0; if (ifaddr.prefixlen > ifaddrclass.prefixlen) subnetted = 1; } destination = ntohl (rte->prefix.s_addr); if (IN_CLASSA (destination)) masklen2ip (8, &rte->mask); else if (IN_CLASSB (destination)) masklen2ip (16, &rte->mask); else if (IN_CLASSC (destination)) masklen2ip (24, &rte->mask); if (subnetted == 1) masklen2ip (ifaddrclass.prefixlen, (struct in_addr *) &destination); if ((subnetted == 1) && ((rte->prefix.s_addr & destination) == ifaddrclass.prefix.s_addr)) { masklen2ip (ifaddr.prefixlen, &rte->mask); if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) masklen2ip (32, &rte->mask); if (IS_RIP_DEBUG_EVENT) zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix)); } else { if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) continue; } if (IS_RIP_DEBUG_EVENT) { zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix)); zlog_debug ("Resultant mask %s", inet_ntoa (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 sanity check */ if (packet->version == RIPv2 && (rte->mask.s_addr == 0) && (rte->prefix.s_addr != 0)) { if (IS_RIP_DEBUG_EVENT) zlog_warn ("Malformed route, zero netmask " "with non-zero addr - dropping route!"); rip_peer_bad_route (from); continue; } /* Routing table updates. */ rip_rte_process (rte, from, ifc->ifp); } } /* Make socket for RIP protocol. */ static int rip_create_socket (struct sockaddr_in *from) { int ret; int sock; struct sockaddr_in addr; memset (&addr, 0, sizeof (struct sockaddr_in)); if (!from) { addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ } else { memcpy(&addr, from, sizeof(addr)); } /* sending port must always be the RIP port */ addr.sin_port = htons (RIP_PORT_DEFAULT); /* Make datagram socket. */ sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { zlog_err("Cannot create UDP socket: %s", safe_strerror(errno)); exit (1); } sockopt_broadcast (sock); sockopt_reuseaddr (sock); sockopt_reuseport (sock); #ifdef RIP_RECVMSG setsockopt_pktinfo (sock); #endif /* RIP_RECVMSG */ #ifdef IPTOS_PREC_INTERNETCONTROL setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); #endif if (ripd_privs.change (ZPRIVS_RAISE)) zlog_err ("rip_create_socket: could not raise privs"); setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF); if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0) { int save_errno = errno; if (ripd_privs.change (ZPRIVS_LOWER)) zlog_err ("rip_create_socket: could not lower privs"); zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__, sock, inet_ntoa(addr.sin_addr), (int) ntohs(addr.sin_port), safe_strerror(save_errno)); close (sock); return ret; } if (ripd_privs.change (ZPRIVS_LOWER)) zlog_err ("rip_create_socket: could not lower privs"); return sock; } /* RIP packet send to destination address, on interface denoted by * by connected argument. NULL to argument denotes destination should be * should be RIP multicast group */ static int rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, struct connected *ifc) { int ret, send_sock; struct sockaddr_in sin; assert (ifc != NULL); if (IS_RIP_DEBUG_PACKET) { #define ADDRESS_SIZE 20 char dst[ADDRESS_SIZE]; dst[ADDRESS_SIZE - 1] = '\0'; if (to) { strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1); } else { sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1); } #undef ADDRESS_SIZE zlog_debug("rip_send_packet %s > %s (%s)", inet_ntoa(ifc->address->u.prefix4), dst, ifc->ifp->name); } if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) ) { /* * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured * with multiple addresses on the same subnet: the first address * on the subnet is configured "primary", and all subsequent addresses * on that subnet are treated as "secondary" addresses. * In order to avoid routing-table bloat on other rip listeners, * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs. * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY * flag is set, we would end up sending a packet for a "secondary" * source address on non-linux systems. */ if (IS_RIP_DEBUG_PACKET) zlog_debug("duplicate dropped"); return 0; } /* Make destination address. */ memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* When destination is specified, use it's port and address. */ if (to) { sin.sin_port = to->sin_port; sin.sin_addr = to->sin_addr; send_sock = rip->sock; } else { struct sockaddr_in from; sin.sin_port = htons (RIP_PORT_DEFAULT); sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); /* multicast send should bind to local interface address */ memset (&from, 0, sizeof (from)); from.sin_family = AF_INET; from.sin_port = htons (RIP_PORT_DEFAULT); from.sin_addr = ifc->address->u.prefix4; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN from.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* * we have to open a new socket for each packet because this * is the most portable way to bind to a different source * ipv4 address for each packet. */ if ( (send_sock = rip_create_socket (&from)) < 0) { zlog_warn("rip_send_packet could not create socket."); return -1; } rip_interface_multicast_set (send_sock, ifc); } ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); if (IS_RIP_DEBUG_EVENT) zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr), ntohs (sin.sin_port)); if (ret < 0) zlog_warn ("can't send packet : %s", safe_strerror (errno)); if (!to) close(send_sock); return ret; } /* Add redistributed route to RIP table. */ void rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, ifindex_t ifindex, struct in_addr *nexthop, unsigned int metric, unsigned char distance, route_tag_t tag) { int ret; struct route_node *rp = NULL; struct rip_info *rinfo = NULL, newinfo; struct list *list = NULL; /* Redistribute route */ ret = rip_destination_check (p->prefix); if (! ret) return; rp = route_node_get (rip->table, (struct prefix *) p); memset (&newinfo, 0, sizeof (struct rip_info)); newinfo.type = type; newinfo.sub_type = sub_type; newinfo.ifindex = ifindex; newinfo.metric = 1; newinfo.external_metric = metric; newinfo.distance = distance; if (tag <= UINT16_MAX) /* RIP only supports 16 bit tags */ newinfo.tag = tag; newinfo.rp = rp; if (nexthop) newinfo.nexthop = *nexthop; if ((list = rp->info) != NULL && listcount (list) != 0) { rinfo = listgetdata (listhead (list)); 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) || (rinfo->sub_type == RIP_ROUTE_DEFAULT)) ) { if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) && (sub_type != RIP_ROUTE_DEFAULT))) { route_unlock_node (rp); return; } } rinfo = rip_ecmp_replace (&newinfo); route_unlock_node (rp); } else rinfo = rip_ecmp_add (&newinfo); if (IS_RIP_DEBUG_EVENT) { if (!nexthop) zlog_debug ("Redistribute new prefix %s/%d on the interface %s", inet_ntoa(p->prefix), p->prefixlen, ifindex2ifname(ifindex)); else zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s", inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop), ifindex2ifname(ifindex)); } 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, ifindex_t 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) { struct list *list = rp->info; if (list != NULL && listcount (list) != 0) { rinfo = listgetdata (listhead (list)); 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; if (IS_RIP_DEBUG_EVENT) zlog_debug ("Poisone %s/%d on the interface %s with an " "infinity metric [delete]", inet_ntoa(p->prefix), p->prefixlen, ifindex2ifname(ifindex)); rip_event (RIP_TRIGGERED_UPDATE, 0); } } route_unlock_node (rp); } } /* Response to request called from rip_read ().*/ static void rip_request_process (struct rip_packet *packet, int size, struct sockaddr_in *from, struct connected *ifc) { caddr_t lim; struct rte *rte; struct prefix_ipv4 p; struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri; /* Does not reponse to the requests on the loopback interfaces */ if (if_is_loopback (ifc->ifp)) return; /* Check RIP process is enabled on this interface. */ ri = ifc->ifp->info; if (! ri->running) return; /* 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 (lim == ((caddr_t) (rte + 1)) && ntohs (rte->family) == 0 && ntohl (rte->metric) == RIP_METRIC_INFINITY) { /* All route with split horizon */ rip_output_process (ifc, 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 = listgetdata (listhead ((struct list *)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 ((u_char *)packet, size, from, ifc); } 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", safe_strerror (errno)); return ret; } /* Read RIP packet by recvmsg function. */ int rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, ifindex_t *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 = ZCMSG_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; ifindex_t 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", safe_strerror (errno)); return ret; } return ret; } #endif /* RIP_RECVMSG */ /* First entry point of RIP packet. */ static 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 len; int vrecv; socklen_t fromlen; struct interface *ifp; struct connected *ifc; 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", safe_strerror (errno)); return len; } /* Check is this packet comming from myself? */ if (if_check_address (from.sin_addr)) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("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_debug ("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 ("rip_read: cannot find interface for packet from %s port %d", inet_ntoa(from.sin_addr), ntohs (from.sin_port)); return -1; } ifc = connected_lookup_address (ifp, from.sin_addr); if (ifc == NULL) { zlog_info ("rip_read: cannot find connected address for packet from %s " "port %d on interface %s", inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name); 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_debug ("RIP is not enabled on interface %s.", ifp->name); rip_peer_bad_packet (&from); return -1; } /* RIP Version check. RFC2453, 4.6 and 5.1 */ vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv : ri->ri_receive); if ((packet->version == RIPv1) && !(vrecv & RIPv1)) { if (IS_RIP_DEBUG_PACKET) zlog_debug (" packet's v%d doesn't fit to if version spec", packet->version); rip_peer_bad_packet (&from); return -1; } if ((packet->version == RIPv2) && !(vrecv & RIPv2)) { if (IS_RIP_DEBUG_PACKET) zlog_debug (" 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 == htons(RIP_FAMILY_AUTH))) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("packet RIPv%d is dropped because authentication disabled", packet->version); rip_peer_bad_packet (&from); return -1; } /* RFC: 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. */ /* We make an exception for RIPv1 REQUEST packets, to which we'll * always reply regardless of authentication settings, because: * * - if there other authorised routers on-link, the REQUESTor can * passively obtain the routing updates anyway * - if there are no other authorised routers on-link, RIP can * easily be disabled for the link to prevent giving out information * on state of this routers RIP routing table.. * * I.e. if RIPv1 has any place anymore these days, it's as a very * simple way to distribute routing information (e.g. to embedded * hosts / appliances) and the ability to give out RIPv1 * routing-information freely, while still requiring RIPv2 * authentication for any RESPONSEs might be vaguely useful. */ if (ri->auth_type != RIP_NO_AUTH && packet->version == RIPv1) { /* Discard RIPv1 messages other than REQUESTs */ if (packet->command != RIP_REQUEST) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv1" " dropped because authentication enabled"); rip_peer_bad_packet (&from); return -1; } } else if (ri->auth_type != RIP_NO_AUTH) { const char *auth_desc; if (rtenum == 0) { /* There definitely is no authentication in the packet. */ if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2 authentication failed: no auth RTE in packet"); rip_peer_bad_packet (&from); return -1; } /* First RTE must be an Authentication Family RTE */ if (packet->rte->family != htons(RIP_FAMILY_AUTH)) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2" " dropped because authentication enabled"); rip_peer_bad_packet (&from); return -1; } /* Check RIPv2 authentication. */ switch (ntohs(packet->rte->tag)) { case RIP_AUTH_SIMPLE_PASSWORD: auth_desc = "simple"; ret = rip_auth_simple_password (packet->rte, &from, ifp); break; case RIP_AUTH_MD5: auth_desc = "MD5"; ret = rip_auth_md5 (packet, &from, len, ifp); /* Reset RIP packet length to trim MD5 data. */ len = ret; break; default: ret = 0; auth_desc = "unknown type"; if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2 Unknown authentication type %d", ntohs (packet->rte->tag)); } if (ret) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2 %s authentication success", auth_desc); } else { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2 %s authentication failure", auth_desc); rip_peer_bad_packet (&from); return -1; } } /* Process each command. */ switch (packet->command) { case RIP_RESPONSE: rip_response_process (packet, len, &from, ifc); break; case RIP_REQUEST: case RIP_POLL: rip_request_process (packet, len, &from, ifc); 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; } /* Write routing table entry to the stream and return next index of the routing table entry in the stream. */ static int rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, u_char version, struct rip_info *rinfo) { struct in_addr mask; /* 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_out); 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 connected *ifc, 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; struct prefix_ipv4 ifaddrclass; struct key *key = NULL; /* this might need to made dynamic if RIP ever supported auth methods with larger key string sizes */ char auth_str[RIP_AUTH_SIMPLE_SIZE]; size_t doff = 0; /* offset of digest offset field */ int num = 0; int rtemax; int subnetted = 0; struct list *list = NULL; struct listnode *listnode = NULL; /* Logging output event. */ if (IS_RIP_DEBUG_EVENT) { if (to) zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr)); else zlog_debug ("update routes on interface %s ifindex %d", ifc->ifp->name, ifc->ifp->ifindex); } /* Set output stream. */ s = rip->obuf; /* Reset stream and RTE counter. */ stream_reset (s); rtemax = RIP_MAX_RTE; /* Get RIP interface. */ ri = ifc->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_NO_AUTH) { if (ri->key_chain) { struct keychain *keychain; keychain = keychain_lookup (ri->key_chain); if (keychain) key = key_lookup_for_send (keychain); } /* to be passed to auth functions later */ rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE); } if (version == RIPv1) { memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4)); apply_classful_mask_ipv4 (&ifaddrclass); subnetted = 0; if (ifc->address->prefixlen > ifaddrclass.prefixlen) subnetted = 1; } for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL && listcount (list) != 0) { rinfo = listgetdata (listhead (list)); /* For RIPv1, if we are subnetted, output subnets in our network */ /* that have the same mask as the output "interface". For other */ /* networks, only the classfull version is output. */ if (version == RIPv1) { p = (struct prefix_ipv4 *) &rp->p; if (IS_RIP_DEBUG_PACKET) zlog_debug("RIPv1 mask check, %s/%d considered for output", inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); if (subnetted && prefix_match ((struct prefix *) &ifaddrclass, &rp->p)) { if ((ifc->address->prefixlen != rp->p.prefixlen) && (rp->p.prefixlen != 32)) continue; } else { memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4)); apply_classful_mask_ipv4(&classfull); if (rp->p.u.prefix4.s_addr != 0 && classfull.prefixlen != rp->p.prefixlen) continue; } if (IS_RIP_DEBUG_PACKET) zlog_debug("RIPv1 mask check, %s/%d made it through", inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); } else p = (struct prefix_ipv4 *) &rp->p; /* Apply output filters. */ ret = rip_filter (RIP_FILTER_OUT, 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 == RIP_SPLIT_HORIZON) { /* * We perform split horizon for RIP and connected route. * For rip routes, we want to suppress the route if we would * end up sending the route back on the interface that we * learned it from, with a higher metric. For connected routes, * we suppress the route if the prefix is a subset of the * source address that we are going to use for the packet * (in order to handle the case when multiple subnets are * configured on the same interface). */ int suppress = 0; struct rip_info *tmp_rinfo = NULL; for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && tmp_rinfo->ifindex == ifc->ifp->ifindex) { suppress = 1; break; } if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT && prefix_match((struct prefix *)p, ifc->address)) suppress = 1; if (suppress) continue; } /* Preparation for route-map. */ rinfo->metric_set = 0; rinfo->nexthop_out.s_addr = 0; rinfo->metric_out = rinfo->metric; rinfo->tag_out = rinfo->tag; rinfo->ifindex_out = ifc->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. * see (4.4) */ if (rinfo->ifindex == ifc->ifp->ifindex) rinfo->nexthop_out = rinfo->nexthop; /* Interface route-map */ if (ri->routemap[RIP_FILTER_OUT]) { ret = route_map_apply (ri->routemap[RIP_FILTER_OUT], (struct prefix *) p, RMAP_RIP, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIP %s/%d is filtered by route-map out", inet_ntoa (p->prefix), p->prefixlen); continue; } } /* Apply redistribute 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_debug ("%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, ifc->ifp, &rinfo->metric_out); if (rinfo->metric_out > RIP_METRIC_INFINITY) rinfo->metric_out = RIP_METRIC_INFINITY; /* Perform split-horizon with poisoned reverse * for RIP and connected routes. **/ if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) { /* * We perform split horizon for RIP and connected route. * For rip routes, we want to suppress the route if we would * end up sending the route back on the interface that we * learned it from, with a higher metric. For connected routes, * we suppress the route if the prefix is a subset of the * source address that we are going to use for the packet * (in order to handle the case when multiple subnets are * configured on the same interface). */ struct rip_info *tmp_rinfo = NULL; for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) { if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && tmp_rinfo->ifindex == ifc->ifp->ifindex) rinfo->metric_out = RIP_METRIC_INFINITY; if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT && prefix_match((struct prefix *)p, ifc->address)) rinfo->metric_out = RIP_METRIC_INFINITY; } } /* Prepare preamble, auth headers, if needs be */ if (num == 0) { stream_putc (s, RIP_RESPONSE); stream_putc (s, version); stream_putw (s, 0); /* auth header for !v1 && !no_auth */ if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) ) doff = rip_auth_header_write (s, ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE); } /* Write RTE to the stream. */ num = rip_write_rte (num, s, p, version, rinfo); if (num == rtemax) { if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE); ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc); 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, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE); ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc); 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. */ static void rip_update_interface (struct connected *ifc, u_char version, int route_type) { struct sockaddr_in to; /* When RIP version is 2 and multicast enable interface. */ if (version == RIPv2 && if_is_multicast (ifc->ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast announce on %s ", ifc->ifp->name); rip_output_process (ifc, NULL, route_type, version); return; } /* If we can't send multicast packet, send it with unicast. */ if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp)) { if (ifc->address->family == AF_INET) { /* Destination address and port setting. */ memset (&to, 0, sizeof (struct sockaddr_in)); if (ifc->destination) /* use specified broadcast or peer destination addr */ to.sin_addr = ifc->destination->u.prefix4; else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN) /* calculate the appropriate broadcast address */ to.sin_addr.s_addr = ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr, ifc->address->prefixlen); else /* do not know where to send the packet */ return; to.sin_port = htons (RIP_PORT_DEFAULT); if (IS_RIP_DEBUG_EVENT) zlog_debug("%s announce to %s on %s", CONNECTED_PEER(ifc) ? "unicast" : "broadcast", inet_ntoa (to.sin_addr), ifc->ifp->name); rip_output_process (ifc, &to, route_type, version); } } } /* Update send to all interface and neighbor. */ static void rip_update_process (int route_type) { struct listnode *node; struct listnode *ifnode, *ifnnode; struct connected *connected; 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 (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { if (if_is_loopback (ifp)) continue; if (! if_is_operative (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 there is no version configuration in the interface, * use rip's version setting. */ int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? rip->version_send : ri->ri_send); if (IS_RIP_DEBUG_EVENT) zlog_debug("SEND UPDATE to %s ifindex %d", ifp->name, ifp->ifindex); /* send update on each connected network */ for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected)) { if (connected->address->family == AF_INET) { if (vsend & RIPv1) rip_update_interface (connected, RIPv1, route_type); if (vsend & RIPv2) rip_update_interface (connected, 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 have connected interface!", inet_ntoa (p->prefix)); continue; } if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL) { zlog_warn ("Neighbor %s doesn't have 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 (connected, &to, route_type, rip->version_send); } } /* RIP's periodical timer. */ static int rip_update (struct thread *t) { /* Clear timer pointer. */ rip->t_update = NULL; if (IS_RIP_DEBUG_EVENT) zlog_debug ("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. */ static void rip_clear_changed_flag (void) { struct route_node *rp; struct rip_info *rinfo = NULL; struct list *list = NULL; struct listnode *listnode = NULL; for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* This flag can be set only on the first entry. */ break; } } /* Triggered update interval timer. */ static 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. */ static 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_debug ("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 = NULL; struct list *list = NULL; if (!rip) return; for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) { rinfo = listgetdata (listhead (list)); 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; if (IS_RIP_DEBUG_EVENT) { struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p; zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]", inet_ntoa(p->prefix), p->prefixlen, ifindex2ifname(rinfo->ifindex)); } rip_event (RIP_TRIGGERED_UPDATE, 0); } } } /* Create new RIP instance and set it to global variable. */ static int rip_create (void) { rip = XCALLOC (MTYPE_RIP, sizeof (struct rip)); /* Set initial value. */ rip->version_send = RI_RIP_VERSION_2; rip->version_recv = RI_RIP_VERSION_1_AND_2; 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 (NULL); 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 connected *connected) { struct rte *rte; struct rip_packet rip_packet; struct listnode *node, *nnode; 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); if (connected) { /* * connected is only sent for ripv1 case, or when * interface does not support multicast. Caller loops * over each connected address for this case. */ if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet), to, connected) != sizeof (rip_packet)) return -1; else return sizeof (rip_packet); } /* send request on each connected network */ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) { struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet), to, connected) != sizeof (rip_packet)) return -1; } return sizeof (rip_packet); } static int rip_update_jitter (unsigned long time) { #define JITTER_BOUND 4 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval. Given that, we cannot let time be less than JITTER_BOUND seconds. The RIPv2 RFC says jitter should be small compared to update_time. We consider 1/JITTER_BOUND to be small. */ int jitter_input = time; int jitter; if (jitter_input < JITTER_BOUND) jitter_input = JITTER_BOUND; jitter = (((random () % ((jitter_input * 2) + 1)) - jitter_input)); return jitter/JITTER_BOUND; } 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_send = version; rip->version_recv = 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_send = RI_RIP_VERSION_2; rip->version_recv = RI_RIP_VERSION_1_AND_2; 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 = (char *)"static"; rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0, 0); 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; } #if 0 static void rip_update_default_metric (void) { struct route_node *np; struct rip_info *rinfo = NULL; struct list *list = NULL; struct listnode *listnode = NULL; for (np = route_top (rip->table); np; np = route_next (np)) if ((list = np->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) rinfo->metric = rip->default_metric; } #endif 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; } ALIAS (no_rip_timers, no_rip_timers_val_cmd, "no timers basic <0-65535> <0-65535> <0-65535>", NO_STR "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") 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; }; static struct rip_distance * rip_distance_new (void) { return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance)); } static void rip_distance_free (struct rip_distance *rdistance) { XFREE (MTYPE_RIP_DISTANCE, rdistance); } static int rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str, const 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; } static int rip_distance_unset (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix_ipv4 p; 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; } 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; } static void rip_distance_reset (void) { 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; } static 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; } /* Update ECMP routes to zebra when ECMP is disabled. */ static void rip_ecmp_disable (void) { struct route_node *rp; struct rip_info *rinfo, *tmp_rinfo; struct list *list; struct listnode *node, *nextnode; if (!rip) return; for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL && listcount (list) > 1) { rinfo = listgetdata (listhead (list)); if (!rip_route_rte (rinfo)) continue; /* Drop all other entries, except the first one. */ for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) if (tmp_rinfo != rinfo) { RIP_TIMER_OFF (tmp_rinfo->t_timeout); RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); list_delete_node (list, node); rip_info_free (tmp_rinfo); } /* Update zebra. */ rip_zebra_ipv4_add (rp); /* Set the route change flag. */ SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* Signal the output process to trigger an update. */ rip_event (RIP_TRIGGERED_UPDATE, 0); } } DEFUN (rip_allow_ecmp, rip_allow_ecmp_cmd, "allow-ecmp", "Allow Equal Cost MultiPath\n") { if (rip->ecmp) { vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE); return CMD_WARNING; } rip->ecmp = 1; zlog_info ("ECMP is enabled."); return CMD_SUCCESS; } DEFUN (no_rip_allow_ecmp, no_rip_allow_ecmp_cmd, "no allow-ecmp", NO_STR "Allow Equal Cost MultiPath\n") { if (!rip->ecmp) { vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE); return CMD_WARNING; } rip->ecmp = 0; zlog_info ("ECMP is disabled."); rip_ecmp_disable (); return CMD_SUCCESS; } /* Print out routes update time. */ static void rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) { time_t clock; struct tm *tm; #define TIME_BUF 25 char timebuf [TIME_BUF]; struct thread *thread; if ((thread = rinfo->t_timeout) != NULL) { clock = thread_timer_remain_second (thread); 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_timer_remain_second (thread); tm = gmtime (&clock); strftime (timebuf, TIME_BUF, "%M:%S", tm); vty_out (vty, "%5s", timebuf); } } static const 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 = NULL; struct list *list = NULL; struct listnode *listnode = NULL; if (! rip) return CMD_SUCCESS; vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s" "Sub-codes:%s" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" " (i) - interface%s%s" " Network Next Hop Metric From Tag Time%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (np = route_top (rip->table); np; np = route_next (np)) if ((list = np->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { int len; len = vty_out (vty, "%c(%s) %s/%d", /* np->lock, For debugging. */ zebra_route_char(rinfo->type), 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)); vty_out (vty, "%3d ", rinfo->tag); rip_vty_out_uptime (vty, rinfo); } else if (rinfo->metric == RIP_METRIC_INFINITY) { vty_out (vty, "self "); vty_out (vty, "%3d ", rinfo->tag); rip_vty_out_uptime (vty, rinfo); } else { if (rinfo->external_metric) { len = vty_out (vty, "self (%s:%d)", zebra_route_string(rinfo->type), rinfo->external_metric); len = 16 - len; if (len > 0) vty_out (vty, "%*s", len, " "); } else vty_out (vty, "self "); vty_out (vty, "%3d", rinfo->tag); } vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } /* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */ DEFUN (show_ip_rip_status, show_ip_rip_status_cmd, "show ip rip status", SHOW_STR IP_STR "Show RIP routes\n" "IP routing protocol process parameters and statistics\n") { struct listnode *node; struct interface *ifp; struct rip_interface *ri; extern const struct message ri_version_msg[]; const char *send_version; const 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 %lu seconds%s", thread_timer_remain_second(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 %s,", lookup(ri_version_msg,rip->version_send)); if (rip->version_recv == RI_RIP_VERSION_1_AND_2) vty_out (vty, " receive any version %s", VTY_NEWLINE); else vty_out (vty, " receive version %s %s", lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE); vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; if (!ri->running) continue; if (ri->enable_network || ri->enable_interface) { if (ri->ri_send == RI_RIP_UNSPEC) send_version = lookup (ri_version_msg, rip->version_send); 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_recv); 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); { int found_passive = 0; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; if ((ri->enable_network || ri->enable_interface) && ri->passive) { if (!found_passive) { vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE); found_passive = 1; } vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE); } } } 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. */ static 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_send != RI_RIP_VERSION_2 || rip->version_recv != RI_RIP_VERSION_1_AND_2) vty_out (vty, " version %d%s", rip->version_send, 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); /* Interface routemap configuration */ write += config_write_if_rmap (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); /* ECMP configuration. */ if (rip->ecmp) vty_out (vty, " allow-ecmp%s", 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. */ static struct cmd_node rip_node = { RIP_NODE, "%s(config-router)# ", 1 }; /* Distribute-list update functions. */ static 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_V4_IN]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_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_V4_OUT]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_V4_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_V4_IN]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_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_V4_OUT]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_V4_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. */ /* ARGSUSED */ static void rip_distribute_update_all (struct prefix_list *notused) { struct interface *ifp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_distribute_update_interface (ifp); } /* ARGSUSED */ static void rip_distribute_update_all_wrapper(const char *unused) { rip_distribute_update_all(NULL); } /* Delete all added rip route. */ void rip_clean (void) { int i; struct route_node *rp; struct rip_info *rinfo = NULL; struct list *list = NULL; struct listnode *listnode = NULL; if (rip) { /* Clear RIP routes */ for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) { rinfo = listgetdata (listhead (list)); if (rip_route_rte (rinfo)) rip_zebra_ipv4_delete (rp); for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); rip_info_free (rinfo); } list_delete (list); rp->info = NULL; route_unlock_node (rp); } /* 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_nondefault_clean (); rip_offset_clean (); rip_interfaces_clean (); rip_distance_reset (); rip_redistribute_clean (); } /* Reset all values to the default settings. */ void rip_reset (void) { /* 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_interfaces_reset (); rip_distance_reset (); rip_zclient_reset (); } static void rip_if_rmap_update (struct if_rmap *if_rmap) { struct interface *ifp; struct rip_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[RIP_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[RIP_FILTER_OUT] = NULL; } void rip_if_rmap_update_interface (struct interface *ifp) { struct if_rmap *if_rmap; if_rmap = if_rmap_lookup (ifp->name); if (if_rmap) rip_if_rmap_update (if_rmap); } static void rip_routemap_update_redistribute (void) { 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); } } } /* ARGSUSED */ static void rip_routemap_update (const char *notused) { struct interface *ifp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_if_rmap_update_interface (ifp); rip_routemap_update_redistribute (); } /* Allocate new rip structure and set default value. */ void rip_init (void) { /* Randomize for triggered update random(). */ srandom (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_rip_status_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, &no_rip_timers_val_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); install_element (RIP_NODE, &rip_allow_ecmp_cmd); install_element (RIP_NODE, &no_rip_allow_ecmp_cmd); /* Debug related init. */ rip_debug_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_wrapper); access_list_delete_hook (rip_distribute_update_all_wrapper); /* 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); /* Route-map */ rip_route_map_init (); rip_offset_init (); route_map_add_hook (rip_routemap_update); route_map_delete_hook (rip_routemap_update); if_rmap_init (RIP_NODE); if_rmap_hook_add (rip_if_rmap_update); if_rmap_hook_delete (rip_if_rmap_update); /* Distance control. */ rip_distance_table = route_table_init (); } quagga-1.2.4/ripd/ripd.conf.sample000066400000000000000000000006261325323223500170120ustar00rootroot00000000000000! -*- rip -*- ! ! RIPd sample configuration file ! ! $Id: ripd.conf.sample,v 1.1 2002/12/13 20:15:30 paul 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 quagga-1.2.4/ripd/ripd.h000066400000000000000000000273621325323223500150420ustar00rootroot00000000000000/* 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 /* N.B. stuff will break if (RIPv1 != RI_RIP_VERSION_1) || (RIPv2 != RI_RIP_VERSION_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 and max size. */ #define RIP_PACKET_MINSIZ 4 #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 ((RIP_PACKET_MAXSIZ - RIP_HEADER_SIZE) / RIP_RTE_SIZE) /* 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 /* 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 /* RIPv2 special RTE family types */ #define RIP_FAMILY_AUTH 0xffff /* RIPv2 authentication types, for RIP_FAMILY_AUTH RTE's */ #define RIP_NO_AUTH 0 #define RIP_AUTH_DATA 1 #define RIP_AUTH_SIMPLE_PASSWORD 2 #define RIP_AUTH_MD5 3 /* RIPv2 Simple authentication */ #define RIP_AUTH_SIMPLE_SIZE 16 /* RIPv2 MD5 authentication. */ #define RIP_AUTH_MD5_SIZE 16 #define RIP_AUTH_MD5_COMPAT_SIZE RIP_RTE_SIZE /* RIP structure. */ struct rip { /* RIP socket. */ int sock; /* Default version of rip instance. */ int version_send; /* version 1 or 2 (but not both) */ int version_recv; /* version 1 or 2 or both */ /* 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; /* RIP ECMP flag */ unsigned int ecmp; /* 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. */ ifindex_t ifindex; /* Metric of this route. */ u_int32_t metric; /* External metric of this route. if learnt from an externalm proto */ u_int32_t external_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; u_int16_t tag_out; ifindex_t 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 */ }; typedef enum { RIP_NO_SPLIT_HORIZON = 0, RIP_SPLIT_HORIZON, RIP_SPLIT_HORIZON_POISONED_REVERSE } split_horizon_policy_t; /* 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; /* RIP version control. */ int ri_send; int ri_receive; /* RIPv2 authentication type. */ int auth_type; /* RIPv2 authentication string. */ char *auth_str; /* RIPv2 authentication key chain. */ char *key_chain; /* value to use for md5->auth_len */ u_int8_t md5_auth_len; /* Split horizon flag. */ split_horizon_policy_t split_horizon; split_horizon_policy_t 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]; /* Route-map. */ struct route_map *routemap[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 /* N.B. stuff will break if (RIPv1 != RI_RIP_VERSION_1) || (RIPv2 != RI_RIP_VERSION_2) */ /* 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. */ extern void rip_init (void); extern void rip_reset (void); extern void rip_clean (void); extern void rip_clean_network (void); extern void rip_interfaces_clean (void); extern void rip_interfaces_reset (void); extern void rip_passive_nondefault_clean (void); extern void rip_if_init (void); extern void rip_if_down_all (void); extern void rip_route_map_init (void); extern void rip_route_map_reset (void); extern void rip_snmp_init (void); extern void rip_zclient_init (struct thread_master *); extern void rip_zclient_start (void); extern void rip_zclient_reset (void); extern void rip_offset_init (void); extern int if_check_address (struct in_addr addr); extern int rip_request_send (struct sockaddr_in *, struct interface *, u_char, struct connected *); extern int rip_neighbor_lookup (struct sockaddr_in *); extern int rip_redistribute_check (int); extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, ifindex_t, struct in_addr *, unsigned int, unsigned char, route_tag_t); extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, ifindex_t); extern void rip_redistribute_withdraw (int); extern void rip_zebra_ipv4_add (struct route_node *); extern void rip_zebra_ipv4_delete (struct route_node *); extern void rip_interface_multicast_set (int, struct connected *); extern void rip_distribute_update_interface (struct interface *); extern void rip_if_rmap_update_interface (struct interface *); extern int config_write_rip_network (struct vty *, int); extern int config_write_rip_offset_list (struct vty *); extern int config_write_rip_redistribute (struct vty *, int); extern void rip_peer_init (void); extern void rip_peer_update (struct sockaddr_in *, u_char); extern void rip_peer_bad_route (struct sockaddr_in *); extern void rip_peer_bad_packet (struct sockaddr_in *); extern void rip_peer_display (struct vty *); extern struct rip_peer *rip_peer_lookup (struct in_addr *); extern struct rip_peer *rip_peer_lookup_next (struct in_addr *); extern int rip_offset_list_apply_in (struct prefix_ipv4 *, struct interface *, u_int32_t *); extern int rip_offset_list_apply_out (struct prefix_ipv4 *, struct interface *, u_int32_t *); extern void rip_offset_clean (void); extern void rip_info_free (struct rip_info *); extern u_char rip_distance_apply (struct rip_info *); extern void rip_redistribute_clean (void); extern void rip_ifaddr_add (struct interface *, struct connected *); extern void rip_ifaddr_delete (struct interface *, struct connected *); extern struct rip_info *rip_ecmp_add (struct rip_info *); extern struct rip_info *rip_ecmp_replace (struct rip_info *); extern struct rip_info *rip_ecmp_delete (struct rip_info *); /* 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 */ quagga-1.2.4/ripngd/000077500000000000000000000000001325323223500142465ustar00rootroot00000000000000quagga-1.2.4/ripngd/Makefile.am000066400000000000000000000012651325323223500163060ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(WERROR) 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_offset.c ripng_peer.c ripng_nexthop.c noinst_HEADERS = \ ripng_debug.h ripng_route.h ripngd.h ripng_nexthop.h ripngd_SOURCES = \ ripng_main.c $(libripng_a_SOURCES) ripngd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ripngd.conf.sample quagga-1.2.4/ripngd/Makefile.in000066400000000000000000000617121325323223500163220ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ripngd$(EXEEXT) subdir = ripngd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libripng_a_AR = $(AR) $(ARFLAGS) 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_offset.$(OBJEXT) ripng_peer.$(OBJEXT) \ ripng_nexthop.$(OBJEXT) libripng_a_OBJECTS = $(am_libripng_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = ripng_interface.$(OBJEXT) ripngd.$(OBJEXT) \ ripng_zebra.$(OBJEXT) ripng_route.$(OBJEXT) \ ripng_debug.$(OBJEXT) ripng_routemap.$(OBJEXT) \ ripng_offset.$(OBJEXT) ripng_peer.$(OBJEXT) \ ripng_nexthop.$(OBJEXT) am_ripngd_OBJECTS = ripng_main.$(OBJEXT) $(am__objects_1) ripngd_OBJECTS = $(am_ripngd_OBJECTS) ripngd_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libripng_a_SOURCES) $(ripngd_SOURCES) DIST_SOURCES = $(libripng_a_SOURCES) $(ripngd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libripng.a libripng_a_SOURCES = \ ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \ ripng_routemap.c ripng_offset.c ripng_peer.c ripng_nexthop.c noinst_HEADERS = \ ripng_debug.h ripng_route.h ripngd.h ripng_nexthop.h ripngd_SOURCES = \ ripng_main.c $(libripng_a_SOURCES) ripngd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ripngd.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ripngd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ripngd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libripng.a: $(libripng_a_OBJECTS) $(libripng_a_DEPENDENCIES) $(EXTRA_libripng_a_DEPENDENCIES) $(AM_V_at)-rm -f libripng.a $(AM_V_AR)$(libripng_a_AR) libripng.a $(libripng_a_OBJECTS) $(libripng_a_LIBADD) $(AM_V_at)$(RANLIB) libripng.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ripngd$(EXEEXT): $(ripngd_OBJECTS) $(ripngd_DEPENDENCIES) $(EXTRA_ripngd_DEPENDENCIES) @rm -f ripngd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ripngd_OBJECTS) $(ripngd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) 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_interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_nexthop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_offset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_peer.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@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/ripngd/ripng_debug.c000066400000000000000000000171641325323223500167100ustar00rootroot00000000000000/* * 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 (show_debugging_ripng, show_debugging_ripng_cmd, "show debugging ripng", SHOW_STR DEBUG_STR "RIPng configuration\n") { vty_out (vty, "RIPng 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 debugging is on%s", VTY_NEWLINE); } else { if (IS_RIPNG_DEBUG_SEND) vty_out (vty, " RIPng packet send debugging is on%s", VTY_NEWLINE); else vty_out (vty, " RIPng packet receive debugging is on%s", VTY_NEWLINE); } } if (IS_RIPNG_DEBUG_ZEBRA) vty_out (vty, " RIPng zebra debugging is on%s", VTY_NEWLINE); return CMD_SUCCESS; } 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; return CMD_SUCCESS; } /* N.B. the "detail" modifier is a no-op. we leave this command for legacy compatibility. */ DEFUN_DEPRECATED (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; 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; } /* Debug node. */ static struct cmd_node debug_node = { DEBUG_NODE, "", /* Debug node has no interface. */ 1 /* VTYSH */ }; static 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", VTY_NEWLINE); write++; } else { if (IS_RIPNG_DEBUG_SEND) vty_out (vty, "debug ripng packet send%s", VTY_NEWLINE); else vty_out (vty, "debug ripng packet recv%s", 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 (VIEW_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); } quagga-1.2.4/ripngd/ripng_debug.h000066400000000000000000000032501325323223500167040ustar00rootroot00000000000000/* * 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_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_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; extern void ripng_debug_init (void); extern void ripng_debug_reset (void); #endif /* _ZEBRA_RIPNG_DEBUG_H */ quagga-1.2.4/ripngd/ripng_interface.c000066400000000000000000000716361325323223500175660ustar00rootroot00000000000000/* * 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 "privs.h" #include "vrf.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 extern struct zebra_privs_t ripngd_privs; /* Static utility function. */ static void ripng_enable_apply (struct interface *); static void ripng_passive_interface_apply (struct interface *); static int ripng_enable_if_lookup (const char *); static int ripng_enable_network_lookup2 (struct connected *); static void ripng_enable_apply_all (void); /* Join to the all rip routers multicast group. */ static int ripng_multicast_join (struct interface *ifp) { int ret; struct ipv6_mreq mreq; int save_errno; if (if_is_up (ifp) && if_is_multicast (ifp)) { memset (&mreq, 0, sizeof (mreq)); inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; /* * NetBSD 1.6.2 requires root to join groups on gif(4). * While this is bogus, privs are available and easy to use * for this call as a workaround. */ if (ripngd_privs.change (ZPRIVS_RAISE)) zlog_err ("ripng_multicast_join: could not raise privs"); ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreq, sizeof (mreq)); save_errno = errno; if (ripngd_privs.change (ZPRIVS_LOWER)) zlog_err ("ripng_multicast_join: could not lower privs"); if (ret < 0 && save_errno == EADDRINUSE) { /* * Group is already joined. This occurs due to sloppy group * management, in particular declining to leave the group on * an interface that has just gone down. */ zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name); return 0; /* not an error */ } if (ret < 0) zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (save_errno)); if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng %s join to all-rip-routers multicast group", ifp->name); if (ret < 0) return -1; } return 0; } /* Leave from the all rip routers multicast group. */ static int ripng_multicast_leave (struct interface *ifp) { int ret; struct ipv6_mreq mreq; if (if_is_up (ifp) && if_is_multicast (ifp)) { 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", safe_strerror (errno)); if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng %s leave from all-rip-routers multicast group", ifp->name); if (ret < 0) return -1; } return 0; } /* How many link local IPv6 address could be used on the interface ? */ static int ripng_if_ipv6_lladdress_check (struct interface *ifp) { struct listnode *nn; struct connected *connected; int count = 0; for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected)) { struct prefix *p; p = connected->address; if ((p->family == AF_INET6) && IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6)) count++; } return count; } static int ripng_if_down (struct interface *ifp) { struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; struct list *list = NULL; struct listnode *listnode = NULL, *nextnode = NULL; if (ripng) for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS (list, listnode, nextnode, rinfo)) if (rinfo->ifindex == ifp->ifindex) ripng_ecmp_delete (rinfo); ri = ifp->info; if (ri->running) { if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("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, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("interface up %s index %d flags %llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); /* 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, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; ripng_if_down (ifp); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("interface down %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6); return 0; } /* Inteface addition message from zebra. */ int ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf, vrf_id); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("RIPng interface add %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6); /* 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, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read (s, vrf_id); if (ifp == NULL) return 0; if (if_is_up (ifp)) { ripng_if_down(ifp); } zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ ifp->ifindex = IFINDEX_INTERNAL; return 0; } void ripng_interface_clean (void) { struct listnode *node, *nnode; struct interface *ifp; struct ripng_interface *ri; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { 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 ripng_interface_reset (void) { struct listnode *node; struct interface *ifp; struct ripng_interface *ri; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; ri->enable_network = 0; ri->enable_interface = 0; ri->running = 0; ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON; ri->list[RIPNG_FILTER_IN] = NULL; ri->list[RIPNG_FILTER_OUT] = NULL; ri->prefix[RIPNG_FILTER_IN] = NULL; ri->prefix[RIPNG_FILTER_OUT] = NULL; if (ri->t_wakeup) { thread_cancel (ri->t_wakeup); ri->t_wakeup = NULL; } ri->passive = 0; } } static void ripng_apply_address_add (struct connected *ifc) { struct prefix_ipv6 address; struct prefix *p; if (!ripng) return; if (! if_is_up(ifc->ifp)) return; p = ifc->address; memset (&address, 0, sizeof (address)); address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6(&address); /* Check if this interface is RIP enabled or not or Check if this address's prefix is RIP enabled */ if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) || (ripng_enable_network_lookup2(ifc) >= 0)) ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, ifc->ifp->ifindex, NULL, 0); } int ripng_interface_address_add (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf, vrf_id); if (c == NULL) return 0; p = c->address; if (p->family == AF_INET6) { struct ripng_interface *ri = c->ifp->info; if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("RIPng connected address %s/%d add", inet6_ntoa(p->u.prefix6), p->prefixlen); /* Check is this prefix needs to be redistributed. */ ripng_apply_address_add(c); /* Let's try once again whether the interface could be activated */ if (!ri->running) { /* Check if this interface is RIP enabled or not.*/ ripng_enable_apply (c->ifp); /* Apply distribute list to the interface. */ ripng_distribute_update_interface (c->ifp); /* Check interface routemap. */ ripng_if_rmap_update_interface (c->ifp); } } return 0; } static void ripng_apply_address_del (struct connected *ifc) { struct prefix_ipv6 address; struct prefix *p; if (!ripng) return; if (! if_is_up(ifc->ifp)) return; p = ifc->address; memset (&address, 0, sizeof (address)); address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6(&address); ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, ifc->ifp->ifindex); } int ripng_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; struct prefix *p; char buf[INET6_ADDRSTRLEN]; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf, vrf_id); if (ifc) { p = ifc->address; if (p->family == AF_INET6) { if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("RIPng connected address %s/%d delete", inet_ntop (AF_INET6, &p->u.prefix6, buf, INET6_ADDRSTRLEN), p->prefixlen); /* Check wether this prefix needs to be removed. */ ripng_apply_address_del(ifc); } 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. */ /* Check wether the interface has at least a connected prefix that * is within the ripng_enable_network table. */ static int ripng_enable_network_lookup_if (struct interface *ifp) { struct listnode *node; struct connected *connected; struct prefix_ipv6 address; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { struct prefix *p; struct route_node *node; p = connected->address; if (p->family == AF_INET6) { address.family = AF_INET6; address.prefix = p->u.prefix6; address.prefixlen = IPV6_MAX_BITLEN; node = route_node_match (ripng_enable_network, (struct prefix *)&address); if (node) { route_unlock_node (node); return 1; } } } return -1; } /* Check wether connected is within the ripng_enable_network table. */ static int ripng_enable_network_lookup2 (struct connected *connected) { struct prefix_ipv6 address; struct prefix *p; p = connected->address; if (p->family == AF_INET6) { struct route_node *node; address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = IPV6_MAX_BITLEN; /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */ node = route_node_match (ripng_enable_network, (struct prefix *)&address); if (node) { route_unlock_node (node); return 1; } } return -1; } /* Add RIPng enable network. */ static 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 = (char *) "enabled"; /* XXX: One should find a better solution than a generic one */ ripng_enable_apply_all(); return 1; } /* Delete RIPng enable network. */ static 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. */ static int ripng_enable_if_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (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. */ static int ripng_enable_if_add (const char *ifname) { int ret; ret = ripng_enable_if_lookup (ifname); if (ret >= 0) return -1; vector_set (ripng_enable_if, strdup (ifname)); ripng_enable_apply_all(); return 1; } /* Delete interface from ripng_enable_if. */ static int ripng_enable_if_delete (const 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); ripng_enable_apply_all(); return 1; } /* Wake up interface. */ static 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. */ if (ripng_multicast_join (ifp) < 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. */ ripng_request (ifp); return 0; } static void ripng_connect_set (struct interface *ifp, int set) { struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv6 address; for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) { struct prefix *p; p = connected->address; if (p->family != AF_INET6) continue; address.family = AF_INET6; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6 (&address); if (set) { /* Check once more wether this prefix is within a "network IF_OR_PREF" one */ if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) || (ripng_enable_network_lookup2(connected) >= 0)) ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, connected->ifp->ifindex, NULL, 0); } else { ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, connected->ifp->ifindex); if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT)) ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE, &address, connected->ifp->ifindex, NULL, 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_up (ifp)) return; ri = ifp->info; /* Is this interface a candidate for RIPng ? */ ret = ripng_enable_network_lookup_if (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; /* any candidate interface MUST have a link-local IPv6 address */ if ((! ripng_if_ipv6_lladdress_check (ifp)) && (ri->enable_network || ri->enable_interface)) { ri->enable_network = 0; ri->enable_interface = 0; zlog_warn("Interface %s does not have any link-local address", ifp->name); } /* Update running status of the interface. */ if (ri->enable_network || ri->enable_interface) { { if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("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); ripng_connect_set (ifp, 1); } } else { if (ri->running) { /* Might as well clean up the route table as well * ripng_if_down sets to 0 ri->running, and displays "turn off %s" **/ ripng_if_down(ifp); ripng_connect_set (ifp, 0); } } } /* Set distribute list to all interfaces. */ static void ripng_enable_apply_all (void) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_enable_apply (ifp); } /* Clear all network and neighbor configuration */ void ripng_clean_network () { unsigned int i; char *str; struct route_node *rn; /* ripng_enable_network */ for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn)) if (rn->info) { rn->info = NULL; route_unlock_node(rn); } /* ripng_enable_if */ for (i = 0; i < vector_active (ripng_enable_if); i++) if ((str = vector_slot (ripng_enable_if, i)) != NULL) { free (str); vector_slot (ripng_enable_if, i) = NULL; } } /* Vector to store passive-interface name. */ vector Vripng_passive_interface; /* Utility function for looking up passive interface settings. */ static int ripng_passive_interface_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (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; } static void ripng_passive_interface_apply_all (void) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_passive_interface_apply (ifp); } /* Passive interface. */ static int ripng_passive_interface_set (struct vty *vty, const 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; } static int ripng_passive_interface_unset (struct vty *vty, const 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) { unsigned int i; char *str; for (i = 0; i < vector_active (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 config_mode) { unsigned int i; const 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, "%s%s/%d%s", config_mode ? " network " : " ", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen, VTY_NEWLINE); } /* Write enable interface. */ for (i = 0; i < vector_active (ripng_enable_if); i++) if ((ifname = vector_slot (ripng_enable_if, i)) != NULL) vty_out (vty, "%s%s%s", config_mode ? " network " : " ", ifname, VTY_NEWLINE); /* Write passive interface. */ if (config_mode) for (i = 0; i < vector_active (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; } 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; } return CMD_SUCCESS; } DEFUN (ipv6_ripng_split_horizon, ipv6_ripng_split_horizon_cmd, "ipv6 ripng split-horizon", IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; struct ripng_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIPNG_SPLIT_HORIZON; return CMD_SUCCESS; } DEFUN (ipv6_ripng_split_horizon_poisoned_reverse, ipv6_ripng_split_horizon_poisoned_reverse_cmd, "ipv6 ripng split-horizon poisoned-reverse", IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") { struct interface *ifp; struct ripng_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE; return CMD_SUCCESS; } DEFUN (no_ipv6_ripng_split_horizon, no_ipv6_ripng_split_horizon_cmd, "no ipv6 ripng split-horizon", NO_STR IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; struct ripng_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; return CMD_SUCCESS; } ALIAS (no_ipv6_ripng_split_horizon, no_ipv6_ripng_split_horizon_poisoned_reverse_cmd, "no ipv6 ripng split-horizon poisoned-reverse", NO_STR IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") 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]); } static struct ripng_interface * ri_new (void) { struct ripng_interface *ri; ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface)); /* 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 = RIPNG_SPLIT_HORIZON; ri->split_horizon = ri->split_horizon_default; return ri; } static int ripng_if_new_hook (struct interface *ifp) { ifp->info = ri_new (); return 0; } /* Called when interface structure deleted. */ static int ripng_if_delete_hook (struct interface *ifp) { XFREE (MTYPE_IF, ifp->info); ifp->info = NULL; return 0; } /* Configuration write function for ripngd. */ static int interface_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; struct ripng_interface *ri; int write = 0; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; /* Do not display the interface if there is no * configuration about it. **/ if ((!ifp->desc) && (ri->split_horizon == ri->split_horizon_default)) continue; 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) { switch (ri->split_horizon) { case RIPNG_SPLIT_HORIZON: vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE); break; case RIPNG_SPLIT_HORIZON_POISONED_REVERSE: vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s", VTY_NEWLINE); break; case RIPNG_NO_SPLIT_HORIZON: default: vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE); break; } } vty_out (vty, "!%s", VTY_NEWLINE); write++; } return write; } /* ripngd's interface node. */ static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */ }; /* Initialization of interface. */ void ripng_if_init () { /* Interface initialize. */ if_add_hook (IF_NEW_HOOK, ripng_if_new_hook); if_add_hook (IF_DELETE_HOOK, ripng_if_delete_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 commands. */ install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); 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); install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd); install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd); install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd); } quagga-1.2.4/ripngd/ripng_main.c000066400000000000000000000154441325323223500165450ustar00rootroot00000000000000/* * 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 #include "getopt.h" #include "vector.h" #include "vty.h" #include "command.h" #include "memory.h" #include "thread.h" #include "log.h" #include "prefix.h" #include "if.h" #include "privs.h" #include "sigevent.h" #include "vrf.h" #include "ripngd/ripngd.h" /* Configuration filename and directory. */ char config_default[] = SYSCONFDIR RIPNG_DEFAULT_CONFIG; char *config_file = NULL; /* RIPngd options. */ struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { 0 } }; /* ripngd privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND }; struct zebra_privs_t ripngd_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = 2, .cap_num_i = 0 }; /* RIPngd program name */ /* Route retain mode flag. */ int retain_mode = 0; /* RIPng VTY bind address. */ char *vty_addr = NULL; /* RIPng VTY connection port. */ int vty_port = RIPNG_VTY_PORT; /* Master of threads. */ struct thread_master *master; /* Process ID saved for use by init system */ const 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\ -z, --socket Set path of zebra socket\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\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog_info ("SIGHUP received"); ripng_clean (); ripng_reset (); /* Reload config file. */ vty_read_config (config_file, config_default); /* Create VTY's socket */ vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); /* Try to return to normal operation. */ } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); if (! retain_mode) ripng_clean (); exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } struct quagga_signal_t ripng_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* RIPngd main routine. */ int main (int argc, char **argv) { char *p; int vty_port = RIPNG_VTY_PORT; int daemon_mode = 0; char *progname; int dryrun = 0; /* Set umask before anything for security */ umask (0027); /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog(progname, ZLOG_RIPNG, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); while (1) { int opt; opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:vC", 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 'z': zclient_serv_path_set (optarg); break; case 'P': /* Deal with atoi() returning 0 on failure, and ripngd not listening on ripngd port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = RIPNG_VTY_PORT; break; case 'r': retain_mode = 1; break; case 'u': ripngd_privs.user = optarg; break; case 'g': ripngd_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } master = thread_master_create (); /* Library inits. */ zprivs_init (&ripngd_privs); signal_init (master, array_size(ripng_signals), ripng_signals); cmd_init (1); vty_init (master); memory_init (); vrf_init (); /* RIPngd inits. */ ripng_init (); zebra_init (master); ripng_peer_init (); /* Get configuration file. */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if(dryrun) return(0); /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("RIPNGd daemon failed: %s", strerror(errno)); exit (1); } /* Create VTY socket */ vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); /* Process id file create. */ pid_output (pid_file); /* Print banner. */ zlog_notice ("RIPNGd %s starting: vty@%d", QUAGGA_VERSION, vty_port); /* Fetch next active thread. */ thread_main (master); /* Not reached. */ return 0; } quagga-1.2.4/ripngd/ripng_nexthop.c000066400000000000000000000133511325323223500173010ustar00rootroot00000000000000/* RIPngd Zebra * Copyright (C) 2002 6WIND * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 required in order to support properly the RIPng nexthop * feature. */ #include /* For struct udphdr. */ #include #include "linklist.h" #include "stream.h" #include "log.h" #include "memory.h" #include "vty.h" #include "if.h" #include "prefix.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" #define DEBUG 1 #define min(a, b) ((a) < (b) ? (a) : (b)) struct ripng_rte_data { struct prefix_ipv6 *p; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; }; void _ripng_rte_del(struct ripng_rte_data *A); int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B); #define METRIC_OUT(a) \ ((a)->rinfo ? (a)->rinfo->metric_out : (a)->aggregate->metric_out) #define NEXTHOP_OUT_PTR(a) \ ((a)->rinfo ? &((a)->rinfo->nexthop_out) : &((a)->aggregate->nexthop_out)) #define TAG_OUT(a) \ ((a)->rinfo ? (a)->rinfo->tag_out : (a)->aggregate->tag_out) struct list * ripng_rte_new(void) { struct list *rte; rte = list_new(); rte->cmp = (int (*)(void *, void *)) _ripng_rte_cmp; rte->del = (void (*)(void *)) _ripng_rte_del; return rte; } void ripng_rte_free(struct list *ripng_rte_list) { list_delete(ripng_rte_list); } /* Delete RTE */ void _ripng_rte_del(struct ripng_rte_data *A) { XFREE(MTYPE_RIPNG_RTE_DATA, A); } /* Compare RTE: * return + if A > B * 0 if A = B * - if A < B */ int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) { return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B)); } /* Add routing table entry */ void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, struct ripng_info *rinfo, struct ripng_aggregate *aggregate) { struct ripng_rte_data *data; /* At least one should not be null */ assert(!rinfo || !aggregate); data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data)); data->p = p; data->rinfo = rinfo; data->aggregate = aggregate; listnode_add_sort(ripng_rte_list, data); } /* Send the RTE with the nexthop support */ void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, struct sockaddr_in6 *to) { struct ripng_rte_data *data; struct listnode *node, *nnode; struct in6_addr last_nexthop; struct in6_addr myself_nexthop; struct stream *s; int num; int mtu; int rtemax; int ret; /* Most of the time, there is no nexthop */ memset(&last_nexthop, 0, sizeof(last_nexthop)); /* Use myself_nexthop if the nexthop is not a link-local address, because * we remain a right path without beeing the optimal one. */ memset(&myself_nexthop, 0, sizeof(myself_nexthop)); /* 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->mtu6; 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); for (ALL_LIST_ELEMENTS (ripng_rte_list, node, nnode, data)) { /* (2.1) Next hop support */ if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) { /* A nexthop entry should be at least followed by 1 RTE */ if (num == (rtemax-1)) { ret = ripng_send_packet ((caddr_t) 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); } /* Add the nexthop (2.1) */ /* 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. */ if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data))) last_nexthop = myself_nexthop; else last_nexthop = *NEXTHOP_OUT_PTR(data); num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP); } else { /* Rewrite the nexthop for each new packet */ if ((num == 0) && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop)) num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP); } num = ripng_write_rte(num, s, data->p, NULL, TAG_OUT(data), METRIC_OUT(data)); if (num == rtemax) { ret = ripng_send_packet ((caddr_t) 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 ((caddr_t) 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"); stream_reset (s); } } quagga-1.2.4/ripngd/ripng_nexthop.h000066400000000000000000000037771325323223500173210ustar00rootroot00000000000000/* RIPng nexthop support * Copyright (C) 6WIND Vincent Jardin * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_RIPNG_NEXTHOP_H #define _ZEBRA_RIPNG_RIPNG_NEXTHOP_H #include #include "linklist.h" #include "ripngd/ripng_route.h" #include "ripngd/ripngd.h" extern struct list * ripng_rte_new(void); extern void ripng_rte_free(struct list *ripng_rte_list); extern void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, struct ripng_info *rinfo, struct ripng_aggregate *aggregate); extern void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, struct sockaddr_in6 *to); /*** * 1 if A > B * 0 if A = B * -1 if A < B **/ static inline int addr6_cmp(struct in6_addr *A, struct in6_addr *B) { #define a(i) A->s6_addr32[i] #define b(i) B->s6_addr32[i] if (a(3) > b(3)) return 1; else if ((a(3) == b(3)) && (a(2) > b(2))) return 1; else if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) > b(1))) return 1; else if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) == b(1)) && (a(0) > b(0))) return 1; if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) == b(1)) && (a(0) == b(0))) return 0; return -1; } #endif /* _ZEBRA_RIPNG_RIPNG_NEXTHOP_H */ quagga-1.2.4/ripngd/ripng_offset.c000066400000000000000000000260171325323223500171050ustar00rootroot00000000000000/* RIPng 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. */ /* RIPng support by Vincent Jardin * Copyright (C) 2002 6WIND */ #include #include "if.h" #include "prefix.h" #include "filter.h" #include "command.h" #include "linklist.h" #include "memory.h" #include "ripngd/ripngd.h" #define RIPNG_OFFSET_LIST_IN 0 #define RIPNG_OFFSET_LIST_OUT 1 #define RIPNG_OFFSET_LIST_MAX 2 struct ripng_offset_list { char *ifname; struct { char *alist_name; /* struct access_list *alist; */ int metric; } direct[RIPNG_OFFSET_LIST_MAX]; }; static struct list *ripng_offset_list_master; static int strcmp_safe (const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) return 0; if (s1 == NULL) return -1; if (s2 == NULL) return 1; return strcmp (s1, s2); } static struct ripng_offset_list * ripng_offset_list_new () { struct ripng_offset_list *new; new = XCALLOC (MTYPE_RIPNG_OFFSET_LIST, sizeof (struct ripng_offset_list)); return new; } static void ripng_offset_list_free (struct ripng_offset_list *offset) { XFREE (MTYPE_RIPNG_OFFSET_LIST, offset); } static struct ripng_offset_list * ripng_offset_list_lookup (const char *ifname) { struct ripng_offset_list *offset; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (ripng_offset_list_master, node, nnode, offset)) { if (strcmp_safe (offset->ifname, ifname) == 0) return offset; } return NULL; } static struct ripng_offset_list * ripng_offset_list_get (const char *ifname) { struct ripng_offset_list *offset; offset = ripng_offset_list_lookup (ifname); if (offset) return offset; offset = ripng_offset_list_new (); if (ifname) offset->ifname = strdup (ifname); listnode_add_sort (ripng_offset_list_master, offset); return offset; } static int ripng_offset_list_set (struct vty *vty, const char *alist, const char *direct_str, const char *metric_str, const char *ifname) { int direct; int metric; struct ripng_offset_list *offset; /* Check direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = RIPNG_OFFSET_LIST_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RIPNG_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 = ripng_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; } static int ripng_offset_list_unset (struct vty *vty, const char *alist, const char *direct_str, const char *metric_str, const char *ifname) { int direct; int metric; struct ripng_offset_list *offset; /* Check direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = RIPNG_OFFSET_LIST_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RIPNG_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 = ripng_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[RIPNG_OFFSET_LIST_IN].alist_name == NULL && offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name == NULL) { listnode_delete (ripng_offset_list_master, offset); if (offset->ifname) free (offset->ifname); ripng_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[RIPNG_OFFSET_LIST_IN].alist_name) #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric) #define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].alist_name) #define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].metric) /* If metric is modifed return 1. */ int ripng_offset_list_apply_in (struct prefix_ipv6 *p, struct interface *ifp, u_char *metric) { struct ripng_offset_list *offset; struct access_list *alist; /* Look up offset-list with interface name. */ offset = ripng_offset_list_lookup (ifp->name); if (offset && OFFSET_LIST_IN_NAME (offset)) { alist = access_list_lookup (AFI_IP6, 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 = ripng_offset_list_lookup (NULL); if (offset && OFFSET_LIST_IN_NAME (offset)) { alist = access_list_lookup (AFI_IP6, 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 ripng_offset_list_apply_out (struct prefix_ipv6 *p, struct interface *ifp, u_char *metric) { struct ripng_offset_list *offset; struct access_list *alist; /* Look up offset-list with interface name. */ offset = ripng_offset_list_lookup (ifp->name); if (offset && OFFSET_LIST_OUT_NAME (offset)) { alist = access_list_lookup (AFI_IP6, 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 = ripng_offset_list_lookup (NULL); if (offset && OFFSET_LIST_OUT_NAME (offset)) { alist = access_list_lookup (AFI_IP6, 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 (ripng_offset_list, ripng_offset_list_cmd, "offset-list WORD (in|out) <0-16>", "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") { return ripng_offset_list_set (vty, argv[0], argv[1], argv[2], NULL); } DEFUN (ripng_offset_list_ifname, ripng_offset_list_ifname_cmd, "offset-list WORD (in|out) <0-16> IFNAME", "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") { return ripng_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]); } DEFUN (no_ripng_offset_list, no_ripng_offset_list_cmd, "no offset-list WORD (in|out) <0-16>", NO_STR "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") { return ripng_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL); } DEFUN (no_ripng_offset_list_ifname, no_ripng_offset_list_ifname_cmd, "no offset-list WORD (in|out) <0-16> IFNAME", NO_STR "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") { return ripng_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]); } static int offset_list_cmp (struct ripng_offset_list *o1, struct ripng_offset_list *o2) { return strcmp_safe (o1->ifname, o2->ifname); } static void offset_list_del (struct ripng_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); ripng_offset_list_free (offset); } void ripng_offset_init (void) { ripng_offset_list_master = list_new (); ripng_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; ripng_offset_list_master->del = (void (*)(void *)) offset_list_del; install_element (RIPNG_NODE, &ripng_offset_list_cmd); install_element (RIPNG_NODE, &ripng_offset_list_ifname_cmd); install_element (RIPNG_NODE, &no_ripng_offset_list_cmd); install_element (RIPNG_NODE, &no_ripng_offset_list_ifname_cmd); } void ripng_offset_clean (void) { list_delete (ripng_offset_list_master); ripng_offset_list_master = list_new (); ripng_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; ripng_offset_list_master->del = (void (*)(void *)) offset_list_del; } int config_write_ripng_offset_list (struct vty *vty) { struct listnode *node, *nnode; struct ripng_offset_list *offset; for (ALL_LIST_ELEMENTS (ripng_offset_list_master, node, nnode, offset)) { if (! offset->ifname) { if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name) vty_out (vty, " offset-list %s in %d%s", offset->direct[RIPNG_OFFSET_LIST_IN].alist_name, offset->direct[RIPNG_OFFSET_LIST_IN].metric, VTY_NEWLINE); if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name) vty_out (vty, " offset-list %s out %d%s", offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name, offset->direct[RIPNG_OFFSET_LIST_OUT].metric, VTY_NEWLINE); } else { if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name) vty_out (vty, " offset-list %s in %d %s%s", offset->direct[RIPNG_OFFSET_LIST_IN].alist_name, offset->direct[RIPNG_OFFSET_LIST_IN].metric, offset->ifname, VTY_NEWLINE); if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name) vty_out (vty, " offset-list %s out %d %s%s", offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name, offset->direct[RIPNG_OFFSET_LIST_OUT].metric, offset->ifname, VTY_NEWLINE); } } return 0; } quagga-1.2.4/ripngd/ripng_peer.c000066400000000000000000000116121325323223500165450ustar00rootroot00000000000000/* RIPng 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. */ /* RIPng support added by Vincent Jardin * Copyright (C) 2002 6WIND */ #include #include "if.h" #include "prefix.h" #include "command.h" #include "linklist.h" #include "thread.h" #include "memory.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_nexthop.h" /* Linked list of RIPng peer. */ struct list *peer_list; static struct ripng_peer * ripng_peer_new (void) { return XCALLOC (MTYPE_RIPNG_PEER, sizeof (struct ripng_peer)); } static void ripng_peer_free (struct ripng_peer *peer) { XFREE (MTYPE_RIPNG_PEER, peer); } struct ripng_peer * ripng_peer_lookup (struct in6_addr *addr) { struct ripng_peer *peer; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (IPV6_ADDR_SAME (&peer->addr, addr)) return peer; } return NULL; } struct ripng_peer * ripng_peer_lookup_next (struct in6_addr *addr) { struct ripng_peer *peer; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (addr6_cmp(&peer->addr, addr) > 0) return peer; } return NULL; } /* RIPng peer is timeout. * Garbage collector. **/ static int ripng_peer_timeout (struct thread *t) { struct ripng_peer *peer; peer = THREAD_ARG (t); listnode_delete (peer_list, peer); ripng_peer_free (peer); return 0; } /* Get RIPng peer. At the same time update timeout thread. */ static struct ripng_peer * ripng_peer_get (struct in6_addr *addr) { struct ripng_peer *peer; peer = ripng_peer_lookup (addr); if (peer) { if (peer->t_timeout) thread_cancel (peer->t_timeout); } else { peer = ripng_peer_new (); peer->addr = *addr; /* XXX */ listnode_add_sort (peer_list, peer); } /* Update timeout thread. */ peer->t_timeout = thread_add_timer (master, ripng_peer_timeout, peer, RIPNG_PEER_TIMER_DEFAULT); /* Last update time set. */ time (&peer->uptime); return peer; } void ripng_peer_update (struct sockaddr_in6 *from, u_char version) { struct ripng_peer *peer; peer = ripng_peer_get (&from->sin6_addr); peer->version = version; } void ripng_peer_bad_route (struct sockaddr_in6 *from) { struct ripng_peer *peer; peer = ripng_peer_get (&from->sin6_addr); peer->recv_badroutes++; } void ripng_peer_bad_packet (struct sockaddr_in6 *from) { struct ripng_peer *peer; peer = ripng_peer_get (&from->sin6_addr); peer->recv_badpackets++; } /* Display peer uptime. */ static char * ripng_peer_uptime (struct ripng_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 ripng_peer_display (struct vty *vty) { struct ripng_peer *peer; struct listnode *node, *nnode; #define RIPNG_UPTIME_LEN 25 char timebuf[RIPNG_UPTIME_LEN]; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { vty_out (vty, " %s %s%14s %10d %10d %10d %s%s", inet6_ntoa (peer->addr), VTY_NEWLINE, " ", peer->recv_badpackets, peer->recv_badroutes, ZEBRA_RIPNG_DISTANCE_DEFAULT, ripng_peer_uptime (peer, timebuf, RIPNG_UPTIME_LEN), VTY_NEWLINE); } } static int ripng_peer_list_cmp (struct ripng_peer *p1, struct ripng_peer *p2) { return addr6_cmp(&p1->addr, &p2->addr) > 0; } void ripng_peer_init () { peer_list = list_new (); peer_list->cmp = (int (*)(void *, void *)) ripng_peer_list_cmp; } quagga-1.2.4/ripngd/ripng_route.c000066400000000000000000000105551325323223500167550ustar00rootroot00000000000000/* * 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 "vty.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" static 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--; } } /* Aggregate count decrement check for a list. */ void ripng_aggregate_decrement_list (struct route_node *child, struct list *list) { struct route_node *np; struct ripng_aggregate *aggregate; struct ripng_info *rinfo = NULL; struct listnode *node = NULL; for (np = child; np; np = np->parent) if ((aggregate = np->aggregate) != NULL) aggregate->count -= listcount (list); for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) 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; struct list *list = NULL; struct listnode *node = NULL; /* 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 ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) { 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; struct list *list = NULL; struct listnode *node = NULL; /* 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 ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) { 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; } quagga-1.2.4/ripngd/ripng_route.h000066400000000000000000000035171325323223500167620ustar00rootroot00000000000000/* * 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_int16_t tag; /* Route-map futures - this variables can be changed. */ struct in6_addr nexthop_out; u_char metric_set; u_char metric_out; u_int16_t tag_out; }; extern void ripng_aggregate_increment (struct route_node *rp, struct ripng_info *rinfo); extern void ripng_aggregate_decrement (struct route_node *rp, struct ripng_info *rinfo); extern void ripng_aggregate_decrement_list (struct route_node *rp, struct list *list); extern int ripng_aggregate_add (struct prefix *p); extern int ripng_aggregate_delete (struct prefix *p); extern void ripng_aggregate_free (struct ripng_aggregate *aggregate); #endif /* _ZEBRA_RIPNG_ROUTE_H */ quagga-1.2.4/ripngd/ripng_routemap.c000066400000000000000000000402641325323223500174530ustar00rootroot00000000000000/* 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 "sockunion.h" #include "ripngd/ripngd.h" struct rip_metric_modifier { enum { metric_increment, metric_decrement, metric_absolute } type; u_char metric; }; static int ripng_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ripng_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ripng_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ripng_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "RIPng Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "RIPng Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *metric; struct ripng_info *rinfo; if (type == RMAP_RIPNG) { 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 */ static void * route_match_metric_compile (const 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. */ static void route_match_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for metric matching. */ static 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. */ static 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 == RMAP_RIPNG) { ifname = rule; ifp = if_lookup_by_name(ifname); if (!ifp) return RMAP_NOMATCH; rinfo = object; if (rinfo->ifindex == ifp->ifindex) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match interface' match statement. `arg' is IFNAME value */ static void * route_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_interface_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_match_interface_cmd = { "interface", route_match_interface, route_match_interface_compile, route_match_interface_free }; /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; struct ripng_info *rinfo; if (type == RMAP_RIPNG) { tag = rule; rinfo = object; /* The information stored by rinfo is host ordered. */ if (rinfo->tag == *tag) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_map_rule_tag_compile, route_map_rule_tag_free, }; /* `set metric METRIC' */ /* Set metric to attribute. */ static 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_out += mod->metric; else if (mod->type == metric_decrement) rinfo->metric_out-= mod->metric; else if (mod->type == metric_absolute) rinfo->metric_out = mod->metric; if (rinfo->metric_out < 1) rinfo->metric_out = 1; if (rinfo->metric_out > RIPNG_METRIC_INFINITY) rinfo->metric_out = RIPNG_METRIC_INFINITY; rinfo->metric_set = 1; } return RMAP_OKAY; } /* set metric compilation. */ static void * route_set_metric_compile (const char *arg) { int len; const 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; } /* Free route map's compiled `set metric' value. */ static void route_set_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_set_metric_compile, route_set_metric_free, }; /* `set ipv6 next-hop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ static 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 ripng_info *rinfo; if(type == RMAP_RIPNG) { /* Fetch routemap's rule information. */ address = rule; rinfo = object; /* Set next hop value. */ rinfo->nexthop_out = *address; } return RMAP_OKAY; } /* Route map `ipv6 nexthop local' compile function. Given string is converted to struct in6_addr structure. */ static void * route_set_ipv6_nexthop_local_compile (const 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 `ipv6 nexthop local' value. */ static void route_set_ipv6_nexthop_local_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ipv6 nexthop local set. */ static 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 }; /* `set tag TAG' */ /* Set tag to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { route_tag_t *tag; struct ripng_info *rinfo; if(type == RMAP_RIPNG) { /* Fetch routemap's rule information. */ tag = rule; rinfo = object; /* Set next hop value. */ rinfo->tag_out = *tag; } return RMAP_OKAY; } /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, route_map_rule_tag_compile, route_map_rule_tag_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 ripng_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 ripng_route_match_delete (vty, vty->index, "metric", NULL); return ripng_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 ripng_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 ripng_route_match_delete (vty, vty->index, "interface", NULL); return ripng_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_tag, match_tag_cmd, "match tag <1-4294967295>", MATCH_STR "Match tag of route\n" "Metric value\n") { return ripng_route_match_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_match_tag, no_match_tag_cmd, "no match tag", NO_STR MATCH_STR "Match tag of route\n") { if (argc == 0) return ripng_route_match_delete (vty, vty->index, "tag", NULL); return ripng_route_match_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_match_tag, no_match_tag_val_cmd, "no match tag <1-4294967295>", NO_STR MATCH_STR "Match tag of route\n" "Metric value\n") /* set functions */ DEFUN (set_metric, set_metric_cmd, "set metric <0-4294967295>", "Set value\n" "Metric value for destination routing protocol\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") 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") { union sockunion su; int ret; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "%% Malformed next-hop local address%s", VTY_NEWLINE); return CMD_WARNING; } return ripng_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 ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL); return ripng_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") DEFUN (set_tag, set_tag_cmd, "set tag <1-4294967295>", SET_STR "Tag value for routing protocol\n" "Tag value\n") { return ripng_route_set_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_set_tag, no_set_tag_cmd, "no set tag", NO_STR SET_STR "Tag value for routing protocol\n") { if (argc == 0) return ripng_route_set_delete (vty, vty->index, "tag", NULL); return ripng_route_set_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_set_tag, no_set_tag_val_cmd, "no set tag <1-4294967295>", NO_STR SET_STR "Tag value for routing protocol\n" "Tag value\n") void ripng_route_map_reset () { /* XXX ??? */ ; } void ripng_route_map_init () { route_map_init (); route_map_init_vty (); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_interface_cmd); route_map_install_match (&route_match_tag_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); route_map_install_set (&route_set_tag_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_tag_cmd); install_element (RMAP_NODE, &no_match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_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_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); install_element (RMAP_NODE, &set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_val_cmd); } quagga-1.2.4/ripngd/ripng_zebra.c000066400000000000000000000376541325323223500167330ustar00rootroot00000000000000/* * 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 "table.h" #include "stream.h" #include "memory.h" #include "routemap.h" #include "zclient.h" #include "log.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_debug.h" /* All information about zebra. */ struct zclient *zclient = NULL; /* Send ECMP routes to zebra. */ static void ripng_zebra_ipv6_send (struct route_node *rp, u_char cmd) { static struct in6_addr **nexthops = NULL; static ifindex_t *ifindexes = NULL; static unsigned int nexthops_len = 0; struct list *list = (struct list *)rp->info; struct zapi_ipv6 api; struct listnode *listnode = NULL; struct ripng_info *rinfo = NULL; int count = 0; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_RIPNG], VRF_DEFAULT)) { api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_RIPNG; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; if (nexthops_len < listcount (list)) { nexthops_len = listcount (list); nexthops = XREALLOC (MTYPE_TMP, nexthops, nexthops_len * sizeof (struct in6_addr *)); ifindexes = XREALLOC (MTYPE_TMP, ifindexes, nexthops_len * sizeof (unsigned int)); } SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { nexthops[count] = &rinfo->nexthop; ifindexes[count] = rinfo->ifindex; count++; if (cmd == ZEBRA_IPV6_ROUTE_ADD) SET_FLAG (rinfo->flags, RIPNG_RTF_FIB); else UNSET_FLAG (rinfo->flags, RIPNG_RTF_FIB); } api.nexthop = nexthops; api.nexthop_num = count; api.ifindex = ifindexes; api.ifindex_num = count; rinfo = listgetdata (listhead (list)); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = rinfo->metric; if (rinfo->tag) { SET_FLAG (api.message, ZAPI_MESSAGE_TAG); api.tag = rinfo->tag; } zapi_ipv6_route (cmd, zclient, (struct prefix_ipv6 *)&rp->p, &api); if (IS_RIPNG_DEBUG_ZEBRA) { if (ripng->ecmp) zlog_debug ("%s: %s/%d nexthops %d", (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \ "Install into zebra" : "Delete from zebra", inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, count); else zlog_debug ("%s: %s/%d", (cmd == ZEBRA_IPV6_ROUTE_ADD) ? \ "Install into zebra" : "Delete from zebra", inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen); } } } /* Add/update ECMP routes to zebra. */ void ripng_zebra_ipv6_add (struct route_node *rp) { ripng_zebra_ipv6_send (rp, ZEBRA_IPV6_ROUTE_ADD); } /* Delete ECMP routes from zebra. */ void ripng_zebra_ipv6_delete (struct route_node *rp) { ripng_zebra_ipv6_send (rp, ZEBRA_IPV6_ROUTE_DELETE); } /* Zebra route add and delete treatment. */ static int ripng_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex; struct in6_addr nexthop; struct prefix_ipv6 p; unsigned char plength = 0; 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; plength = stream_getc (s); p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, plength); 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 (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) api.tag = stream_getl (s); else api.tag = 0; if (command == ZEBRA_IPV6_ROUTE_ADD) ripng_redistribute_add (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop, api.tag); else ripng_redistribute_delete (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex); return 0; } void ripng_zclient_reset (void) { zclient_reset (zclient); } static int ripng_redistribute_unset (int type) { if (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)) return CMD_SUCCESS; vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT); if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT); ripng_redistribute_withdraw (type); return CMD_SUCCESS; } int ripng_redistribute_check (int type) { return vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT); } static void ripng_redistribute_metric_set (int type, int metric) { ripng->route_map[type].metric_config = 1; ripng->route_map[type].metric = metric; } static int ripng_redistribute_metric_unset (int type) { ripng->route_map[type].metric_config = 0; ripng->route_map[type].metric = 0; return 0; } static void ripng_redistribute_routemap_set (int type, const 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); } static 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; } /* Redistribution types */ static struct { int type; int str_min_len; const char *str; } redist_type[] = { {ZEBRA_ROUTE_KERNEL, 1, "kernel"}, {ZEBRA_ROUTE_CONNECT, 1, "connected"}, {ZEBRA_ROUTE_STATIC, 1, "static"}, {ZEBRA_ROUTE_OSPF6, 1, "ospf6"}, {ZEBRA_ROUTE_BGP, 2, "bgp"}, {ZEBRA_ROUTE_BABEL, 2, "babel"}, {0, 0, NULL} }; void ripng_redistribute_clean () { int i; for (i = 0; redist_type[i].str; i++) { if (vrf_bitmap_check (zclient->redist[redist_type[i].type], VRF_DEFAULT)) { if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, redist_type[i].type, VRF_DEFAULT); vrf_bitmap_unset (zclient->redist[redist_type[i].type], VRF_DEFAULT); /* Remove the routes from RIPng table. */ ripng_redistribute_withdraw (redist_type[i].type); } } } 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") { vrf_bitmap_set (zclient->redist[ZEBRA_ROUTE_RIPNG], VRF_DEFAULT); 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") { vrf_bitmap_unset (zclient->redist[ZEBRA_ROUTE_RIPNG], VRF_DEFAULT); return CMD_SUCCESS; } DEFUN (ripng_redistribute_type, ripng_redistribute_type_cmd, "redistribute " QUAGGA_REDIST_STR_RIPNGD, "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } DEFUN (no_ripng_redistribute_type, no_ripng_redistribute_type_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPNGD, NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_metric_unset (type); ripng_redistribute_routemap_unset (type); return ripng_redistribute_unset (type); } DEFUN (ripng_redistribute_type_metric, ripng_redistribute_type_metric_cmd, "redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16>", "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n") { int type; int metric; metric = atoi (argv[1]); type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_metric_set (type, metric); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_metric_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16>", NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n") DEFUN (ripng_redistribute_type_routemap, ripng_redistribute_type_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_RIPNGD " route-map WORD", "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_routemap_set (type, argv[1]); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_routemap_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPNGD " route-map WORD", NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") DEFUN (ripng_redistribute_type_metric_routemap, ripng_redistribute_type_metric_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16> route-map WORD", "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") { int type; int metric; type = proto_redistnum(AFI_IP6, argv[0]); metric = atoi (argv[1]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_metric_set (type, metric); ripng_redistribute_routemap_set (type, argv[2]); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT); return CMD_SUCCESS; } ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_metric_routemap_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16> route-map WORD", NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") void ripng_redistribute_write (struct vty *vty, int config_mode) { int i; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && vrf_bitmap_check (zclient->redist[i], VRF_DEFAULT)) { if (config_mode) { if (ripng->route_map[i].metric_config) { if (ripng->route_map[i].name) vty_out (vty, " redistribute %s metric %d route-map %s%s", zebra_route_string(i), ripng->route_map[i].metric, ripng->route_map[i].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s metric %d%s", zebra_route_string(i), ripng->route_map[i].metric, VTY_NEWLINE); } else { if (ripng->route_map[i].name) vty_out (vty, " redistribute %s route-map %s%s", zebra_route_string(i), ripng->route_map[i].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s%s", zebra_route_string(i), VTY_NEWLINE); } } else vty_out (vty, " %s", zebra_route_string(i)); } } /* RIPng configuration write function. */ static int zebra_config_write (struct vty *vty) { if (! zclient->enable) { vty_out (vty, "no router zebra%s", VTY_NEWLINE); return 1; } else if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_RIPNG], VRF_DEFAULT)) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute ripng%s", VTY_NEWLINE); return 1; } return 0; } /* Zebra node structure. */ static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# ", }; static void ripng_zebra_connected (struct zclient *zclient) { zclient_send_requests (zclient, VRF_DEFAULT); } /* Initialize zebra structure and it's commands. */ void zebra_init (struct thread_master *master) { /* Allocate zebra structure. */ zclient = zclient_new (master); zclient_init (zclient, ZEBRA_ROUTE_RIPNG); zclient->zebra_connected = ripng_zebra_connected; 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 command elements to ripng node */ install_element (RIPNG_NODE, &ripng_redistribute_type_cmd); install_element (RIPNG_NODE, &ripng_redistribute_type_routemap_cmd); install_element (RIPNG_NODE, &ripng_redistribute_type_metric_cmd); install_element (RIPNG_NODE, &ripng_redistribute_type_metric_routemap_cmd); install_element (RIPNG_NODE, &no_ripng_redistribute_type_cmd); install_element (RIPNG_NODE, &no_ripng_redistribute_type_routemap_cmd); install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_cmd); install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_routemap_cmd); } quagga-1.2.4/ripngd/ripngd.c000066400000000000000000002432171325323223500157060ustar00rootroot00000000000000/* 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 #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 "if_rmap.h" #include "privs.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" /* 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, }; extern struct zebra_privs_t ripngd_privs; /* Prototypes. */ void ripng_output_process (struct interface *, struct sockaddr_in6 *, 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; }; static int ripng_route_rte (struct ripng_info *rinfo) { return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE); } /* 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); } /* Create ripng socket. */ static 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; #ifdef IPTOS_PREC_INTERNETCONTROL ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); if (ret < 0) return ret; #endif 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); if (ripngd_privs.change (ZPRIVS_RAISE)) zlog_err ("ripng_make_socket: could not raise privs"); ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr)); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno)); if (ripngd_privs.change (ZPRIVS_LOWER)) zlog_err ("ripng_make_socket: could not lower privs"); return ret; } if (ripngd_privs.change (ZPRIVS_LOWER)) zlog_err ("ripng_make_socket: could not lower privs"); 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; if (IS_RIPNG_DEBUG_SEND) { if (to) zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr)); zlog_debug (" send interface %s", ifp->name); zlog_debug (" send packet size %d", bufsize); } 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) { if (to) zlog_err ("RIPng send fail on %s to %s: %s", ifp->name, inet6_ntoa (to->sin6_addr), safe_strerror (errno)); else zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno)); } return ret; } /* Receive UDP RIPng packet from socket. */ static int ripng_recv_packet (int sock, u_char *buf, int bufsize, struct sockaddr_in6 *from, ifindex_t *ifindex, int *hoplimit) { int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; struct in6_addr dst = { .s6_addr = { 0 } }; /* 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 = ZCMSG_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) { int *phoplimit = (int *) CMSG_DATA (cmsgptr); *hoplimit = *phoplimit; } } /* 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, const char *sndrcv) { caddr_t lim; struct rte *rte; const 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_debug ("%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_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen); else zlog_debug (" %s/%d metric %d tag %d", inet6_ntoa (rte->addr), rte->prefixlen, rte->metric, ntohs (rte->tag)); } } /* RIPng next hop address RTE (Route Table Entry). */ static 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_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d", inet6_ntoa (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_ntoa (from->sin6_addr)); if (rte->prefixlen != 0) zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s", rte->prefixlen, inet6_ntoa (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_ntoa (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. */ static int ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr) { struct listnode *node; struct connected *connected; struct prefix *p; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { 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. */ static 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; /* Unlock route_node. */ listnode_delete (rp->info, rinfo); if (list_isempty ((struct list *)rp->info)) { list_free (rp->info); rp->info = NULL; route_unlock_node (rp); } /* Free RIPng routing information. */ ripng_info_free (rinfo); return 0; } static void ripng_timeout_update (struct ripng_info *rinfo); /* Add new route to the ECMP list. * RETURN: the new entry added in the list, or NULL if it is not the first * entry and ECMP is not allowed. */ struct ripng_info * ripng_ecmp_add (struct ripng_info *rinfo_new) { struct route_node *rp = rinfo_new->rp; struct ripng_info *rinfo = NULL; struct list *list = NULL; if (rp->info == NULL) rp->info = list_new (); list = (struct list *)rp->info; /* If ECMP is not allowed and some entry already exists in the list, * do nothing. */ if (listcount (list) && !ripng->ecmp) return NULL; rinfo = ripng_info_new (); memcpy (rinfo, rinfo_new, sizeof (struct ripng_info)); listnode_add (list, rinfo); if (ripng_route_rte (rinfo)) { ripng_timeout_update (rinfo); ripng_zebra_ipv6_add (rp); } ripng_aggregate_increment (rp, rinfo); /* Set the route change flag on the first entry. */ rinfo = listgetdata (listhead (list)); SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); /* Signal the output process to trigger an update. */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); return rinfo; } /* Replace the ECMP list with the new route. * RETURN: the new entry added in the list */ struct ripng_info * ripng_ecmp_replace (struct ripng_info *rinfo_new) { struct route_node *rp = rinfo_new->rp; struct list *list = (struct list *)rp->info; struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL; struct listnode *node = NULL, *nextnode = NULL; if (list == NULL || listcount (list) == 0) return ripng_ecmp_add (rinfo_new); /* Get the first entry */ rinfo = listgetdata (listhead (list)); /* Learnt route replaced by a local one. Delete it from zebra. */ if (ripng_route_rte (rinfo) && !ripng_route_rte (rinfo_new)) if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB)) ripng_zebra_ipv6_delete (rp); if (rinfo->metric != RIPNG_METRIC_INFINITY) ripng_aggregate_decrement_list (rp, list); /* Re-use the first entry, and delete the others. */ for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) if (tmp_rinfo != rinfo) { RIPNG_TIMER_OFF (tmp_rinfo->t_timeout); RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect); list_delete_node (list, node); ripng_info_free (tmp_rinfo); } RIPNG_TIMER_OFF (rinfo->t_timeout); RIPNG_TIMER_OFF (rinfo->t_garbage_collect); memcpy (rinfo, rinfo_new, sizeof (struct ripng_info)); if (ripng_route_rte (rinfo)) { ripng_timeout_update (rinfo); /* The ADD message implies an update. */ ripng_zebra_ipv6_add (rp); } ripng_aggregate_increment (rp, rinfo); /* Set the route change flag. */ SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); /* Signal the output process to trigger an update. */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); return rinfo; } /* Delete one route from the ECMP list. * RETURN: * null - the entry is freed, and other entries exist in the list * the entry - the entry is the last one in the list; its metric is set * to INFINITY, and the garbage collector is started for it */ struct ripng_info * ripng_ecmp_delete (struct ripng_info *rinfo) { struct route_node *rp = rinfo->rp; struct list *list = (struct list *)rp->info; RIPNG_TIMER_OFF (rinfo->t_timeout); if (rinfo->metric != RIPNG_METRIC_INFINITY) ripng_aggregate_decrement (rp, rinfo); if (listcount (list) > 1) { /* Some other ECMP entries still exist. Just delete this entry. */ RIPNG_TIMER_OFF (rinfo->t_garbage_collect); listnode_delete (list, rinfo); if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB)) /* The ADD message implies the update. */ ripng_zebra_ipv6_add (rp); ripng_info_free (rinfo); rinfo = NULL; } else { assert (rinfo == listgetdata (listhead (list))); /* This is the only entry left in the list. We must keep it in * the list for garbage collection time, with INFINITY metric. */ rinfo->metric = RIPNG_METRIC_INFINITY; RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB)) ripng_zebra_ipv6_delete (rp); } /* Set the route change flag on the first entry. */ rinfo = listgetdata (listhead (list)); SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); /* Signal the output process to trigger an update. */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); return rinfo; } /* Timeout RIPng routes. */ static int ripng_timeout (struct thread *t) { ripng_ecmp_delete ((struct ripng_info *)THREAD_ARG (t)); return 0; } static 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); } } static int ripng_filter (int ripng_distribute, struct prefix_ipv6 *p, struct ripng_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; int distribute = ripng_distribute == RIPNG_FILTER_OUT ? DISTRIBUTE_V6_OUT : DISTRIBUTE_V6_IN; const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in"; /* Input distribute-list filtering. */ if (ri->list[ripng_distribute]) { if (access_list_apply (ri->list[ripng_distribute], (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute %s", inet6_ntoa (p->prefix), p->prefixlen, inout); return -1; } } if (ri->prefix[ripng_distribute]) { if (prefix_list_apply (ri->prefix[ripng_distribute], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list %s", inet6_ntoa (p->prefix), p->prefixlen, inout); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[distribute]) { alist = access_list_lookup (AFI_IP6, dist->list[distribute]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute %s", inet6_ntoa (p->prefix), p->prefixlen, inout); return -1; } } } if (dist->prefix[distribute]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]); if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list %s", inet6_ntoa (p->prefix), p->prefixlen, inout); return -1; } } } } return 0; } /* Process RIPng route according to RFC2080. */ static void ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, struct ripng_nexthop *ripng_nexthop, struct interface *ifp) { int ret; struct prefix_ipv6 p; struct route_node *rp; struct ripng_info *rinfo = NULL, newinfo; struct ripng_interface *ri; struct in6_addr *nexthop; int same = 0; struct list *list = NULL; struct listnode *node = NULL; /* 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; ret = ripng_filter (RIPNG_FILTER_IN, &p, ri); if (ret < 0) return; memset (&newinfo, 0, sizeof (newinfo)); newinfo.type = ZEBRA_ROUTE_RIPNG; newinfo.sub_type = RIPNG_ROUTE_RTE; if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) newinfo.nexthop = ripng_nexthop->address; else newinfo.nexthop = from->sin6_addr; newinfo.from = from->sin6_addr; newinfo.ifindex = ifp->ifindex; newinfo.metric = rte->metric; newinfo.metric_out = rte->metric; /* XXX */ newinfo.tag = ntohs (rte->tag); /* XXX */ /* Modify entry. */ if (ri->routemap[RIPNG_FILTER_IN]) { int ret; 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_debug ("RIPng %s/%d is filtered by route-map in", inet6_ntoa (p.prefix), p.prefixlen); return; } /* Get back the object */ if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) { if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) { /* the nexthop get changed by the routemap */ if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) ripng_nexthop->address = newinfo.nexthop; else ripng_nexthop->address = in6addr_any; } } else { if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) { /* the nexthop get changed by the routemap */ if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) { ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS; ripng_nexthop->address = newinfo.nexthop; } } } rte->tag = htons(newinfo.tag_out); /* XXX */ rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */ } /* 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 ripngd can handle offset-list in. */ ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric); /* If offset-list does not modify the metric use interface's * one. */ if (! ret) rte->metric += ifp->metric ? ifp->metric : 1; if (rte->metric > RIPNG_METRIC_INFINITY) rte->metric = RIPNG_METRIC_INFINITY; /* 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); newinfo.rp = rp; newinfo.nexthop = *nexthop; newinfo.metric = rte->metric; newinfo.tag = ntohs (rte->tag); /* Check to see whether there is already RIPng route on the table. */ if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) { /* Need to compare with redistributed entry or local entry */ if (!ripng_route_rte (rinfo)) break; if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) && IPV6_ADDR_SAME (&rinfo->nexthop, nexthop)) break; if (!listnextnode (node)) { /* Not found in the list */ if (rte->metric > rinfo->metric) { /* New route has a greater metric. Discard it. */ route_unlock_node (rp); return; } if (rte->metric < rinfo->metric) /* New route has a smaller metric. Replace the ECMP list * with the new one in below. */ break; /* Metrics are same. Keep "rinfo" null and the new route * is added in the ECMP list in below. */ } } if (rinfo) { /* Redistributed route check. */ if (rinfo->type != ZEBRA_ROUTE_RIPNG && rinfo->metric != RIPNG_METRIC_INFINITY) { route_unlock_node (rp); return; } /* Local static route. */ if (rinfo->type == ZEBRA_ROUTE_RIPNG && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) && rinfo->metric != RIPNG_METRIC_INFINITY) { route_unlock_node (rp); 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 != RIPNG_METRIC_INFINITY) ripng_ecmp_add (&newinfo); } else { /* 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)); /* 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) { if (listcount (list) == 1) { if (newinfo.metric != RIPNG_METRIC_INFINITY) ripng_ecmp_replace (&newinfo); else ripng_ecmp_delete (rinfo); } else { if (newinfo.metric < rinfo->metric) ripng_ecmp_replace (&newinfo); else /* newinfo.metric > rinfo->metric */ ripng_ecmp_delete (rinfo); } } else /* same & no change */ ripng_timeout_update (rinfo); /* 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, ifindex_t ifindex, struct in6_addr *nexthop, route_tag_t tag) { struct route_node *rp; struct ripng_info *rinfo = NULL, newinfo; struct list *list = NULL; /* 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); memset (&newinfo, 0, sizeof (struct ripng_info)); newinfo.type = type; newinfo.sub_type = sub_type; newinfo.ifindex = ifindex; newinfo.metric = 1; if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */ newinfo.tag = tag; newinfo.rp = rp; if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop)) newinfo.nexthop = *nexthop; if ((list = rp->info) != NULL && listcount (list) != 0) { rinfo = listgetdata (listhead (list)); if (rinfo->type == ZEBRA_ROUTE_CONNECT && rinfo->sub_type == RIPNG_ROUTE_INTERFACE && rinfo->metric != RIPNG_METRIC_INFINITY) { route_unlock_node (rp); return; } /* Manually configured RIPng route check. * They have the precedence on all the other entries. **/ if (rinfo->type == ZEBRA_ROUTE_RIPNG && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) { if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) && (sub_type != RIPNG_ROUTE_DEFAULT))) { route_unlock_node (rp); return; } } rinfo = ripng_ecmp_replace (&newinfo); route_unlock_node (rp); } else rinfo = ripng_ecmp_add (&newinfo); if (IS_RIPNG_DEBUG_EVENT) { if (!nexthop) zlog_debug ("Redistribute new prefix %s/%d on the interface %s", inet6_ntoa(p->prefix), p->prefixlen, ifindex2ifname(ifindex)); else zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s", inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop), ifindex2ifname(ifindex)); } ripng_event (RIPNG_TRIGGERED_UPDATE, 0); } /* Delete redistributed route to RIPng table. */ void ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, ifindex_t 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) { struct list *list = rp->info; if (list != NULL && listcount (list) != 0) { rinfo = listgetdata (listhead (list)); if (rinfo != NULL && rinfo->type == type && rinfo->sub_type == sub_type && rinfo->ifindex == ifindex) { /* Perform poisoned reverse. */ rinfo->metric = RIPNG_METRIC_INFINITY; RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); RIPNG_TIMER_OFF (rinfo->t_timeout); /* Aggregate count decrement. */ ripng_aggregate_decrement (rp, rinfo); rinfo->flags |= RIPNG_RTF_CHANGED; if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("Poisone %s/%d on the interface %s with an " "infinity metric [delete]", inet6_ntoa (p->prefix), p->prefixlen, ifindex2ifname (ifindex)); ripng_event (RIPNG_TRIGGERED_UPDATE, 0); } } route_unlock_node (rp); } } /* Withdraw redistributed route. */ void ripng_redistribute_withdraw (int type) { struct route_node *rp; struct ripng_info *rinfo = NULL; struct list *list = NULL; if (!ripng) return; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) { rinfo = listgetdata (listhead (list)); if ((rinfo->type == type) && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE)) { /* Perform poisoned reverse. */ rinfo->metric = RIPNG_METRIC_INFINITY; RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); RIPNG_TIMER_OFF (rinfo->t_timeout); /* Aggregate count decrement. */ ripng_aggregate_decrement (rp, rinfo); rinfo->flags |= RIPNG_RTF_CHANGED; if (IS_RIPNG_DEBUG_EVENT) { struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p; zlog_debug ("Poisone %s/%d on the interface %s [withdraw]", inet6_ntoa(p->prefix), p->prefixlen, ifindex2ifname(rinfo->ifindex)); } ripng_event (RIPNG_TRIGGERED_UPDATE, 0); } } } /* RIP routing information. */ static 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_ntoa (from->sin6_addr)); ripng_peer_bad_packet (from); 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_ntoa (from->sin6_addr)); ripng_peer_bad_packet (from); 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_ntoa (from->sin6_addr)); ripng_peer_bad_packet (from); 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_ntoa (from->sin6_addr)); ripng_peer_bad_packet (from); return; } /* Update RIPng peer. */ ripng_peer_update (from, packet->version); /* 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_ntoa (rte->addr), rte->prefixlen, rte->metric); ripng_peer_bad_route (from); continue; } if (IN6_IS_ADDR_LINKLOCAL (&rte->addr)) { zlog_warn ("Destination prefix is a link-local address %s/%d [%d]", inet6_ntoa (rte->addr), rte->prefixlen, rte->metric); ripng_peer_bad_route (from); continue; } if (IN6_IS_ADDR_LOOPBACK (&rte->addr)) { zlog_warn ("Destination prefix is a loopback address %s/%d [%d]", inet6_ntoa (rte->addr), rte->prefixlen, rte->metric); ripng_peer_bad_route (from); 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_ntoa (rte->addr), rte->prefixlen, inet6_ntoa (from->sin6_addr), ifp->name); ripng_peer_bad_route (from); 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_ntoa (from->sin6_addr), ifp->name); ripng_peer_bad_route (from); continue; } /* Vincent: XXX Should we compute the direclty reachable nexthop * for our RIPng network ? **/ /* Routing table updates. */ ripng_route_process (rte, from, &nexthop, ifp); } } /* Response to request message. */ static 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; /* Does not reponse to the requests on the loopback interfaces */ if (if_is_loopback (ifp)) return; /* 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; /* RIPng peer update. */ ripng_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 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); } 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 = listgetdata (listhead ((struct list *)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. */ static int ripng_read (struct thread *thread) { int len; int sock; struct sockaddr_in6 from; struct ripng_packet *packet; ifindex_t ifindex = 0; 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.", safe_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_ntoa (from.sin6_addr)); ripng_peer_bad_packet (&from); 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_debug ("RIPng packet received from %s port %d on %s", inet6_ntoa (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); ripng_peer_bad_packet (&from); 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); ripng_peer_bad_packet (&from); break; } return 0; } /* Walk down the RIPng routing table then clear changed flag. */ static void ripng_clear_changed_flag (void) { struct route_node *rp; struct ripng_info *rinfo = NULL; struct list *list = NULL; struct listnode *listnode = NULL; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); /* This flag can be set only on the first entry. */ break; } } /* Regular update of RIPng route. Send all routing formation to RIPng enabled interface. */ static int ripng_update (struct thread *t) { struct 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_debug ("RIPng update timer expired!"); /* Supply routes to each interface. */ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { 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_DEBUG, "[Event] RIPng send to if %d is suppressed by config", ifp->ifindex); continue; } #endif /* RIPNG_ADVANCED */ ripng_output_process (ifp, NULL, ripng_all_route); } /* 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. */ static 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) { struct 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_debug ("RIPng triggered update!"); /* Split Horizon processing is done when generating triggered updates as well as normal updates (see section 2.6). */ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { 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); } /* 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, struct in6_addr *nexthop, 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. */ if (!nexthop) stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr)); else stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr)); stream_putw (s, tag); if (p) stream_putc (s, p->prefixlen); else stream_putc (s, 0); 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 ret; struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; struct ripng_aggregate *aggregate; struct prefix_ipv6 *p; struct list * ripng_rte_list; struct list *list = NULL; struct listnode *listnode = NULL; if (IS_RIPNG_DEBUG_EVENT) { if (to) zlog_debug ("RIPng update routes to neighbor %s", inet6_ntoa(to->sin6_addr)); else zlog_debug ("RIPng update routes on interface %s", ifp->name); } /* Get RIPng interface. */ ri = ifp->info; ripng_rte_list = ripng_rte_new(); for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { if ((list = rp->info) != NULL && (rinfo = listgetdata (listhead (list))) != NULL && rinfo->suppress == 0) { /* If no route-map are applied, the RTE will be these following * informations. */ p = (struct prefix_ipv6 *) &rp->p; rinfo->metric_out = rinfo->metric; rinfo->tag_out = rinfo->tag; memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out)); /* In order to avoid some local loops, * if the RIPng 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. */ if (rinfo->ifindex == ifp->ifindex) rinfo->nexthop_out = rinfo->nexthop; /* Apply output filters. */ ret = ripng_filter (RIPNG_FILTER_OUT, p, ri); if (ret < 0) continue; /* Changed route only output. */ if (route_type == ripng_changed_route && (! (rinfo->flags & RIPNG_RTF_CHANGED))) continue; /* Split horizon. */ if (ri->split_horizon == RIPNG_SPLIT_HORIZON) { /* We perform split horizon for RIPng routes. */ int suppress = 0; struct ripng_info *tmp_rinfo = NULL; for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG && tmp_rinfo->ifindex == ifp->ifindex) { suppress = 1; break; } if (suppress) continue; } /* Preparation for route-map. */ rinfo->metric_set = 0; /* nexthop_out, * metric_out * and tag_out are already initialized. */ /* Interface route-map */ if (ri->routemap[RIPNG_FILTER_OUT]) { int ret; ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], (struct prefix *) p, RMAP_RIPNG, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("RIPng %s/%d is filtered by route-map out", inet6_ntoa (p->prefix), p->prefixlen); continue; } } /* Redistribute route-map. */ if (ripng->route_map[rinfo->type].name) { int ret; ret = route_map_apply (ripng->route_map[rinfo->type].map, (struct prefix *) p, RMAP_RIPNG, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("RIPng %s/%d is filtered by route-map", inet6_ntoa (p->prefix), p->prefixlen); continue; } } /* When the route-map does not set metric. */ if (! rinfo->metric_set) { /* If the redistribute metric is set. */ if (ripng->route_map[rinfo->type].metric_config && rinfo->metric != RIPNG_METRIC_INFINITY) { rinfo->metric_out = 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) rinfo->metric_out = ripng->default_metric; } } /* Apply offset-list */ if (rinfo->metric_out != RIPNG_METRIC_INFINITY) ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out); if (rinfo->metric_out > RIPNG_METRIC_INFINITY) rinfo->metric_out = RIPNG_METRIC_INFINITY; /* Perform split-horizon with poisoned reverse * for RIPng routes. **/ if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) { struct ripng_info *tmp_rinfo = NULL; for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) && tmp_rinfo->ifindex == ifp->ifindex) rinfo->metric_out = RIPNG_METRIC_INFINITY; } /* Add RTE to the list */ ripng_rte_add(ripng_rte_list, p, rinfo, NULL); } /* Process the aggregated RTE entry */ if ((aggregate = rp->aggregate) != NULL && aggregate->count > 0 && aggregate->suppress == 0) { /* If no route-map are applied, the RTE will be these following * informations. */ p = (struct prefix_ipv6 *) &rp->p; aggregate->metric_set = 0; aggregate->metric_out = aggregate->metric; aggregate->tag_out = aggregate->tag; memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out)); /* Apply output filters.*/ ret = ripng_filter (RIPNG_FILTER_OUT, p, ri); if (ret < 0) continue; /* Interface route-map */ if (ri->routemap[RIPNG_FILTER_OUT]) { int ret; struct ripng_info newinfo; /* let's cast the aggregate structure to ripng_info */ memset (&newinfo, 0, sizeof (struct ripng_info)); /* the nexthop is :: */ newinfo.metric = aggregate->metric; newinfo.metric_out = aggregate->metric_out; newinfo.tag = aggregate->tag; newinfo.tag_out = aggregate->tag_out; 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_debug ("RIPng %s/%d is filtered by route-map out", inet6_ntoa (p->prefix), p->prefixlen); continue; } aggregate->metric_out = newinfo.metric_out; aggregate->tag_out = newinfo.tag_out; if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out)) aggregate->nexthop_out = newinfo.nexthop_out; } /* There is no redistribute routemap for the aggregated RTE */ /* Changed route only output. */ /* XXX, vincent, in order to increase time convergence, * it should be announced if a child has changed. */ if (route_type == ripng_changed_route) continue; /* Apply offset-list */ if (aggregate->metric_out != RIPNG_METRIC_INFINITY) ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out); if (aggregate->metric_out > RIPNG_METRIC_INFINITY) aggregate->metric_out = RIPNG_METRIC_INFINITY; /* Add RTE to the list */ ripng_rte_add(ripng_rte_list, p, NULL, aggregate); } } /* Flush the list */ ripng_rte_send(ripng_rte_list, ifp, to); ripng_rte_free(ripng_rte_list); } /* Create new RIPng instance and set it to global variable. */ static int ripng_create (void) { /* ripng should be NULL. */ assert (ripng == NULL); /* Allocaste RIPng instance. */ ripng = XCALLOC (MTYPE_RIPNG, 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; } /* Send RIPng request to the interface. */ int ripng_request (struct interface *ifp) { struct rte *rte; struct ripng_packet ripng_packet; /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */ if (if_is_loopback(ifp)) return 0; /* If interface is down, don't send RIP packet. */ if (! if_is_up (ifp)) return 0; if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("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); } static int ripng_update_jitter (int time) { return ((random () % (time + 1)) - (time / 2)); } void ripng_event (enum ripng_event event, int sock) { 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; } } /* Print out routes update time. */ static void ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo) { time_t clock; struct tm *tm; #define TIME_BUF 25 char timebuf [TIME_BUF]; struct thread *thread; if ((thread = rinfo->t_timeout) != NULL) { clock = thread_timer_remain_second (thread); 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_timer_remain_second (thread); tm = gmtime (&clock); strftime (timebuf, TIME_BUF, "%M:%S", tm); vty_out (vty, "%5s", timebuf); } } static char * ripng_route_subtype_print (struct ripng_info *rinfo) { static char str[3]; memset(str, 0, 3); if (rinfo->suppress) strcat(str, "S"); switch (rinfo->sub_type) { case RIPNG_ROUTE_RTE: strcat(str, "n"); break; case RIPNG_ROUTE_STATIC: strcat(str, "s"); break; case RIPNG_ROUTE_DEFAULT: strcat(str, "d"); break; case RIPNG_ROUTE_REDISTRIBUTE: strcat(str, "r"); break; case RIPNG_ROUTE_INTERFACE: strcat(str, "i"); break; default: strcat(str, "?"); break; } return str; } DEFUN (show_ipv6_ripng, show_ipv6_ripng_cmd, "show ipv6 ripng", SHOW_STR IPV6_STR "Show RIPng routes\n") { struct route_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct prefix_ipv6 *p; struct list *list = NULL; struct listnode *listnode = NULL; int len; if (! ripng) return CMD_SUCCESS; /* Header of display. */ vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s" "Sub-codes:%s" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" " (i) - interface, (a/S) - aggregated/Suppressed%s%s" " Network Next Hop Via Metric Tag Time%s", VTY_NEWLINE, VTY_NEWLINE, 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, "R(a) %d/%d %s/%d ", aggregate->count, aggregate->suppress, inet6_ntoa (p->prefix), p->prefixlen); #else len = vty_out (vty, "R(a) %s/%d ", inet6_ntoa (p->prefix), p->prefixlen); #endif /* DEBUG */ vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%*s", 18, " "); vty_out (vty, "%*s", 28, " "); vty_out (vty, "self %2d %3d%s", aggregate->metric, aggregate->tag, VTY_NEWLINE); } if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { p = (struct prefix_ipv6 *) &rp->p; #ifdef DEBUG len = vty_out (vty, "%c(%s) 0/%d %s/%d ", zebra_route_char(rinfo->type), ripng_route_subtype_print(rinfo), rinfo->suppress, inet6_ntoa (p->prefix), p->prefixlen); #else len = vty_out (vty, "%c(%s) %s/%d ", zebra_route_char(rinfo->type), ripng_route_subtype_print(rinfo), inet6_ntoa (p->prefix), p->prefixlen); #endif /* DEBUG */ vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%*s", 18, " "); len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop)); len = 28 - len; if (len > 0) len = vty_out (vty, "%*s", len, " "); /* from */ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && (rinfo->sub_type == RIPNG_ROUTE_RTE)) { len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex)); } else if (rinfo->metric == RIPNG_METRIC_INFINITY) { len = vty_out (vty, "kill"); } else len = vty_out (vty, "self"); len = 9 - len; if (len > 0) vty_out (vty, "%*s", len, " "); vty_out (vty, " %2d %3d ", rinfo->metric, rinfo->tag); /* time */ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && (rinfo->sub_type == RIPNG_ROUTE_RTE)) { /* RTE from remote RIP routers */ ripng_vty_out_uptime (vty, rinfo); } else if (rinfo->metric == RIPNG_METRIC_INFINITY) { /* poisonous reversed routes (gc) */ ripng_vty_out_uptime (vty, rinfo); } vty_out (vty, "%s", VTY_NEWLINE); } } return CMD_SUCCESS; } DEFUN (show_ipv6_ripng_status, show_ipv6_ripng_status_cmd, "show ipv6 ripng status", SHOW_STR IPV6_STR "Show RIPng routes\n" "IPv6 routing protocol process parameters and statistics\n") { struct listnode *node; struct interface *ifp; if (! ripng) return CMD_SUCCESS; vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE); vty_out (vty, " Sending updates every %ld seconds with +/-50%%,", ripng->update_time); vty_out (vty, " next due in %lu seconds%s", thread_timer_remain_second (ripng->t_update), VTY_NEWLINE); vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time); vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time, VTY_NEWLINE); /* Filtering status show. */ config_show_distribute (vty); /* Default metric information. */ vty_out (vty, " Default redistribution metric is %d%s", ripng->default_metric, VTY_NEWLINE); /* Redistribute information. */ vty_out (vty, " Redistributing:"); ripng_redistribute_write (vty, 0); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Default version control: send version %d,", ripng->version); vty_out (vty, " receive version %d %s", ripng->version, VTY_NEWLINE); vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct ripng_interface *ri; ri = ifp->info; if (ri->enable_network || ri->enable_interface) { vty_out (vty, " %-17s%-3d %-3d%s", ifp->name, ripng->version, ripng->version, VTY_NEWLINE); } } vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE); ripng_network_write (vty, 0); vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE); vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE); ripng_peer_display (vty); 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 (no_router_ripng, no_router_ripng_cmd, "no router ripng", NO_STR "Enable a routing process\n" "Make RIPng instance command\n") { if(ripng) ripng_clean(); 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, NULL, 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") #if 0 /* RIPng update timer setup. */ DEFUN (ripng_update_timer, ripng_update_timer_cmd, "update-timer SECOND", "Set RIPng update timer in seconds\n" "Seconds\n") { unsigned long update; 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; } ripng->update_time = update; ripng_event (RIPNG_UPDATE_EVENT, 0); return CMD_SUCCESS; } DEFUN (no_ripng_update_timer, no_ripng_update_timer_cmd, "no update-timer SECOND", NO_STR "Unset RIPng update timer in seconds\n" "Seconds\n") { ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT; ripng_event (RIPNG_UPDATE_EVENT, 0); return CMD_SUCCESS; } /* RIPng timeout timer setup. */ DEFUN (ripng_timeout_timer, ripng_timeout_timer_cmd, "timeout-timer SECOND", "Set RIPng timeout timer in seconds\n" "Seconds\n") { unsigned long timeout; char *endptr = NULL; timeout = strtoul (argv[0], &endptr, 10); if (timeout == ULONG_MAX || *endptr != '\0') { vty_out (vty, "timeout timer value error%s", VTY_NEWLINE); return CMD_WARNING; } ripng->timeout_time = timeout; return CMD_SUCCESS; } DEFUN (no_ripng_timeout_timer, no_ripng_timeout_timer_cmd, "no timeout-timer SECOND", NO_STR "Unset RIPng timeout timer in seconds\n" "Seconds\n") { ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT; return CMD_SUCCESS; } /* RIPng garbage timer setup. */ DEFUN (ripng_garbage_timer, ripng_garbage_timer_cmd, "garbage-timer SECOND", "Set RIPng garbage timer in seconds\n" "Seconds\n") { unsigned long garbage; char *endptr = NULL; garbage = strtoul (argv[0], &endptr, 10); if (garbage == ULONG_MAX || *endptr != '\0') { vty_out (vty, "garbage timer value error%s", VTY_NEWLINE); return CMD_WARNING; } ripng->garbage_time = garbage; return CMD_SUCCESS; } DEFUN (no_ripng_garbage_timer, no_ripng_garbage_timer_cmd, "no garbage-timer SECOND", NO_STR "Unset RIPng garbage timer in seconds\n" "Seconds\n") { ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT; return CMD_SUCCESS; } #endif /* 0 */ 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; VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535); VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535); VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535); /* 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; } ALIAS (no_ripng_timers, no_ripng_timers_val_cmd, "no timers basic <0-65535> <0-65535> <0-65535>", NO_STR "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") DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd, "show ipv6 protocols", SHOW_STR IPV6_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; if (! ripng ->default_information) { ripng->default_information = 1; str2prefix_ipv6 ("::/0", &p); ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 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; if (ripng->default_information) { ripng->default_information = 0; str2prefix_ipv6 ("::/0", &p); ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0); } return CMD_SUCCESS; } /* Update ECMP routes to zebra when ECMP is disabled. */ static void ripng_ecmp_disable (void) { struct route_node *rp; struct ripng_info *rinfo, *tmp_rinfo; struct list *list; struct listnode *node, *nextnode; if (!ripng) return; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL && listcount (list) > 1) { rinfo = listgetdata (listhead (list)); if (!ripng_route_rte (rinfo)) continue; /* Drop all other entries, except the first one. */ for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) if (tmp_rinfo != rinfo) { RIPNG_TIMER_OFF (tmp_rinfo->t_timeout); RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect); list_delete_node (list, node); ripng_info_free (tmp_rinfo); } /* Update zebra. */ ripng_zebra_ipv6_add (rp); /* Set the route change flag. */ SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED); /* Signal the output process to trigger an update. */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); } } DEFUN (ripng_allow_ecmp, ripng_allow_ecmp_cmd, "allow-ecmp", "Allow Equal Cost MultiPath\n") { if (ripng->ecmp) { vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE); return CMD_WARNING; } ripng->ecmp = 1; zlog_info ("ECMP is enabled."); return CMD_SUCCESS; } DEFUN (no_ripng_allow_ecmp, no_ripng_allow_ecmp_cmd, "no allow-ecmp", NO_STR "Allow Equal Cost MultiPath\n") { if (!ripng->ecmp) { vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE); return CMD_WARNING; } ripng->ecmp = 0; zlog_info ("ECMP is disabled."); ripng_ecmp_disable (); return CMD_SUCCESS; } /* RIPng configuration write function. */ static int ripng_config_write (struct vty *vty) { int ripng_network_write (struct vty *, int); void ripng_redistribute_write (struct vty *, int); 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, 1); /* 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, 1); /* RIP offset-list configuration. */ config_write_ripng_offset_list (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_ntoa (rp->p.u.prefix6), rp->p.prefixlen, VTY_NEWLINE); /* ECMP configuration. */ if (ripng->ecmp) vty_out (vty, " allow-ecmp%s", 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_ntoa (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); } #if 0 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT) vty_out (vty, " update-timer %d%s", ripng->update_time, VTY_NEWLINE); if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT) vty_out (vty, " timeout-timer %d%s", ripng->timeout_time, VTY_NEWLINE); if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT) vty_out (vty, " garbage-timer %d%s", ripng->garbage_time, VTY_NEWLINE); #endif /* 0 */ write += config_write_distribute (vty); write += config_write_if_rmap (vty); write++; } return write; } /* RIPng node structure. */ static struct cmd_node cmd_ripng_node = { RIPNG_NODE, "%s(config-router)# ", 1, }; static 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_V6_IN]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_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_V6_OUT]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_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_V6_IN]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_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_V6_OUT]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_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. */ static void ripng_distribute_update_all (struct prefix_list *notused) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_distribute_update_interface (ifp); } static void ripng_distribute_update_all_wrapper (const char *notused) { ripng_distribute_update_all(NULL); } /* delete all the added ripng routes. */ void ripng_clean() { int i; struct route_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct list *list = NULL; struct listnode *listnode = NULL; if (ripng) { /* Clear RIPng routes */ for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { if ((list = rp->info) != NULL) { rinfo = listgetdata (listhead (list)); if (ripng_route_rte (rinfo)) ripng_zebra_ipv6_delete (rp); for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { RIPNG_TIMER_OFF (rinfo->t_timeout); RIPNG_TIMER_OFF (rinfo->t_garbage_collect); ripng_info_free (rinfo); } list_delete (list); rp->info = NULL; route_unlock_node (rp); } if ((aggregate = rp->aggregate) != NULL) { ripng_aggregate_free (aggregate); rp->aggregate = NULL; route_unlock_node (rp); } } /* Cancel the RIPng timers */ RIPNG_TIMER_OFF (ripng->t_update); RIPNG_TIMER_OFF (ripng->t_triggered_update); RIPNG_TIMER_OFF (ripng->t_triggered_interval); /* Cancel the read thread */ if (ripng->t_read) { thread_cancel (ripng->t_read); ripng->t_read = NULL; } /* Close the RIPng socket */ if (ripng->sock >= 0) { close(ripng->sock); ripng->sock = -1; } /* Static RIPng route configuration. */ for (rp = route_top (ripng->route); rp; rp = route_next (rp)) if (rp->info) { rp->info = NULL; route_unlock_node (rp); } /* RIPng aggregated prefixes */ for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp)) if (rp->info) { rp->info = NULL; route_unlock_node (rp); } for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (ripng->route_map[i].name) free (ripng->route_map[i].name); XFREE (MTYPE_ROUTE_TABLE, ripng->table); XFREE (MTYPE_ROUTE_TABLE, ripng->route); XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate); XFREE (MTYPE_RIPNG, ripng); ripng = NULL; } /* if (ripng) */ ripng_clean_network(); ripng_passive_interface_clean (); ripng_offset_clean (); ripng_interface_clean (); ripng_redistribute_clean (); } /* Reset all values to the default settings. */ void ripng_reset () { /* Call ripd related reset functions. */ ripng_debug_reset (); ripng_route_map_reset (); /* Call library reset functions. */ vty_reset (); access_list_reset (); prefix_list_reset (); distribute_list_reset (); ripng_interface_reset (); ripng_zclient_reset (); } static 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); } static 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); } } } static void ripng_routemap_update (const char *unused) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_if_rmap_update_interface (ifp); ripng_routemap_update_redistribute (); } /* Initialize ripng structure and set commands. */ void ripng_init () { /* Randomize. */ srandom (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 (VIEW_NODE, &show_ipv6_ripng_status_cmd); install_element (CONFIG_NODE, &router_ripng_cmd); install_element (CONFIG_NODE, &no_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, &no_ripng_timers_val_cmd); #if 0 install_element (RIPNG_NODE, &ripng_update_timer_cmd); install_element (RIPNG_NODE, &no_ripng_update_timer_cmd); install_element (RIPNG_NODE, &ripng_timeout_timer_cmd); install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd); install_element (RIPNG_NODE, &ripng_garbage_timer_cmd); install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd); #endif /* 0 */ install_element (RIPNG_NODE, &ripng_default_information_originate_cmd); install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd); install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd); install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd); ripng_if_init (); ripng_debug_init (); /* Access list install. */ access_list_init (); access_list_add_hook (ripng_distribute_update_all_wrapper); access_list_delete_hook (ripng_distribute_update_all_wrapper); /* 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 (); ripng_offset_init (); route_map_add_hook (ripng_routemap_update); route_map_delete_hook (ripng_routemap_update); if_rmap_init (RIPNG_NODE); if_rmap_hook_add (ripng_if_rmap_update); if_rmap_hook_delete (ripng_if_rmap_update); } quagga-1.2.4/ripngd/ripngd.conf.sample000066400000000000000000000006061325323223500176620ustar00rootroot00000000000000! -*- rip -*- ! ! RIPngd sample configuration file ! ! $Id: ripngd.conf.sample,v 1.1 2002/12/13 20:15:30 paul 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 quagga-1.2.4/ripngd/ripngd.h000066400000000000000000000261301325323223500157040ustar00rootroot00000000000000/* * 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 #include #include /* RIPng version and port number. */ #define RIPNG_V1 1 #define RIPNG_PORT_DEFAULT 521 #define RIPNG_VTY_PORT 2603 #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 /* RIPng peer timeout value. */ #define RIPNG_PEER_TIMER_DEFAULT 180 /* 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_DEFAULT 2 #define RIPNG_ROUTE_REDISTRIBUTE 3 #define RIPNG_ROUTE_INTERFACE 4 #define RIPNG_ROUTE_AGGREGATE 5 /* Interface send/receive configuration. */ #define RIPNG_SEND_UNSPEC 0 #define RIPNG_SEND_OFF 1 #define RIPNG_RECEIVE_UNSPEC 0 #define RIPNG_RECEIVE_OFF 1 /* 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; /* RIPng ECMP flag */ unsigned int ecmp; /* 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; /* RIPng destination prefix */ u_int16_t tag; /* RIPng tag */ u_char prefixlen; /* Length of the RIPng prefix */ u_char metric; /* Metric of the RIPng route */ /* The nexthop is stored by the structure * ripng_nexthop within ripngd.c */ }; /* 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. */ ifindex_t 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. */ struct in6_addr nexthop_out; u_char metric_set; u_char metric_out; u_int16_t tag_out; struct route_node *rp; }; #ifdef notyet #if 0 /* 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; }; #endif /* 0 */ #endif /* not yet */ typedef enum { RIPNG_NO_SPLIT_HORIZON = 0, RIPNG_SPLIT_HORIZON, RIPNG_SPLIT_HORIZON_POISONED_REVERSE } split_horizon_policy_t; /* 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; /* Split horizon flag. */ split_horizon_policy_t split_horizon; split_horizon_policy_t split_horizon_default; /* 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]; #ifdef notyet #if 0 /* RIPng tag configuration. */ struct ripng_tag *rtag; #endif /* 0 */ #endif /* notyet */ /* 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; }; /* RIPng peer information. */ struct ripng_peer { /* Peer address. */ struct in6_addr addr; /* Peer RIPng 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; }; /* 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) /* Extern variables. */ extern struct ripng *ripng; extern struct thread_master *master; /* Prototypes. */ extern void ripng_init (void); extern void ripng_reset (void); extern void ripng_clean (void); extern void ripng_clean_network (void); extern void ripng_interface_clean (void); extern void ripng_interface_reset (void); extern void ripng_passive_interface_clean (void); extern void ripng_if_init (void); extern void ripng_route_map_init (void); extern void ripng_route_map_reset (void); extern void ripng_terminate (void); /* zclient_init() is done by ripng_zebra.c:zebra_init() */ extern void zebra_init (struct thread_master *); extern void ripng_zclient_start (void); extern void ripng_zclient_reset (void); extern void ripng_offset_init (void); extern int config_write_ripng_offset_list (struct vty *); extern void ripng_peer_init (void); extern void ripng_peer_update (struct sockaddr_in6 *, u_char); extern void ripng_peer_bad_route (struct sockaddr_in6 *); extern void ripng_peer_bad_packet (struct sockaddr_in6 *); extern void ripng_peer_display (struct vty *); extern struct ripng_peer *ripng_peer_lookup (struct in6_addr *); extern struct ripng_peer *ripng_peer_lookup_next (struct in6_addr *); extern int ripng_offset_list_apply_in (struct prefix_ipv6 *, struct interface *, u_char *); extern int ripng_offset_list_apply_out (struct prefix_ipv6 *, struct interface *, u_char *); extern void ripng_offset_clean (void); extern struct ripng_info * ripng_info_new (void); extern void ripng_info_free (struct ripng_info *rinfo); extern void ripng_event (enum ripng_event, int); extern int ripng_request (struct interface *ifp); extern void ripng_redistribute_add (int, int, struct prefix_ipv6 *, ifindex_t, struct in6_addr *, route_tag_t); extern void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, ifindex_t); extern void ripng_redistribute_withdraw (int type); extern void ripng_distribute_update_interface (struct interface *); extern void ripng_if_rmap_update_interface (struct interface *); extern void ripng_zebra_ipv6_add (struct route_node *); extern void ripng_zebra_ipv6_delete (struct route_node *); extern void ripng_redistribute_clean (void); extern int ripng_redistribute_check (int); extern void ripng_redistribute_write (struct vty *, int); extern int ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p, struct in6_addr *nexthop, u_int16_t tag, u_char metric); extern int ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, struct interface *ifp); extern void ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv); extern int ripng_interface_up (int command, struct zclient *, zebra_size_t, vrf_id_t); extern int ripng_interface_down (int command, struct zclient *, zebra_size_t, vrf_id_t); extern int ripng_interface_add (int command, struct zclient *, zebra_size_t, vrf_id_t); extern int ripng_interface_delete (int command, struct zclient *, zebra_size_t, vrf_id_t); extern int ripng_interface_address_add (int command, struct zclient *, zebra_size_t, vrf_id_t); extern int ripng_interface_address_delete (int command, struct zclient *, zebra_size_t, vrf_id_t); extern int ripng_network_write (struct vty *, int); extern struct ripng_info *ripng_ecmp_add (struct ripng_info *); extern struct ripng_info *ripng_ecmp_replace (struct ripng_info *); extern struct ripng_info *ripng_ecmp_delete (struct ripng_info *); #endif /* _ZEBRA_RIPNG_RIPNGD_H */ quagga-1.2.4/solaris/000077500000000000000000000000001325323223500144375ustar00rootroot00000000000000quagga-1.2.4/solaris/Makefile.am000066400000000000000000000103441325323223500164750ustar00rootroot00000000000000# Solaris packages automake file # XXX This file uses GNU make extensions. .PHONY: packages # the names of the various subpackages, and some convenient # derived variables. pkg_names = daemons dev doc libs smf pkg_quagga_daemons = zebra bgpd ospfd ospf6d ripd ripngd pkg_name_rev = @PACKAGE_VERSION@-@CONFDATE@-@target_os@-@target_cpu@ pkg_depends = $(pkg_names:%=depend.%) pkg_packages = $(pkg_names:%=@PACKAGE_TARNAME@-%-$(pkg_name_rev).pkg) pkg_pkginfos = $(pkg_names:%=pkginfo.%.full) pkg_prototypes = $(pkg_names:%=prototype.%) pkg_manifests = quagga.xml # pkgmk variable substitutions wont grok ${variable} in prototype # file, so we cant let autoconf generate the file sadly # wish automake would just provide a template for this edit = $(SED) \ -e 's,@prefix\@,$(prefix),g' \ -e 's,@exec_prefix,$(exec_prefix),g' \ -e 's,@bindir\@,$(bindir),g' \ -e 's,@sbindir\@,$(sbindir),g' \ -e 's,@libexecdir\@,$(libexecdir),g' \ -e 's,@datadir\@,$(datadir),g' \ -e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@sharedstatedir\@,$(sharedstatedir),g' \ -e 's,@localstatedir\@,$(localstatedir),g' \ -e 's,@libdir\@,$(libdir),g' \ -e 's,@includedir\@,$(includedir),g' \ -e 's,@infodir\@,$(infodir),g' \ -e 's,@mandir\@,$(mandir),g' \ -e 's,@enable_user\@,$(enable_user),g' \ -e 's,@enable_group\@,$(enable_group),g' \ -e 's,@enable_vty_group\@,$(enable_vty_group),g' \ -e 's,@quagga_statedir\@,$(quagga_statedir),g' \ -e 's,[@]PACKAGE_NAME[@],@PACKAGE_NAME@,g' \ -e 's,[@]PACKAGE_TARNAME[@],@PACKAGE_TARNAME@,g' \ -e 's,[@]PACKAGE_VERSION[@],@PACKAGE_VERSION@,g' \ -e 's,[@]PACKAGE_BUGREPORT[@],@PACKAGE_BUGREPORT@,g' \ -e 's,[@]CONFDATE[@],@CONFDATE@,g' \ -e 's,[@]target_cpu[@],$(target_cpu),g' \ -e 's,[@]target_host[@],$(target_host),g' \ -e 's,[@]target_os[@],$(target_os),g' # common options for pkgmk pkg_make_vars = exec_prefix=@exec_prefix@ prefix=@prefix@ \ builddir=@builddir@ srcdir=@srcdir@ \ top_builddir=@top_builddir@ top_srcdir=@top_srcdir@ \ abs_builddir=@abs_builddir@ abs_srcdir=@abs_srcdir@ \ abs_top_builddir=@abs_top_builddir@ abs_top_srcdir=@abs_top_srcdir@ # pkgmk: write the package to spool in build dir, to avoid root dependencies pkg_make = pkgmk -o -d @abs_builddir@ \ -f $< DESTDIR="$(DESTDIR)/" $(pkg_make_vars) # pkgtrans: write a pkg file stream, shame we cant pipe directly to it from # pkgmk.. pkg_trans = pkgtrans -s @abs_builddir@ "@abs_builddir@/$@" # pkgmk can only cope with a single pkginfo, cant 'stack' various # pkginfo template files and a package specific pkginfo file in the prototype # Create the package specific template here, and create the full pkginfo # by cating this and the common pkginfo.tmpl together. pkginfo.tmpl: $(srcdir)/pkginfo.tmpl.in Makefile rm -f $@ $(edit) $< > $@ pkginfo.%.tmpl: $(srcdir)/pkginfo.%.tmpl.in Makefile rm -f $@ $(edit) $< > $@ pkginfo.%.full: pkginfo.%.tmpl pkginfo.tmpl Makefile cat pkginfo.tmpl pkginfo.$*.tmpl > $@ # use 'edit' above to transform prototype.in to pkgmk acceptable prototype prototype.%: $(srcdir)/prototype.%.in Makefile rm -f $@ $(edit) $< > $@ # use edit to construct the SMF manifest files %.xml: $(srcdir)/%.xml.in Makefile rm -f $@ $(edit) $< > $@ # use edit to construct the depend files depend.%: $(srcdir)/depend.%.in Makefile rm -f $@ $(edit) $< > $@ # method file (bit like init script) quagga.init: $(srcdir)/quagga.init.in Makefile rm -f $@ $(edit) $< > $@ # construct the pkg @PACKAGE_TARNAME@-%-$(pkg_name_rev).pkg: prototype.% \ depend.% quagga.init pkginfo.%.full ($(pkg_make) && \ $(pkg_trans) "QUAGGA$*") %.pkg.gz : %.pkg (gzip -c $< > $@) # pkginfo.package and prototype.package are all built sources #BUILT_SOURCES = pkginfo.daemons pkginfo.dev pkginfo.doc pkginfo.libs \ # prototype.daemons prototype.dev prototype.doc prototype.libs BUILT_SOURCES = $(pkg_pkginfos) pkginfo.tmpl $(pkg_prototypes) \ $(pkg_manifests) $(pkg_depends) quagga.init CLEANFILES = $(BUILT_SOURCES) $(pkg_packages) EXTRA_DIST = $(pkg_manifests:%=%.in) $(pkg_prototypes:%=%.in) \ $(pkg_names:%=pkginfo.%.tmpl.in) $(srcdir)/pkginfo.tmpl.in \ $(pkg_depends:%=%.in) quagga.init.in README.txt pkg-root-install: (cd $(top_builddir) && \ $(MAKE) DESTDIR=$(abs_builddir)/quagga-root install) packages: $(pkg_packages) #nodist_pkgdata_DATA = $(pkg_packages) quagga-1.2.4/solaris/Makefile.in000066400000000000000000000432321325323223500165100ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ # Solaris packages automake file # XXX This file uses GNU make extensions. VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = solaris ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # the names of the various subpackages, and some convenient # derived variables. pkg_names = daemons dev doc libs smf pkg_quagga_daemons = zebra bgpd ospfd ospf6d ripd ripngd pkg_name_rev = @PACKAGE_VERSION@-@CONFDATE@-@target_os@-@target_cpu@ pkg_depends = $(pkg_names:%=depend.%) pkg_packages = $(pkg_names:%=@PACKAGE_TARNAME@-%-$(pkg_name_rev).pkg) pkg_pkginfos = $(pkg_names:%=pkginfo.%.full) pkg_prototypes = $(pkg_names:%=prototype.%) pkg_manifests = quagga.xml # pkgmk variable substitutions wont grok ${variable} in prototype # file, so we cant let autoconf generate the file sadly # wish automake would just provide a template for this edit = $(SED) \ -e 's,@prefix\@,$(prefix),g' \ -e 's,@exec_prefix,$(exec_prefix),g' \ -e 's,@bindir\@,$(bindir),g' \ -e 's,@sbindir\@,$(sbindir),g' \ -e 's,@libexecdir\@,$(libexecdir),g' \ -e 's,@datadir\@,$(datadir),g' \ -e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@sharedstatedir\@,$(sharedstatedir),g' \ -e 's,@localstatedir\@,$(localstatedir),g' \ -e 's,@libdir\@,$(libdir),g' \ -e 's,@includedir\@,$(includedir),g' \ -e 's,@infodir\@,$(infodir),g' \ -e 's,@mandir\@,$(mandir),g' \ -e 's,@enable_user\@,$(enable_user),g' \ -e 's,@enable_group\@,$(enable_group),g' \ -e 's,@enable_vty_group\@,$(enable_vty_group),g' \ -e 's,@quagga_statedir\@,$(quagga_statedir),g' \ -e 's,[@]PACKAGE_NAME[@],@PACKAGE_NAME@,g' \ -e 's,[@]PACKAGE_TARNAME[@],@PACKAGE_TARNAME@,g' \ -e 's,[@]PACKAGE_VERSION[@],@PACKAGE_VERSION@,g' \ -e 's,[@]PACKAGE_BUGREPORT[@],@PACKAGE_BUGREPORT@,g' \ -e 's,[@]CONFDATE[@],@CONFDATE@,g' \ -e 's,[@]target_cpu[@],$(target_cpu),g' \ -e 's,[@]target_host[@],$(target_host),g' \ -e 's,[@]target_os[@],$(target_os),g' # common options for pkgmk pkg_make_vars = exec_prefix=@exec_prefix@ prefix=@prefix@ \ builddir=@builddir@ srcdir=@srcdir@ \ top_builddir=@top_builddir@ top_srcdir=@top_srcdir@ \ abs_builddir=@abs_builddir@ abs_srcdir=@abs_srcdir@ \ abs_top_builddir=@abs_top_builddir@ abs_top_srcdir=@abs_top_srcdir@ # pkgmk: write the package to spool in build dir, to avoid root dependencies pkg_make = pkgmk -o -d @abs_builddir@ \ -f $< DESTDIR="$(DESTDIR)/" $(pkg_make_vars) # pkgtrans: write a pkg file stream, shame we cant pipe directly to it from # pkgmk.. pkg_trans = pkgtrans -s @abs_builddir@ "@abs_builddir@/$@" # pkginfo.package and prototype.package are all built sources #BUILT_SOURCES = pkginfo.daemons pkginfo.dev pkginfo.doc pkginfo.libs \ # prototype.daemons prototype.dev prototype.doc prototype.libs BUILT_SOURCES = $(pkg_pkginfos) pkginfo.tmpl $(pkg_prototypes) \ $(pkg_manifests) $(pkg_depends) quagga.init CLEANFILES = $(BUILT_SOURCES) $(pkg_packages) EXTRA_DIST = $(pkg_manifests:%=%.in) $(pkg_prototypes:%=%.in) \ $(pkg_names:%=pkginfo.%.tmpl.in) $(srcdir)/pkginfo.tmpl.in \ $(pkg_depends:%=%.in) quagga.init.in README.txt all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu solaris/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu solaris/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile installdirs: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: all check install install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile .PHONY: packages # pkgmk can only cope with a single pkginfo, cant 'stack' various # pkginfo template files and a package specific pkginfo file in the prototype # Create the package specific template here, and create the full pkginfo # by cating this and the common pkginfo.tmpl together. pkginfo.tmpl: $(srcdir)/pkginfo.tmpl.in Makefile rm -f $@ $(edit) $< > $@ pkginfo.%.tmpl: $(srcdir)/pkginfo.%.tmpl.in Makefile rm -f $@ $(edit) $< > $@ pkginfo.%.full: pkginfo.%.tmpl pkginfo.tmpl Makefile cat pkginfo.tmpl pkginfo.$*.tmpl > $@ # use 'edit' above to transform prototype.in to pkgmk acceptable prototype prototype.%: $(srcdir)/prototype.%.in Makefile rm -f $@ $(edit) $< > $@ # use edit to construct the SMF manifest files %.xml: $(srcdir)/%.xml.in Makefile rm -f $@ $(edit) $< > $@ # use edit to construct the depend files depend.%: $(srcdir)/depend.%.in Makefile rm -f $@ $(edit) $< > $@ # method file (bit like init script) quagga.init: $(srcdir)/quagga.init.in Makefile rm -f $@ $(edit) $< > $@ # construct the pkg @PACKAGE_TARNAME@-%-$(pkg_name_rev).pkg: prototype.% \ depend.% quagga.init pkginfo.%.full ($(pkg_make) && \ $(pkg_trans) "QUAGGA$*") %.pkg.gz : %.pkg (gzip -c $< > $@) pkg-root-install: (cd $(top_builddir) && \ $(MAKE) DESTDIR=$(abs_builddir)/quagga-root install) packages: $(pkg_packages) #nodist_pkgdata_DATA = $(pkg_packages) # 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: quagga-1.2.4/solaris/README.txt000066400000000000000000000154221325323223500161410ustar00rootroot00000000000000To build packages for Solaris 10: Requirements: ------------- - Development environment including gcc (eg as shipped with Solaris 10) - The Package tools from Solaris 10 or Solaris Nevada/Express. - i.manifest and r.manifest scripts as supplied with Solaris Express in /usr/sadm/install/scripts/ or from OpenSolaris.org: http://cvs.opensolaris.org/source/xref/usr/src/pkgdefs/common_files/i.manifest http://cvs.opensolaris.org/source/xref/usr/src/pkgdefs/common_files/r.manifest i.manifest must be at least version 1.5. Place these scripts in this directory if you are using Solaris 10 GA (which does not ship with these scripts), or in the solaris/ directory in the Quagga source. Package creation instructions: ------------------------------ 1. Configure and build Quagga in the top level build directory as per normal, eg: ./configure --prefix=/usr/local/quagga \ --localstatedir=/var/run/quagga --enable-gcc-rdynamic --enable-opaque-lsa --enable-ospf-te \ --enable-multipath=64 --enable-user=quagga \ --enable-ospfclient=yes --enable-ospfapi=yes \ --enable-group=quagga --enable-nssa --enable-opaque-lsa You will need /usr/sfw/bin and /usr/ccs/bin in your path. 2. make install in the top-level build directory, it's a good idea to make use of DESTDIR to install to an alternate root, eg: gmake DESTDIR=/var/tmp/qroot install 3. In this directory (solaris/), run make packages, specifying DESTDIR if appropriate, eg: gmake DESTDIR=/var/tmp/qroot packages This should result in 4 packages being created: quagga-libs-...-$ARCH.pkg - QUAGGAlibs quagga-daemons-...-$ARCH.pkg - QUAGGAdaemons quagga-doc-...-$ARCH.pkg - QUAGGAdoc quagga-dev-...-$ARCH.pkg - QUAGGAdev quagga-smf-...-$ARCH.pkg - QUAGGAsmf QUAGGAlibs and QUAGGAdaemons are needed for daemon runtime. QUAGGAsmf provides the required bits for Solaris 10+ SMF support. Install and post-install configuration notes: --------------------------------------------- - If you specified a user/group which does not exist per default on Solaris (eg quagga/quagga) you *must* create these before installing these on a system. The packages do *not* create the users. - The configuration files are not created. You must create the configuration file yourself, either with your complete desired configuration, or else if you wish to use the telnet interface for further configuration you must create them containing at least: password whatever The user which quagga runs as must have write permissions on this file, no other user should have read permissions, and you would also have to enable the telnet interface (see below). - SMF notes: - QUAGGAsmf installs a svc:/network/routing/quagga service, with an instance for each daemon - The state of all instances of quagga service can be inspected with: svcs -l svc:/network/routing/quagga or typically just with a shortcut of 'quagga': svcs -l quagga - A specific instance of the quagga service can be inspected by specifying the daemon name as the instance, ie quagga:: svcs -l svc:/network/routing/quagga:zebra svcs -l svc:/network/routing/quagga:ospfd or typically just with the shortcut of 'quagga:' or even : svcs -l quagga:zebra svcs -l ospfd Eg: # # svcs -l ripd fmri svc:/network/routing/quagga:ripd name Quagga: ripd, RIPv1/2 IPv4 routing protocol daemon. enabled true state online next_state none state_time Wed Jun 15 16:21:02 2005 logfile /var/svc/log/network-routing-quagga:ripd.log restarter svc:/system/svc/restarter:default contract_id 93 dependency require_all/restart svc:/network/routing/quagga:zebra (online) dependency require_all/restart file://localhost//usr/local/quagga/etc/ripd.conf (online) dependency require_all/none svc:/system/filesystem/usr:default (online) dependency require_all/none svc:/network/loopback (online) - Configuration of startup options is by way of SMF properties in a property group named 'quagga'. The defaults should automatically be inline with how you configured Quagga in Step 1 above. - By default the VTY interface is disabled. To change this, see below for how to set the 'quagga/vty_port' property as appropriate for /each/ service. Also, the VTY is set to listen only to localhost by default, you may change the 'quagga/vty_addr' property as appropriate for both of the 'quagga' service and specific individual instances of the 'quagga' service (ie quagga:zebra, quagga:ospfd, etc..). - Properties belonging to the 'quagga' service are inherited by all instances. Eg: # svcprop -p quagga svc:/network/routing/quagga quagga/group astring root quagga/retain boolean false quagga/user astring root quagga/vty_addr astring 127.1 quagga/vty_port integer 0 # svcprop -p quagga svc:/network/routing/quagga:ospfd quagga/retain_routes boolean false quagga/group astring root quagga/retain boolean false quagga/user astring root quagga/vty_addr astring 127.1 quagga/vty_port integer 0 All instances will inherit these properties, unless the instance itself overrides these defaults. This also implies one can modify properties of the 'quagga' service and have them apply to all daemons. # svccfg -s svc:/network/routing/quagga \ setprop quagga/vty_addr = astring: ::1 # svcprop -p quagga svc:/network/routing/quagga quagga/group astring root quagga/retain boolean false quagga/user astring root quagga/vty_port integer 0 quagga/vty_addr astring ::1 # # You *must* refresh instances to have the property change # # take affect for the 'running snapshot' of service state. # svcadm refresh quagga:ospfd # svcprop -p quagga svc:/network/routing/quagga:ospfd quagga/retain_routes boolean false quagga/group astring root quagga/retain boolean false quagga/user astring root quagga/vty_port integer 0 quagga/vty_addr astring ::1 Other daemon-specific options/properties may be available, however they are not yet honoured/used (eg ospfd/apiserver on svc:/network/ospf). - As SMF is dependency aware, restarting network/zebra will restart all the other daemons. - To upgrade from one set of Quagga packages to a newer release, one must first pkgrm the installed packages. When one pkgrm's QUAGGAsmf all property configuration will be lost, and any customisations will have to redone after installing the updated QUAGGAsmf package. - These packages are not supported by Sun Microsystems, report bugs via the usual Quagga channels, ie Bugzilla. Improvements/contributions of course would be greatly appreciated. quagga-1.2.4/solaris/depend.daemons.in000066400000000000000000000003611325323223500176530ustar00rootroot00000000000000P QUAGGAlibs Quagga common runtime libraries @PACKAGE_VERSION@,REV=@CONFDATE@ P SUNWcsu Core Solaris, (Usr) P SUNWcsr Core Solaris Libraries (Root) P SUNWcnetr Core Solaris Network Infrastructure (Root) I SUNWzebrar I SUNWzebrau I CSWzebra quagga-1.2.4/solaris/depend.dev.in000066400000000000000000000001171325323223500170020ustar00rootroot00000000000000P QUAGGAlibs Quagga common runtime libraries @PACKAGE_VERSION@,REV=@CONFDATE@ quagga-1.2.4/solaris/depend.doc.in000066400000000000000000000000361325323223500167710ustar00rootroot00000000000000P SUNWdoc Documentation Tools quagga-1.2.4/solaris/depend.libs.in000066400000000000000000000002551325323223500171600ustar00rootroot00000000000000P SUNWcslr Core Solaris Libraries (Root) P SUNWcsl Core Solaris, (Shared Libs) P SUNWlibmsr Math & Microtasking Libraries (Root) R QUAGGAdaemons Quagga daemons R QUAGGAdev quagga-1.2.4/solaris/depend.smf.in000066400000000000000000000003371325323223500170150ustar00rootroot00000000000000P QUAGGAdaemons Quagga daemons @PACKAGE_VERSION@,REV=@CONFDATE@ P SUNWcsu Core Solaris, (Usr) P SUNWcsr Core Solaris Libraries (Root) P SUNWroute Network Routing daemons/commands (Usr) I SUNWzebrar I SUNWzebrau I CSWzebra quagga-1.2.4/solaris/pkginfo.daemons.tmpl.in000066400000000000000000000001031325323223500210160ustar00rootroot00000000000000PKG="QUAGGAdaemons" NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ daemons" quagga-1.2.4/solaris/pkginfo.dev.tmpl.in000066400000000000000000000001101325323223500201440ustar00rootroot00000000000000PKG=QUAGGAdev NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ development files" quagga-1.2.4/solaris/pkginfo.doc.tmpl.in000066400000000000000000000001031325323223500201350ustar00rootroot00000000000000PKG=QUAGGAdoc NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ documentation" quagga-1.2.4/solaris/pkginfo.libs.tmpl.in000066400000000000000000000001171325323223500203260ustar00rootroot00000000000000PKG=QUAGGAlibs NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ common runtime libraries" quagga-1.2.4/solaris/pkginfo.smf.tmpl.in000066400000000000000000000001031325323223500201550ustar00rootroot00000000000000PKG="QUAGGAsmf" NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ SMF support" quagga-1.2.4/solaris/pkginfo.tmpl.in000066400000000000000000000004141325323223500173760ustar00rootroot00000000000000ARCH="@target_cpu@" CATEGORY="system" VERSION="@PACKAGE_VERSION@,REV=@CONFDATE@" VENDOR="http://www.quagga.net/" HOTLINE="@PACKAGE_BUGREPORT@" EMAIL=paul@quagga.net DESC="@PACKAGE_NAME@ Routing Protocols" MAXINST=1 CLASSES="none preserve renamenew manifest" BASEDIR=/ quagga-1.2.4/solaris/prototype.daemons.in000066400000000000000000000026131325323223500204630ustar00rootroot00000000000000i pkginfo=$abs_builddir/pkginfo.daemons.full i depend=$abs_builddir/depend.daemons i copying=$abs_top_srcdir/COPYING d none @sbindir@=$DESTDIR/@sbindir@ 0755 root bin f none @sbindir@/zebra=$DESTDIR/@sbindir@/zebra 0755 root bin f none @sbindir@/bgpd=$DESTDIR/@sbindir@/bgpd 0755 root bin f none @sbindir@/ripd=$DESTDIR/@sbindir@/ripd 0755 root bin f none @sbindir@/ripngd=$DESTDIR/@sbindir@/ripngd 0755 root bin f none @sbindir@/ospfd=$DESTDIR/@sbindir@/ospfd 0755 root bin f none @sbindir@/ospf6d=$DESTDIR/@sbindir@/ospf6d 0755 root bin f none @sbindir@/watchquagga=$DESTDIR/@sbindir@/watchquagga 0755 root bin d none @sysconfdir@=$DESTDIR/@sysconfdir@ 0711 @enable_user@ @enable_group@ f none @sysconfdir@/zebra.conf.sample=$DESTDIR/@sysconfdir@/zebra.conf.sample 0644 root bin f none @sysconfdir@/bgpd.conf.sample=$DESTDIR/@sysconfdir@/bgpd.conf.sample 0644 root bin f none @sysconfdir@/bgpd.conf.sample2=$DESTDIR/@sysconfdir@/bgpd.conf.sample2 0644 root bin f none @sysconfdir@/ripd.conf.sample=$DESTDIR/@sysconfdir@/ripd.conf.sample 0644 root bin f none @sysconfdir@/ripngd.conf.sample=$DESTDIR/@sysconfdir@/ripngd.conf.sample 0644 root bin f none @sysconfdir@/ospfd.conf.sample=$DESTDIR/@sysconfdir@/ospfd.conf.sample 0644 root bin f none @sysconfdir@/ospf6d.conf.sample=$DESTDIR/@sysconfdir@/ospf6d.conf.sample 0644 root bin d none @quagga_statedir@=$DESTDIR/@quagga_statedir@ 0711 @enable_user@ @enable_group@ quagga-1.2.4/solaris/prototype.dev.in000066400000000000000000000114511325323223500176130ustar00rootroot00000000000000i pkginfo=$abs_builddir/pkginfo.dev.full i depend=$abs_builddir/depend.dev i copying=$abs_top_srcdir/COPYING f none @libdir@/libzebra.la=$DESTDIR/@libdir@/libzebra.la 0755 root bin f none @libdir@/libzebra.a=$DESTDIR/@libdir@/libzebra.a 0644 root bin f none @libdir@/libospf.la=$DESTDIR/@libdir@/libospf.la 0755 root bin f none @libdir@/libospf.a=$DESTDIR/@libdir@/libospf.a 0644 root bin f none @libdir@/libospfapiclient.la=$DESTDIR/@libdir@/libospfapiclient.la 0755 root bin f none @libdir@/libospfapiclient.a=$DESTDIR/@libdir@/libospfapiclient.a 0644 root bin d none @includedir@=$DESTDIR/@includedir@ 0755 root bin d none @includedir@/quagga=$DESTDIR/@includedir@/quagga 0755 root bin d none @includedir@/quagga/ospfd=$DESTDIR/@includedir@/quagga/ospfd 0755 root bin f none @includedir@/quagga/ospfd/ospf_api.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_api.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_asbr.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_asbr.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_dump.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_dump.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_lsa.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_lsa.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_lsdb.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_lsdb.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_nsm.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_nsm.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_ism.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_ism.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_opaque.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_opaque.h 0644 root bin f none @includedir@/quagga/ospfd/ospfd.h=$DESTDIR/@includedir@/quagga/ospfd/ospfd.h 0644 root bin f none @includedir@/quagga/buffer.h=$DESTDIR/@includedir@/quagga/buffer.h 0644 root bin f none @includedir@/quagga/command.h=$DESTDIR/@includedir@/quagga/command.h 0644 root bin f none @includedir@/quagga/filter.h=$DESTDIR/@includedir@/quagga/filter.h 0644 root bin f none @includedir@/quagga/getopt.h=$DESTDIR/@includedir@/quagga/getopt.h 0644 root bin f none @includedir@/quagga/hash.h=$DESTDIR/@includedir@/quagga/hash.h 0644 root bin f none @includedir@/quagga/if.h=$DESTDIR/@includedir@/quagga/if.h 0644 root bin f none @includedir@/quagga/linklist.h=$DESTDIR/@includedir@/quagga/linklist.h 0644 root bin f none @includedir@/quagga/log.h=$DESTDIR/@includedir@/quagga/log.h 0644 root bin f none @includedir@/quagga/memory.h=$DESTDIR/@includedir@/quagga/memory.h 0644 root bin f none @includedir@/quagga/network.h=$DESTDIR/@includedir@/quagga/network.h 0644 root bin f none @includedir@/quagga/prefix.h=$DESTDIR/@includedir@/quagga/prefix.h 0644 root bin f none @includedir@/quagga/routemap.h=$DESTDIR/@includedir@/quagga/routemap.h 0644 root bin f none @includedir@/quagga/distribute.h=$DESTDIR/@includedir@/quagga/distribute.h 0644 root bin f none @includedir@/quagga/sockunion.h=$DESTDIR/@includedir@/quagga/sockunion.h 0644 root bin f none @includedir@/quagga/str.h=$DESTDIR/@includedir@/quagga/str.h 0644 root bin f none @includedir@/quagga/stream.h=$DESTDIR/@includedir@/quagga/stream.h 0644 root bin f none @includedir@/quagga/table.h=$DESTDIR/@includedir@/quagga/table.h 0644 root bin f none @includedir@/quagga/thread.h=$DESTDIR/@includedir@/quagga/thread.h 0644 root bin f none @includedir@/quagga/vector.h=$DESTDIR/@includedir@/quagga/vector.h 0644 root bin f none @includedir@/quagga/version.h=$DESTDIR/@includedir@/quagga/version.h 0644 root bin f none @includedir@/quagga/vty.h=$DESTDIR/@includedir@/quagga/vty.h 0644 root bin f none @includedir@/quagga/zebra.h=$DESTDIR/@includedir@/quagga/zebra.h 0644 root bin f none @includedir@/quagga/plist.h=$DESTDIR/@includedir@/quagga/plist.h 0644 root bin f none @includedir@/quagga/zclient.h=$DESTDIR/@includedir@/quagga/zclient.h 0644 root bin f none @includedir@/quagga/sockopt.h=$DESTDIR/@includedir@/quagga/sockopt.h 0644 root bin f none @includedir@/quagga/smux.h=$DESTDIR/@includedir@/quagga/smux.h 0644 root bin f none @includedir@/quagga/md5.h=$DESTDIR/@includedir@/quagga/md5.h 0644 root bin f none @includedir@/quagga/if_rmap.h=$DESTDIR/@includedir@/quagga/if_rmap.h 0644 root bin f none @includedir@/quagga/keychain.h=$DESTDIR/@includedir@/quagga/keychain.h 0644 root bin f none @includedir@/quagga/privs.h=$DESTDIR/@includedir@/quagga/privs.h 0644 root bin f none @includedir@/quagga/sigevent.h=$DESTDIR/@includedir@/quagga/sigevent.h 0644 root bin f none @includedir@/quagga/pqueue.h=$DESTDIR/@includedir@/quagga/pqueue.h 0644 root bin f none @includedir@/quagga/jhash.h=$DESTDIR/@includedir@/quagga/jhash.h 0644 root bin f none @includedir@/quagga/zassert.h=$DESTDIR/@includedir@/quagga/zassert.h 0644 root bin d none @includedir@/quagga/ospfapi=$DESTDIR/@includedir@/quagga/ospfapi 0755 root bin f none @includedir@/quagga/ospfapi/ospf_apiclient.h=$DESTDIR/@includedir@/quagga/ospfapi/ospf_apiclient.h 0644 root bin quagga-1.2.4/solaris/prototype.doc.in000066400000000000000000000020301325323223500175730ustar00rootroot00000000000000i pkginfo=$abs_builddir/pkginfo.doc.full i depend=$abs_builddir/depend.doc i copying=$abs_top_srcdir/COPYING d none @infodir@=$DESTDIR/@infodir@ 0755 root bin #f none @infodir@/dir=$DESTDIR/@infodir@/dir 0644 root bin f none @infodir@/quagga.info=$DESTDIR/@infodir@/quagga.info 0644 root bin d none @mandir@=$DESTDIR/@mandir@ 0755 root bin d none @mandir@/man1=$DESTDIR/@mandir@/man1 0755 root bin f none @mandir@/man1/vtysh.1=$DESTDIR/@mandir@/man1/vtysh.1 0644 root bin d none @mandir@/man8=$DESTDIR/@mandir@/man8 0755 root bin f none @mandir@/man8/bgpd.8=$DESTDIR/@mandir@/man8/bgpd.8 0644 root bin f none @mandir@/man8/ospf6d.8=$DESTDIR/@mandir@/man8/ospf6d.8 0644 root bin f none @mandir@/man8/ospfd.8=$DESTDIR/@mandir@/man8/ospfd.8 0644 root bin f none @mandir@/man8/ripd.8=$DESTDIR/@mandir@/man8/ripd.8 0644 root bin f none @mandir@/man8/ripngd.8=$DESTDIR/@mandir@/man8/ripngd.8 0644 root bin f none @mandir@/man8/zebra.8=$DESTDIR/@mandir@/man8/zebra.8 0644 root bin f none @mandir@/man8/isisd.8=$DESTDIR/@mandir@/man8/isisd.8 0644 root bin quagga-1.2.4/solaris/prototype.libs.in000066400000000000000000000013371325323223500177700ustar00rootroot00000000000000i pkginfo=$abs_builddir/pkginfo.libs.full i depend=$abs_builddir/depend.libs i copying=$abs_top_srcdir/COPYING d none @libdir@=$DESTDIR/@libdir@ 0755 root bin s none @libdir@/libzebra.so.0=libzebra.so.0.0.0 f none @libdir@/libzebra.so.0.0.0=$DESTDIR/@libdir@/libzebra.so.0.0.0 0755 root bin s none @libdir@/libzebra.so=libzebra.so.0.0.0 s none @libdir@/libospf.so.0=libospf.so.0.0.0 f none @libdir@/libospf.so.0.0.0=$DESTDIR/@libdir@/libospf.so.0.0.0 0755 root bin s none @libdir@/libospf.so=libospf.so.0.0.0 f none @libdir@/libospfapiclient.so.0.0.0=$DESTDIR/@libdir@/libospfapiclient.so.0.0.0 0755 root bin s none @libdir@/libospfapiclient.so.0=libospfapiclient.so.0.0.0 s none @libdir@/libospfapiclient.so=libospfapiclient.so.0.0.0 quagga-1.2.4/solaris/prototype.smf.in000066400000000000000000000005471325323223500176260ustar00rootroot00000000000000i pkginfo=$abs_builddir/pkginfo.smf.full i depend=$abs_builddir/depend.smf i copying=$abs_top_srcdir/COPYING i i.manifest i r.manifest f manifest var/svc/manifest/network/quagga.xml 0444 root bin #f none var/svc/profile/@PACKAGE_TARNAME@_options.xml=$abs_builddir/options.xml 0755 root sys f none lib/svc/method/quagga=$abs_builddir/quagga.init 0755 root bin quagga-1.2.4/solaris/quagga.init.in000077500000000000000000000166301325323223500172070ustar00rootroot00000000000000#!/sbin/sh # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This file is part of Quagga. # # Quagga is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any # later version. # # Quagga is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Quagga; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Starts/stops the given daemon SMFINCLUDE=/lib/svc/share/smf_include.sh ROUTEADMINCLUDE=/lib/svc/share/routing_include.sh GLOBAL_OPTIONS="PAfiug" DAEMON_PATH=@sbindir@ USER=@enable_user@ GROUP=@enable_group@ # handle upgrade of daemon-args SMF property to new routeadm properties # used during upgrade too by routeadm. # relevant to S10U4+ only. handle_routeadm_upgrade () { GLOBAL_OPTIONS="PAfiug" daemon_args=`get_daemon_args $SMF_FMRI` if [ -n "$daemon_args" ]; then set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "P" vty_port 0 set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "A" vty_address set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "f" config_file set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "i" pid_file set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "u" user set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "g" group case "$1" in zebra) set_daemon_boolean_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}b" "b" batch true false ;; ripd|ripngd) set_daemon_boolean_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}r" "r" retain true false ;; bgpd) set_daemon_boolean_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}rnp" "r" retain true false set_daemon_boolean_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}rnp" "n" no_kernel true false set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}rnp" "p" bgp_port esac clear_daemon_args $SMF_FMRI fi } upgrade_config () { DAEMON=$1 # handle upgrade of SUNWzebra to Quagga if [ -d "/etc/quagga" -a ! -f "/etc/quagga/${DAEMON}.conf" ] ; then if [ -f "/etc/sfw/zebra/${DAEMON}.conf" ] ; then cp "/etc/sfw/zebra/${DAEMON}.conf" \ "/etc/quagga/${DAEMON}.conf.upgrade" \ || exit $SMF_EXIT_ERR_FATAL chown "${USER}:${GROUP}" "/etc/quagga/${DAEMON}.conf.upgrade" \ || exit $SMF_EXIT_ERR_FATAL chmod 0600 "/etc/quagga/${DAEMON}.conf.upgrade" \ || exit $SMF_EXIT_ERR_FATAL mv "/etc/quagga/${DAEMON}.conf.upgrade" "/etc/quagga/${DAEMON}.conf" \ || exit $SMF_EXIT_ERR_FATAL fi fi if [ ! -f "/etc/quagga/${DAEMON}.conf" ] ; then touch "/etc/quagga/${DAEMON}.conf.new" \ || exit $SMF_EXIT_ERR_FATAL chown "${USER}:${GROUP}" "/etc/quagga/${DAEMON}.conf.new" \ || exit $SMF_EXIT_ERR_FATAL chmod 0600 "/etc/quagga/${DAEMON}.conf.new" \ || exit $SMF_EXIT_ERR_FATAL mv "/etc/quagga/${DAEMON}.conf.new" "/etc/quagga/${DAEMON}.conf" \ || exit $SMF_EXIT_ERR_FATAL fi } # Relevant to S10+ quagga_is_globalzone () { if [ "${QUAGGA_INIT_ZONENAME:=`/sbin/zonename`}" = "global" \ -o `/sbin/zonename -t` = "exclusive" ]; then return 0 else return 1 fi } routeadm_daemon_args () { # globals args="`get_daemon_option_from_property $SMF_FMRI config_file f`" args="${args} `get_daemon_option_from_property $SMF_FMRI vty_port P`" args="${args} `get_daemon_option_from_property $SMF_FMRI vty_address A`" args="${args} `get_daemon_option_from_property $SMF_FMRI pid_file i`" # user and group we need for config file upgrade.. SMF_USER=`get_routeadm_property $SMF_FMRI user` SMF_GROUP=`get_routeadm_property() $SMF_FMRI group` if [ "${SMF_USER}" ] ; then USER="${SMF_USER}" args="${args} -u ${SMF_USER}" fi if [ "${SMF_GROUP}" ] ; then GROUP="${SMF_GROUP}" args="${args} -g ${SMF_GROUP}" fi case $1 in zebra) args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI batch -b true`" ;; ripd|ripngd) args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI retain -r true`" ;; bgpd) args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI retain -r true`" args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI no_kernel -n true`" args="${args} `get_daemon_option_from_property $SMF_FMRI bgp_port p 179`" ;; esac echo ${args} } # Include smf functions, if available. If not, define smf_present to indicate # there is no SMF. Should allow this script to work pre-S10. if [ -f "$SMFINCLUDE" ] ; then . "$SMFINCLUDE"; # source the SMF-routeadm include if present.. if [ -f "$ROUTEADMINCLUDE" ] ; then . "$ROUTEADMINCLUDE" fi else # pre-SMF system, fake up any functions and exit codes # which SMFINCLUDE usually provides. smf_present () { return 1 } SMF_EXIT_OK=0; SMF_EXIT_ERR_CONFIG=96; SMF_EXIT_ERR_FATAL=95; fi # if there's no SMF, set some default DAEMON_ARGS smf_present || DAEMON_ARGS="" usage () { if smf_present ; then echo "Usage: $0 "; else echo "Usage: $0 "; fi echo "The --pid_file argument is implied"; echo "This help message: $0 "; } # parse arguments, different according to SMF or not. case $1 in 'help' | 'usage') usage exit $SMF_EXIT_OK ;; esac if smf_present ; then QUAGGA_METHOD="start" else QUAGGA_METHOD="$1" shift; fi DAEMON="$1" # daemon path must be given if [ "$DAEMON_PATH/$DAEMON" = "/" ]; then usage exit $SMF_EXIT_ERR_FATAL fi # only bgpd is suitable for running in a non-global zone, at this # time. case "${DAEMON}" in bgpd) ;; zebra | ospfd | ospf6d | ripd | ripngd ) quagga_is_globalzone || exit $SMF_EXIT_OK ;; *) usage exit $SMF_EXIT_ERR_CONFIG; ;; esac # Older Quagga SMF packages pass daemon args on the commandline # Newer SMF routeadm model uses properties for each argument # so we must handle that. if [ smf_present -a -f "$ROUTEADMINCLUDE" ]; then handle_routeadm_upgrade $DAEMON; DAEMON_ARGS=`routeadm_daemon_args`; else if [ $# -gt 0 ] ; then shift DAEMON_ARGS="$@" fi fi upgrade_config "$DAEMON" CONF_FILE=`get_routeadm_property $SMF_FMRI config_file` if [ -z "$CONF_FILE" ] ; then CONF_FILE="@sysconfdir@/${DAEMON}.conf" fi if [ ! -f "$CONF_FILE" ] ; then echo "Could not find config file, $CONF_FILE" exit $SMF_EXIT_ERR_CONFIG fi # we need @quagga_statedir@ to exist, it probably is on tmpfs. if [ ! -d @quagga_statedir@ ] ; then mkdir -p @quagga_statedir@ chown @enable_user@:@enable_group@ @quagga_statedir@ chmod 751 @quagga_statedir@ fi PIDFILE="@quagga_statedir@/${DAEMON}.pid" start () { if [ ! -x "$DAEMON_PATH/$DAEMON" ] ; then echo "Error, could not find daemon, $DAEMON_PATH/$DAEMON" exit $SMF_EXIT_ERR_FATAL fi eval exec $DAEMON_PATH/$DAEMON $DAEMON_ARGS --pid_file ${PIDFILE} & } stop_by_pidfile () { if [ -f "${PIDFILE}" ]; then /usr/bin/kill -TERM `/usr/bin/cat "${PIDFILE}"` fi } case "$QUAGGA_METHOD" in 'start') start ;; 'stop') stop_by_pidfile ;; *) usage exit $SMF_EXIT_ERR_FATAL ;; esac exit $SMF_EXIT_OK; quagga-1.2.4/solaris/quagga.xml.in000066400000000000000000000575721325323223500170530ustar00rootroot00000000000000 quagga-1.2.4/test-driver000077500000000000000000000110401325323223500151550ustar00rootroot00000000000000#! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2013-07-13.22; # UTC # Copyright (C) 2011-2014 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, see . # 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. # This file is maintained in Automake, please report # bugs to or send patches to # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <$log_file 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then tweaked_estatus=1 else tweaked_estatus=$estatus fi case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report the test outcome and exit status in the logs, so that one can # know whether the test passed or failed simply by looking at the '.log' # file, without the need of also peaking into the corresponding '.trs' # file (automake bug#11814). echo "$res $test_name (exit status: $estatus)" >>$log_file # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: quagga-1.2.4/tests/000077500000000000000000000000001325323223500141255ustar00rootroot00000000000000quagga-1.2.4/tests/Makefile.am000066400000000000000000000060221325323223500161610ustar00rootroot00000000000000 EXTRA_DIST = \ testcommands.in \ testcommands.refout \ testcli.in \ testcli.refout AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" if BGPD TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath else TESTS_BGPD = endif check_PROGRAMS = testsig testsegv testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest testnexthopiter \ testcommands test-timer-correctness test-timer-performance \ testcli \ $(TESTS_BGPD) TESTS = $(TESTS_BGPD) teststream tabletest testmemory testnexthopiter \ test-timer-correctness tabletest ../vtysh/vtysh_cmd.c: $(MAKE) -C ../vtysh vtysh_cmd.c test-commands-defun.c: ../vtysh/vtysh_cmd.c sed \ -e 's/"vtysh\.h"/"tests.h"/' \ -e 's/vtysh_init_cmd/test_init_cmd/' \ -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ < ../vtysh/vtysh_cmd.c \ > test-commands-defun.c BUILT_SOURCES = test-commands-defun.c CLEANFILES = test-commands-defun.c bgpd libzebra noinst_HEADERS = prng.h tests.h common-cli.h testcli_SOURCES = test-cli.c common-cli.c testsig_SOURCES = test-sig.c testsegv_SOURCES = test-segv.c testbuffer_SOURCES = test-buffer.c testmemory_SOURCES = test-memory.c testprivs_SOURCES = test-privs.c teststream_SOURCES = test-stream.c heavy_SOURCES = heavy.c main.c heavywq_SOURCES = heavy-wq.c main.c heavythread_SOURCES = heavy-thread.c main.c aspathtest_SOURCES = aspath_test.c testbgpcap_SOURCES = bgp_capability_test.c ecommtest_SOURCES = ecommunity_test.c testbgpmpattr_SOURCES = bgp_mp_attr_test.c testchecksum_SOURCES = test-checksum.c testbgpmpath_SOURCES = bgp_mpath_test.c tabletest_SOURCES = table_test.c testnexthopiter_SOURCES = test-nexthop-iter.c prng.c testcommands_SOURCES = test-commands-defun.c test-commands.c prng.c test_timer_correctness_SOURCES = test-timer-correctness.c prng.c test_timer_performance_SOURCES = test-timer-performance.c prng.c testcli_LDADD = ../lib/libzebra.la @LIBCAP@ testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testsegv_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ testmemory_LDADD = ../lib/libzebra.la @LIBCAP@ testprivs_LDADD = ../lib/libzebra.la @LIBCAP@ teststream_LDADD = ../lib/libzebra.la @LIBCAP@ heavy_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavywq_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavythread_LDADD = ../lib/libzebra.la @LIBCAP@ -lm aspathtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testbgpcap_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm ecommtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testbgpmpattr_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@ testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm testnexthopiter_LDADD = ../lib/libzebra.la @LIBCAP@ testcommands_LDADD = ../lib/libzebra.la @LIBCAP@ test_timer_correctness_LDADD = ../lib/libzebra.la @LIBCAP@ test_timer_performance_LDADD = ../lib/libzebra.la @LIBCAP@ quagga-1.2.4/tests/Makefile.in000066400000000000000000001403151325323223500161760ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = testsig$(EXEEXT) testsegv$(EXEEXT) \ testbuffer$(EXEEXT) testmemory$(EXEEXT) heavy$(EXEEXT) \ heavywq$(EXEEXT) heavythread$(EXEEXT) testprivs$(EXEEXT) \ teststream$(EXEEXT) testchecksum$(EXEEXT) tabletest$(EXEEXT) \ testnexthopiter$(EXEEXT) testcommands$(EXEEXT) \ test-timer-correctness$(EXEEXT) \ test-timer-performance$(EXEEXT) testcli$(EXEEXT) \ $(am__EXEEXT_1) TESTS = $(am__EXEEXT_1) teststream$(EXEEXT) tabletest$(EXEEXT) \ testmemory$(EXEEXT) testnexthopiter$(EXEEXT) \ test-timer-correctness$(EXEEXT) tabletest$(EXEEXT) subdir = tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @BGPD_TRUE@am__EXEEXT_1 = aspathtest$(EXEEXT) testbgpcap$(EXEEXT) \ @BGPD_TRUE@ ecommtest$(EXEEXT) testbgpmpattr$(EXEEXT) \ @BGPD_TRUE@ testbgpmpath$(EXEEXT) am_aspathtest_OBJECTS = aspath_test.$(OBJEXT) aspathtest_OBJECTS = $(am_aspathtest_OBJECTS) aspathtest_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_ecommtest_OBJECTS = ecommunity_test.$(OBJEXT) ecommtest_OBJECTS = $(am_ecommtest_OBJECTS) ecommtest_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la am_heavy_OBJECTS = heavy.$(OBJEXT) main.$(OBJEXT) heavy_OBJECTS = $(am_heavy_OBJECTS) heavy_DEPENDENCIES = ../lib/libzebra.la am_heavythread_OBJECTS = heavy-thread.$(OBJEXT) main.$(OBJEXT) heavythread_OBJECTS = $(am_heavythread_OBJECTS) heavythread_DEPENDENCIES = ../lib/libzebra.la am_heavywq_OBJECTS = heavy-wq.$(OBJEXT) main.$(OBJEXT) heavywq_OBJECTS = $(am_heavywq_OBJECTS) heavywq_DEPENDENCIES = ../lib/libzebra.la am_tabletest_OBJECTS = table_test.$(OBJEXT) tabletest_OBJECTS = $(am_tabletest_OBJECTS) tabletest_DEPENDENCIES = ../lib/libzebra.la am_test_timer_correctness_OBJECTS = test-timer-correctness.$(OBJEXT) \ prng.$(OBJEXT) test_timer_correctness_OBJECTS = $(am_test_timer_correctness_OBJECTS) test_timer_correctness_DEPENDENCIES = ../lib/libzebra.la am_test_timer_performance_OBJECTS = test-timer-performance.$(OBJEXT) \ prng.$(OBJEXT) test_timer_performance_OBJECTS = $(am_test_timer_performance_OBJECTS) test_timer_performance_DEPENDENCIES = ../lib/libzebra.la am_testbgpcap_OBJECTS = bgp_capability_test.$(OBJEXT) testbgpcap_OBJECTS = $(am_testbgpcap_OBJECTS) testbgpcap_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la am_testbgpmpath_OBJECTS = bgp_mpath_test.$(OBJEXT) testbgpmpath_OBJECTS = $(am_testbgpmpath_OBJECTS) testbgpmpath_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la am_testbgpmpattr_OBJECTS = bgp_mp_attr_test.$(OBJEXT) testbgpmpattr_OBJECTS = $(am_testbgpmpattr_OBJECTS) testbgpmpattr_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la am_testbuffer_OBJECTS = test-buffer.$(OBJEXT) testbuffer_OBJECTS = $(am_testbuffer_OBJECTS) testbuffer_DEPENDENCIES = ../lib/libzebra.la am_testchecksum_OBJECTS = test-checksum.$(OBJEXT) testchecksum_OBJECTS = $(am_testchecksum_OBJECTS) testchecksum_DEPENDENCIES = ../lib/libzebra.la am_testcli_OBJECTS = test-cli.$(OBJEXT) common-cli.$(OBJEXT) testcli_OBJECTS = $(am_testcli_OBJECTS) testcli_DEPENDENCIES = ../lib/libzebra.la am_testcommands_OBJECTS = test-commands-defun.$(OBJEXT) \ test-commands.$(OBJEXT) prng.$(OBJEXT) testcommands_OBJECTS = $(am_testcommands_OBJECTS) testcommands_DEPENDENCIES = ../lib/libzebra.la am_testmemory_OBJECTS = test-memory.$(OBJEXT) testmemory_OBJECTS = $(am_testmemory_OBJECTS) testmemory_DEPENDENCIES = ../lib/libzebra.la am_testnexthopiter_OBJECTS = test-nexthop-iter.$(OBJEXT) \ prng.$(OBJEXT) testnexthopiter_OBJECTS = $(am_testnexthopiter_OBJECTS) testnexthopiter_DEPENDENCIES = ../lib/libzebra.la am_testprivs_OBJECTS = test-privs.$(OBJEXT) testprivs_OBJECTS = $(am_testprivs_OBJECTS) testprivs_DEPENDENCIES = ../lib/libzebra.la am_testsegv_OBJECTS = test-segv.$(OBJEXT) testsegv_OBJECTS = $(am_testsegv_OBJECTS) testsegv_DEPENDENCIES = ../lib/libzebra.la am_testsig_OBJECTS = test-sig.$(OBJEXT) testsig_OBJECTS = $(am_testsig_OBJECTS) testsig_DEPENDENCIES = ../lib/libzebra.la am_teststream_OBJECTS = test-stream.$(OBJEXT) teststream_OBJECTS = $(am_teststream_OBJECTS) teststream_DEPENDENCIES = ../lib/libzebra.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(aspathtest_SOURCES) $(ecommtest_SOURCES) $(heavy_SOURCES) \ $(heavythread_SOURCES) $(heavywq_SOURCES) $(tabletest_SOURCES) \ $(test_timer_correctness_SOURCES) \ $(test_timer_performance_SOURCES) $(testbgpcap_SOURCES) \ $(testbgpmpath_SOURCES) $(testbgpmpattr_SOURCES) \ $(testbuffer_SOURCES) $(testchecksum_SOURCES) \ $(testcli_SOURCES) $(testcommands_SOURCES) \ $(testmemory_SOURCES) $(testnexthopiter_SOURCES) \ $(testprivs_SOURCES) $(testsegv_SOURCES) $(testsig_SOURCES) \ $(teststream_SOURCES) DIST_SOURCES = $(aspathtest_SOURCES) $(ecommtest_SOURCES) \ $(heavy_SOURCES) $(heavythread_SOURCES) $(heavywq_SOURCES) \ $(tabletest_SOURCES) $(test_timer_correctness_SOURCES) \ $(test_timer_performance_SOURCES) $(testbgpcap_SOURCES) \ $(testbgpmpath_SOURCES) $(testbgpmpattr_SOURCES) \ $(testbuffer_SOURCES) $(testchecksum_SOURCES) \ $(testcli_SOURCES) $(testcommands_SOURCES) \ $(testmemory_SOURCES) $(testnexthopiter_SOURCES) \ $(testprivs_SOURCES) $(testsegv_SOURCES) $(testsig_SOURCES) \ $(teststream_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ $(top_srcdir)/test-driver DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = \ testcommands.in \ testcommands.refout \ testcli.in \ testcli.refout AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib @BGPD_FALSE@TESTS_BGPD = @BGPD_TRUE@TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath BUILT_SOURCES = test-commands-defun.c CLEANFILES = test-commands-defun.c bgpd libzebra noinst_HEADERS = prng.h tests.h common-cli.h testcli_SOURCES = test-cli.c common-cli.c testsig_SOURCES = test-sig.c testsegv_SOURCES = test-segv.c testbuffer_SOURCES = test-buffer.c testmemory_SOURCES = test-memory.c testprivs_SOURCES = test-privs.c teststream_SOURCES = test-stream.c heavy_SOURCES = heavy.c main.c heavywq_SOURCES = heavy-wq.c main.c heavythread_SOURCES = heavy-thread.c main.c aspathtest_SOURCES = aspath_test.c testbgpcap_SOURCES = bgp_capability_test.c ecommtest_SOURCES = ecommunity_test.c testbgpmpattr_SOURCES = bgp_mp_attr_test.c testchecksum_SOURCES = test-checksum.c testbgpmpath_SOURCES = bgp_mpath_test.c tabletest_SOURCES = table_test.c testnexthopiter_SOURCES = test-nexthop-iter.c prng.c testcommands_SOURCES = test-commands-defun.c test-commands.c prng.c test_timer_correctness_SOURCES = test-timer-correctness.c prng.c test_timer_performance_SOURCES = test-timer-performance.c prng.c testcli_LDADD = ../lib/libzebra.la @LIBCAP@ testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testsegv_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ testmemory_LDADD = ../lib/libzebra.la @LIBCAP@ testprivs_LDADD = ../lib/libzebra.la @LIBCAP@ teststream_LDADD = ../lib/libzebra.la @LIBCAP@ heavy_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavywq_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavythread_LDADD = ../lib/libzebra.la @LIBCAP@ -lm aspathtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testbgpcap_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm ecommtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testbgpmpattr_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@ testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm testnexthopiter_LDADD = ../lib/libzebra.la @LIBCAP@ testcommands_LDADD = ../lib/libzebra.la @LIBCAP@ test_timer_correctness_LDADD = ../lib/libzebra.la @LIBCAP@ test_timer_performance_LDADD = ../lib/libzebra.la @LIBCAP@ all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list aspathtest$(EXEEXT): $(aspathtest_OBJECTS) $(aspathtest_DEPENDENCIES) $(EXTRA_aspathtest_DEPENDENCIES) @rm -f aspathtest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(aspathtest_OBJECTS) $(aspathtest_LDADD) $(LIBS) ecommtest$(EXEEXT): $(ecommtest_OBJECTS) $(ecommtest_DEPENDENCIES) $(EXTRA_ecommtest_DEPENDENCIES) @rm -f ecommtest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ecommtest_OBJECTS) $(ecommtest_LDADD) $(LIBS) heavy$(EXEEXT): $(heavy_OBJECTS) $(heavy_DEPENDENCIES) $(EXTRA_heavy_DEPENDENCIES) @rm -f heavy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(heavy_OBJECTS) $(heavy_LDADD) $(LIBS) heavythread$(EXEEXT): $(heavythread_OBJECTS) $(heavythread_DEPENDENCIES) $(EXTRA_heavythread_DEPENDENCIES) @rm -f heavythread$(EXEEXT) $(AM_V_CCLD)$(LINK) $(heavythread_OBJECTS) $(heavythread_LDADD) $(LIBS) heavywq$(EXEEXT): $(heavywq_OBJECTS) $(heavywq_DEPENDENCIES) $(EXTRA_heavywq_DEPENDENCIES) @rm -f heavywq$(EXEEXT) $(AM_V_CCLD)$(LINK) $(heavywq_OBJECTS) $(heavywq_LDADD) $(LIBS) tabletest$(EXEEXT): $(tabletest_OBJECTS) $(tabletest_DEPENDENCIES) $(EXTRA_tabletest_DEPENDENCIES) @rm -f tabletest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tabletest_OBJECTS) $(tabletest_LDADD) $(LIBS) test-timer-correctness$(EXEEXT): $(test_timer_correctness_OBJECTS) $(test_timer_correctness_DEPENDENCIES) $(EXTRA_test_timer_correctness_DEPENDENCIES) @rm -f test-timer-correctness$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_timer_correctness_OBJECTS) $(test_timer_correctness_LDADD) $(LIBS) test-timer-performance$(EXEEXT): $(test_timer_performance_OBJECTS) $(test_timer_performance_DEPENDENCIES) $(EXTRA_test_timer_performance_DEPENDENCIES) @rm -f test-timer-performance$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_timer_performance_OBJECTS) $(test_timer_performance_LDADD) $(LIBS) testbgpcap$(EXEEXT): $(testbgpcap_OBJECTS) $(testbgpcap_DEPENDENCIES) $(EXTRA_testbgpcap_DEPENDENCIES) @rm -f testbgpcap$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testbgpcap_OBJECTS) $(testbgpcap_LDADD) $(LIBS) testbgpmpath$(EXEEXT): $(testbgpmpath_OBJECTS) $(testbgpmpath_DEPENDENCIES) $(EXTRA_testbgpmpath_DEPENDENCIES) @rm -f testbgpmpath$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testbgpmpath_OBJECTS) $(testbgpmpath_LDADD) $(LIBS) testbgpmpattr$(EXEEXT): $(testbgpmpattr_OBJECTS) $(testbgpmpattr_DEPENDENCIES) $(EXTRA_testbgpmpattr_DEPENDENCIES) @rm -f testbgpmpattr$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testbgpmpattr_OBJECTS) $(testbgpmpattr_LDADD) $(LIBS) testbuffer$(EXEEXT): $(testbuffer_OBJECTS) $(testbuffer_DEPENDENCIES) $(EXTRA_testbuffer_DEPENDENCIES) @rm -f testbuffer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testbuffer_OBJECTS) $(testbuffer_LDADD) $(LIBS) testchecksum$(EXEEXT): $(testchecksum_OBJECTS) $(testchecksum_DEPENDENCIES) $(EXTRA_testchecksum_DEPENDENCIES) @rm -f testchecksum$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testchecksum_OBJECTS) $(testchecksum_LDADD) $(LIBS) testcli$(EXEEXT): $(testcli_OBJECTS) $(testcli_DEPENDENCIES) $(EXTRA_testcli_DEPENDENCIES) @rm -f testcli$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testcli_OBJECTS) $(testcli_LDADD) $(LIBS) testcommands$(EXEEXT): $(testcommands_OBJECTS) $(testcommands_DEPENDENCIES) $(EXTRA_testcommands_DEPENDENCIES) @rm -f testcommands$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testcommands_OBJECTS) $(testcommands_LDADD) $(LIBS) testmemory$(EXEEXT): $(testmemory_OBJECTS) $(testmemory_DEPENDENCIES) $(EXTRA_testmemory_DEPENDENCIES) @rm -f testmemory$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testmemory_OBJECTS) $(testmemory_LDADD) $(LIBS) testnexthopiter$(EXEEXT): $(testnexthopiter_OBJECTS) $(testnexthopiter_DEPENDENCIES) $(EXTRA_testnexthopiter_DEPENDENCIES) @rm -f testnexthopiter$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testnexthopiter_OBJECTS) $(testnexthopiter_LDADD) $(LIBS) testprivs$(EXEEXT): $(testprivs_OBJECTS) $(testprivs_DEPENDENCIES) $(EXTRA_testprivs_DEPENDENCIES) @rm -f testprivs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testprivs_OBJECTS) $(testprivs_LDADD) $(LIBS) testsegv$(EXEEXT): $(testsegv_OBJECTS) $(testsegv_DEPENDENCIES) $(EXTRA_testsegv_DEPENDENCIES) @rm -f testsegv$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testsegv_OBJECTS) $(testsegv_LDADD) $(LIBS) testsig$(EXEEXT): $(testsig_OBJECTS) $(testsig_DEPENDENCIES) $(EXTRA_testsig_DEPENDENCIES) @rm -f testsig$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testsig_OBJECTS) $(testsig_LDADD) $(LIBS) teststream$(EXEEXT): $(teststream_OBJECTS) $(teststream_DEPENDENCIES) $(EXTRA_teststream_DEPENDENCIES) @rm -f teststream$(EXEEXT) $(AM_V_CCLD)$(LINK) $(teststream_OBJECTS) $(teststream_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aspath_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_capability_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mp_attr_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mpath_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common-cli.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecommunity_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heavy-thread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heavy-wq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heavy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prng.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-checksum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-cli.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-commands-defun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-commands.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-memory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nexthop-iter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-privs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-segv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-sig.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-stream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-timer-correctness.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-timer-performance.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all $(check_PROGRAMS) @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? aspathtest.log: aspathtest$(EXEEXT) @p='aspathtest$(EXEEXT)'; \ b='aspathtest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) testbgpcap.log: testbgpcap$(EXEEXT) @p='testbgpcap$(EXEEXT)'; \ b='testbgpcap'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) ecommtest.log: ecommtest$(EXEEXT) @p='ecommtest$(EXEEXT)'; \ b='ecommtest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) testbgpmpattr.log: testbgpmpattr$(EXEEXT) @p='testbgpmpattr$(EXEEXT)'; \ b='testbgpmpattr'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) testbgpmpath.log: testbgpmpath$(EXEEXT) @p='testbgpmpath$(EXEEXT)'; \ b='testbgpmpath'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) teststream.log: teststream$(EXEEXT) @p='teststream$(EXEEXT)'; \ b='teststream'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) tabletest.log: tabletest$(EXEEXT) @p='tabletest$(EXEEXT)'; \ b='tabletest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) testmemory.log: testmemory$(EXEEXT) @p='testmemory$(EXEEXT)'; \ b='testmemory'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) testnexthopiter.log: testnexthopiter$(EXEEXT) @p='testnexthopiter$(EXEEXT)'; \ b='testnexthopiter'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) test-timer-correctness.log: test-timer-correctness$(EXEEXT) @p='test-timer-correctness$(EXEEXT)'; \ b='test-timer-correctness'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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 $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(HEADERS) installdirs: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: all check check-am install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ recheck tags tags-am uninstall uninstall-am .PRECIOUS: Makefile ../vtysh/vtysh_cmd.c: $(MAKE) -C ../vtysh vtysh_cmd.c test-commands-defun.c: ../vtysh/vtysh_cmd.c sed \ -e 's/"vtysh\.h"/"tests.h"/' \ -e 's/vtysh_init_cmd/test_init_cmd/' \ -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ < ../vtysh/vtysh_cmd.c \ > test-commands-defun.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: quagga-1.2.4/tests/aspath_test.c000066400000000000000000001234661325323223500166240ustar00rootroot00000000000000/* * Copyright (C) 2005 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "vty.h" #include "stream.h" #include "privs.h" #include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_attr.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" #define VT100_GREEN "\x1b[32m" #define VT100_YELLOW "\x1b[33m" #define OK VT100_GREEN "OK" VT100_RESET #define FAILED VT100_RED "failed" VT100_RESET /* need these to link in libbgp */ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; static int failed = 0; /* specification for a test - what the results should be */ struct test_spec { const char *shouldbe; /* the string the path should parse to */ const char *shouldbe_delete_confed; /* ditto, but once confeds are deleted */ const unsigned int hops; /* aspath_count_hops result */ const unsigned int confeds; /* aspath_count_confeds */ const int private_as; /* whether the private_as check should pass or fail */ #define NOT_ALL_PRIVATE 0 #define ALL_PRIVATE 1 const as_t does_loop; /* an ASN which should trigger loop-check */ const as_t doesnt_loop; /* one which should not */ const as_t first; /* the first ASN, if there is one */ #define NULL_ASN 0 }; /* test segments to parse and validate, and use for other tests */ static struct test_segment { const char *name; const char *desc; const u_char asdata[1024]; int len; struct test_spec sp; } test_segments [] = { { /* 0 */ "seq1", "seq(8466,3,52737,4096)", { 0x2,0x4, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00 }, 10, { "8466 3 52737 4096", "8466 3 52737 4096", 4, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 1 */ "seq2", "seq(8722) seq(4)", { 0x2,0x1, 0x22,0x12, 0x2,0x1, 0x00,0x04 }, 8, { "8722 4", "8722 4", 2, 0, NOT_ALL_PRIVATE, 4, 5, 8722, }, }, { /* 2 */ "seq3", "seq(8466,3,52737,4096,8722,4)", { 0x2,0x6, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x22,0x12, 0x00,0x04}, 14, { "8466 3 52737 4096 8722 4", "8466 3 52737 4096 8722 4", 6, 0, NOT_ALL_PRIVATE, 3, 5, 8466 }, }, { /* 3 */ "seqset", "seq(8482,51457) set(5204)", { 0x2,0x2, 0x21,0x22, 0xc9,0x01, 0x1,0x1, 0x14,0x54 }, 10, { "8482 51457 {5204}", "8482 51457 {5204}", 3, 0, NOT_ALL_PRIVATE, 5204, 51456, 8482}, }, { /* 4 */ "seqset2", "seq(8467, 59649) set(4196,48658) set(17322,30745)", { 0x2,0x2, 0x21,0x13, 0xe9,0x01, 0x1,0x2, 0x10,0x64, 0xbe,0x12, 0x1,0x2, 0x43,0xaa, 0x78,0x19 }, 18, { "8467 59649 {4196,48658} {17322,30745}", "8467 59649 {4196,48658} {17322,30745}", 4, 0, NOT_ALL_PRIVATE, 48658, 1, 8467}, }, { /* 5 */ "multi", "seq(6435,59408,21665) set(2457,61697,4369), seq(1842,41590,51793)", { 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, 0x1,0x3, 0x09,0x99, 0xf1,0x01, 0x11,0x11, 0x2,0x3, 0x07,0x32, 0xa2,0x76, 0xca,0x51 }, 24, { "6435 59408 21665 {2457,4369,61697} 1842 41590 51793", "6435 59408 21665 {2457,4369,61697} 1842 41590 51793", 7, 0, NOT_ALL_PRIVATE, 51793, 1, 6435 }, }, { /* 6 */ "confed", "confseq(123,456,789)", { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15 }, 8, { "(123 456 789)", "", 0, 3, NOT_ALL_PRIVATE, 789, 1, NULL_ASN }, }, { /* 7 */ "confed2", "confseq(123,456,789) confseq(111,222)", { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15, 0x3,0x2, 0x00,0x6f, 0x00,0xde }, 14, { "(123 456 789) (111 222)", "", 0, 5, NOT_ALL_PRIVATE, 111, 1, NULL_ASN }, }, { /* 8 */ "confset", "confset(456,123,789)", { 0x4,0x3, 0x01,0xc8, 0x00,0x7b, 0x03,0x15 }, 8, { "[123,456,789]", "[123,456,789]", 0, 1, NOT_ALL_PRIVATE, 123, 1, NULL_ASN }, }, { /* 9 */ "confmulti", "confseq(123,456,789) confset(222,111) seq(8722) set(4196,48658)", { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15, 0x4,0x2, 0x00,0xde, 0x00,0x6f, 0x2,0x1, 0x22,0x12, 0x1,0x2, 0x10,0x64, 0xbe,0x12 }, 24, { "(123 456 789) [111,222] 8722 {4196,48658}", "8722 {4196,48658}", 2, 4, NOT_ALL_PRIVATE, 123, 1, NULL_ASN }, }, { /* 10 */ "seq4", "seq(8466,2,52737,4096,8722,4)", { 0x2,0x6, 0x21,0x12, 0x00,0x02, 0xce,0x01, 0x10,0x00, 0x22,0x12, 0x00,0x04}, 14, { "8466 2 52737 4096 8722 4", "8466 2 52737 4096 8722 4", 6, 0, NOT_ALL_PRIVATE, 4096, 1, 8466 }, }, { /* 11 */ "tripleseq1", "seq(8466,2,52737) seq(4096,8722,4) seq(8722)", { 0x2,0x3, 0x21,0x12, 0x00,0x02, 0xce,0x01, 0x2,0x3, 0x10,0x00, 0x22,0x12, 0x00,0x04, 0x2,0x1, 0x22,0x12}, 20, { "8466 2 52737 4096 8722 4 8722", "8466 2 52737 4096 8722 4 8722", 7, 0, NOT_ALL_PRIVATE, 4096, 1, 8466 }, }, { /* 12 */ "someprivate", "seq(8466,64512,52737,65535)", { 0x2,0x4, 0x21,0x12, 0xfc,0x00, 0xce,0x01, 0xff,0xff }, 10, { "8466 64512 52737 65535", "8466 64512 52737 65535", 4, 0, NOT_ALL_PRIVATE, 65535, 4, 8466 }, }, { /* 13 */ "allprivate", "seq(65534,64512,64513,65535)", { 0x2,0x4, 0xff,0xfe, 0xfc,0x00, 0xfc,0x01, 0xff,0xff }, 10, { "65534 64512 64513 65535", "65534 64512 64513 65535", 4, 0, ALL_PRIVATE, 65534, 4, 65534 }, }, { /* 14 */ "long", "seq(8466,3,52737,4096,34285,)", { 0x2,0xfa, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, }, 502, { "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285", "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285", 250, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 15 */ "seq1extra", "seq(8466,3,52737,4096,3456)", { 0x2,0x5, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80 }, 12, { "8466 3 52737 4096 3456", "8466 3 52737 4096 3456", 5, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 16 */ "empty", "", {}, 0, { "", "", 0, 0, 0, 0, 0, 0 }, }, { /* 17 */ "redundantset", "seq(8466,3,52737,4096,3456) set(7099,8153,8153,8153)", { 0x2,0x5, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80, 0x1,0x4, 0x1b,0xbb, 0x1f,0xd9, 0x1f,0xd9, 0x1f,0xd9 }, 22, { /* We shouldn't ever /generate/ such paths. However, we should * cope with them fine. */ "8466 3 52737 4096 3456 {7099,8153}", "8466 3 52737 4096 3456 {7099,8153}", 6, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 18 */ "reconcile_lead_asp", "seq(6435,59408,21665) set(23456,23456,23456), seq(23456,23456,23456)", { 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, 0x1,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0 }, 24, { "6435 59408 21665 {23456} 23456 23456 23456", "6435 59408 21665 {23456} 23456 23456 23456", 7, 0, NOT_ALL_PRIVATE, 23456, 1, 6435 }, }, { /* 19 */ "reconcile_new_asp", "set(2457,61697,4369), seq(1842,41591,51793)", { 0x1,0x3, 0x09,0x99, 0xf1,0x01, 0x11,0x11, 0x2,0x3, 0x07,0x32, 0xa2,0x77, 0xca,0x51 }, 16, { "{2457,4369,61697} 1842 41591 51793", "{2457,4369,61697} 1842 41591 51793", 4, 0, NOT_ALL_PRIVATE, 51793, 1, 2457 }, }, { /* 20 */ "reconcile_confed", "confseq(123,456,789) confset(456,124,788) seq(6435,59408,21665)" " set(23456,23456,23456), seq(23456,23456,23456)", { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15, 0x4,0x3, 0x01,0xc8, 0x00,0x7c, 0x03,0x14, 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, 0x1,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0 }, 40, { "(123 456 789) [124,456,788] 6435 59408 21665" " {23456} 23456 23456 23456", "6435 59408 21665 {23456} 23456 23456 23456", 7, 4, NOT_ALL_PRIVATE, 23456, 1, 6435 }, }, { /* 21 */ "reconcile_start_trans", "seq(23456,23456,23456) seq(6435,59408,21665)", { 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, }, 16, { "23456 23456 23456 6435 59408 21665", "23456 23456 23456 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE, 21665, 1, 23456 }, }, { /* 22 */ "reconcile_start_trans4", "seq(1842,41591,51793) seq(6435,59408,21665)", { 0x2,0x3, 0x07,0x32, 0xa2,0x77, 0xca,0x51, 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, }, 16, { "1842 41591 51793 6435 59408 21665", "1842 41591 51793 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE, 41591, 1, 1842 }, }, { /* 23 */ "reconcile_start_trans_error", "seq(23456,23456,23456) seq(6435,59408)", { 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, 0x2,0x2, 0x19,0x23, 0xe8,0x10, }, 14, { "23456 23456 23456 6435 59408", "23456 23456 23456 6435 59408", 5, 0, NOT_ALL_PRIVATE, 59408, 1, 23456 }, }, { /* 24 */ "redundantset2", "seq(8466,3,52737,4096,3456) set(7099,8153,8153,8153,7099)", { 0x2,0x5, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80, 0x1,0x5, 0x1b,0xbb, 0x1f,0xd9, 0x1f,0xd9, 0x1f,0xd9, 0x1b,0xbb,}, 24, { /* We should weed out duplicate set members. */ "8466 3 52737 4096 3456 {7099,8153}", "8466 3 52737 4096 3456 {7099,8153}", 6, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 25 */ "zero-size overflow", "#ASNs = 0, data = seq(8466 3 52737 4096 3456)", { 0x2,0x0, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80 }, 12, { NULL, NULL, 0, 0, 0, 0, 0, 0 }, }, { /* 26 */ "zero-size overflow + valid segment", "seq(#AS=0:8466 3 52737),seq(4096 3456)", { 0x2,0x0, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x2,0x2, 0x10,0x00, 0x0d,0x80 }, 14 , { NULL, NULL, 0, 0, 0, 0, 0, 0 }, }, { /* 27 */ "invalid segment type", "type=8(4096 3456)", { 0x8,0x2, 0x10,0x00, 0x0d,0x80 }, 14 , { NULL, NULL, 0, 0, 0, 0, 0, 0 }, }, { NULL, NULL, {0}, 0, { NULL, 0, 0 } } }; #define COMMON_ATTRS \ BGP_ATTR_FLAG_TRANS, \ BGP_ATTR_ORIGIN, \ 1, \ BGP_ORIGIN_EGP, \ BGP_ATTR_FLAG_TRANS, \ BGP_ATTR_NEXT_HOP, \ 4, 192, 0, 2, 0 #define COMMON_ATTR_SIZE 11 /* */ static struct aspath_tests { const char *desc; const struct test_segment *segment; const char *shouldbe; /* String it should evaluate to */ const enum as4 { AS4_DATA, AS2_DATA } as4; /* whether data should be as4 or not (ie as2) */ const int result; /* expected result for bgp_attr_parse */ const int cap; /* capabilities to set for peer */ const char attrheader [1024]; size_t len; const struct test_segment *old_segment; } aspath_tests [] = { /* 0 */ { "basic test", &test_segments[0], "8466 3 52737 4096", AS2_DATA, 0, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 10, }, COMMON_ATTR_SIZE + 3, }, /* 1 */ { "length too short", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 8, }, COMMON_ATTR_SIZE + 3, }, /* 2 */ { "length too long", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 12, }, COMMON_ATTR_SIZE + 3, }, /* 3 */ { "incorrect flag", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS_PATH, 10, }, COMMON_ATTR_SIZE + 3, }, /* 4 */ { "as4_path, with as2 format data", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 10, }, COMMON_ATTR_SIZE + 3, }, /* 5 */ { "as4, with incorrect attr length", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 10, }, COMMON_ATTR_SIZE + 3, }, /* 6 */ { "basic 4-byte as-path", &test_segments[0], "8466 3 52737 4096", AS4_DATA, 0, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 18, }, COMMON_ATTR_SIZE + 3, }, /* 7 */ { "4b AS_PATH: too short", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 16, }, COMMON_ATTR_SIZE + 3, }, /* 8 */ { "4b AS_PATH: too long", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 20, }, COMMON_ATTR_SIZE + 3, }, /* 9 */ { "4b AS_PATH: too long2", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 22, }, COMMON_ATTR_SIZE + 3, }, /* 10 */ { "4b AS_PATH: bad flags", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS_PATH, 18, }, COMMON_ATTR_SIZE + 3, }, /* 11 */ { "4b AS4_PATH w/o AS_PATH", &test_segments[6], NULL, AS4_DATA, -1, PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 14, }, COMMON_ATTR_SIZE + 3, }, /* 12 */ { "4b AS4_PATH: confed", &test_segments[6], "8466 3 52737 4096 (123 456 789)", AS4_DATA, 0, PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 14, }, COMMON_ATTR_SIZE + 3, &test_segments[0], }, { NULL, NULL, NULL, 0, 0, 0, { 0 }, 0 }, }; /* prepending tests */ static struct tests { const struct test_segment *test1; const struct test_segment *test2; struct test_spec sp; } prepend_tests[] = { /* 0 */ { &test_segments[0], &test_segments[1], { "8466 3 52737 4096 8722 4", "8466 3 52737 4096 8722 4", 6, 0, NOT_ALL_PRIVATE, 4096, 1, 8466 }, }, /* 1 */ { &test_segments[1], &test_segments[3], { "8722 4 8482 51457 {5204}", "8722 4 8482 51457 {5204}", 5, 0, NOT_ALL_PRIVATE, 5204, 1, 8722 } }, /* 2 */ { &test_segments[3], &test_segments[4], { "8482 51457 {5204} 8467 59649 {4196,48658} {17322,30745}", "8482 51457 {5204} 8467 59649 {4196,48658} {17322,30745}", 7, 0, NOT_ALL_PRIVATE, 5204, 1, 8482 }, }, /* 3 */ { &test_segments[4], &test_segments[5], { "8467 59649 {4196,48658} {17322,30745} 6435 59408 21665" " {2457,4369,61697} 1842 41590 51793", "8467 59649 {4196,48658} {17322,30745} 6435 59408 21665" " {2457,4369,61697} 1842 41590 51793", 11, 0, NOT_ALL_PRIVATE, 61697, 1, 8467 } }, /* 4 */ { &test_segments[5], &test_segments[6], { "6435 59408 21665 {2457,4369,61697} 1842 41590 51793", "6435 59408 21665 {2457,4369,61697} 1842 41590 51793", 7, 0, NOT_ALL_PRIVATE, 1842, 1, 6435 }, }, /* 5 */ { &test_segments[6], &test_segments[7], { "(123 456 789) (123 456 789) (111 222)", "", 0, 8, NOT_ALL_PRIVATE, 111, 1, 0 } }, { &test_segments[7], &test_segments[8], { "(123 456 789) (111 222) [123,456,789]", "", 0, 6, NOT_ALL_PRIVATE, 111, 1, 0 } }, { &test_segments[8], &test_segments[9], { "[123,456,789] (123 456 789) [111,222] 8722 {4196,48658}", "[123,456,789] (123 456 789) [111,222] 8722 {4196,48658}", 2, 5, NOT_ALL_PRIVATE, 456, 1, NULL_ASN }, }, { &test_segments[9], &test_segments[8], { "(123 456 789) [111,222] 8722 {4196,48658} [123,456,789]", "8722 {4196,48658} [123,456,789]", 2, 5, NOT_ALL_PRIVATE, 48658, 1, NULL_ASN }, }, { &test_segments[14], &test_segments[11], { "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 2 52737 4096 8722 4 8722", "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 2 52737 4096 8722 4 8722", 257, 0, NOT_ALL_PRIVATE, 4096, 1000, 8466 }, }, { NULL, NULL, { NULL, 0, 0, 0, 0, 0, 0, } }, }; struct tests reconcile_tests[] = { { &test_segments[18], &test_segments[19], { "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", 7, 0, NOT_ALL_PRIVATE, 51793, 1, 6435 }, }, { &test_segments[19], &test_segments[18], /* AS_PATH (19) has more hops than NEW_AS_PATH, * so just AS_PATH should be used (though, this practice * is bad imho). */ { "{2457,4369,61697} 1842 41591 51793 6435 59408 21665 {23456} 23456 23456 23456", "{2457,4369,61697} 1842 41591 51793 6435 59408 21665 {23456} 23456 23456 23456", 11, 0, NOT_ALL_PRIVATE, 51793, 1, 6435 }, }, { &test_segments[20], &test_segments[19], { "(123 456 789) [124,456,788] 6435 59408 21665" " {2457,4369,61697} 1842 41591 51793", "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", 7, 4, NOT_ALL_PRIVATE, 51793, 1, 6435 }, }, { &test_segments[21], &test_segments[22], { "1842 41591 51793 6435 59408 21665", "1842 41591 51793 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE, 51793, 1, 1842 }, }, { &test_segments[23], &test_segments[22], { "23456 23456 23456 6435 59408 1842 41591 51793 6435 59408 21665", "23456 23456 23456 6435 59408 1842 41591 51793 6435 59408 21665", 11, 0, NOT_ALL_PRIVATE, 51793, 1, 1842 }, }, { NULL, NULL, { NULL, 0, 0, 0, 0, 0, 0, } }, }; struct tests aggregate_tests[] = { { &test_segments[0], &test_segments[2], { "8466 3 52737 4096 {4,8722}", "8466 3 52737 4096 {4,8722}", 5, 0, NOT_ALL_PRIVATE, 4, 1, 8466 }, }, { &test_segments[2], &test_segments[0], { "8466 3 52737 4096 {4,8722}", "8466 3 52737 4096 {4,8722}", 5, 0, NOT_ALL_PRIVATE, 8722, 1, 8466 }, }, { &test_segments[2], &test_segments[10], { "8466 {2,3,4,4096,8722,52737}", "8466 {2,3,4,4096,8722,52737}", 2, 0, NOT_ALL_PRIVATE, 8722, 5, 8466 }, }, { &test_segments[10], &test_segments[2], { "8466 {2,3,4,4096,8722,52737}", "8466 {2,3,4,4096,8722,52737}", 2, 0, NOT_ALL_PRIVATE, 2, 20000, 8466 }, }, { &test_segments[5], &test_segments[18], { "6435 59408 21665 {1842,2457,4369,23456,41590,51793,61697}", "6435 59408 21665 {1842,2457,4369,23456,41590,51793,61697}", 4, 0, NOT_ALL_PRIVATE, 41590, 1, 6435 }, }, { NULL, NULL, { NULL, 0, 0} }, }; struct compare_tests { int test_index1; int test_index2; #define CMP_RES_YES 1 #define CMP_RES_NO 0 char shouldbe_cmp; char shouldbe_confed; } left_compare [] = { { 0, 1, CMP_RES_NO, CMP_RES_NO }, { 0, 2, CMP_RES_YES, CMP_RES_NO }, { 0, 11, CMP_RES_YES, CMP_RES_NO }, { 0, 15, CMP_RES_YES, CMP_RES_NO }, { 0, 16, CMP_RES_NO, CMP_RES_NO }, { 1, 11, CMP_RES_NO, CMP_RES_NO }, { 6, 7, CMP_RES_NO, CMP_RES_YES }, { 6, 8, CMP_RES_NO, CMP_RES_NO }, { 7, 8, CMP_RES_NO, CMP_RES_NO }, { 1, 9, CMP_RES_YES, CMP_RES_NO }, { 0, 9, CMP_RES_NO, CMP_RES_NO }, { 3, 9, CMP_RES_NO, CMP_RES_NO }, { 0, 6, CMP_RES_NO, CMP_RES_NO }, { 1, 6, CMP_RES_NO, CMP_RES_NO }, { 0, 8, CMP_RES_NO, CMP_RES_NO }, { 1, 8, CMP_RES_NO, CMP_RES_NO }, { 11, 6, CMP_RES_NO, CMP_RES_NO }, { 11, 7, CMP_RES_NO, CMP_RES_NO }, { 11, 8, CMP_RES_NO, CMP_RES_NO }, { 9, 6, CMP_RES_NO, CMP_RES_YES }, { 9, 7, CMP_RES_NO, CMP_RES_YES }, { 9, 8, CMP_RES_NO, CMP_RES_NO }, }; /* make an aspath from a data stream */ static struct aspath * make_aspath (const u_char *data, size_t len, int use32bit) { struct stream *s = NULL; struct aspath *as; if (len) { s = stream_new (len); stream_put (s, data, len); } as = aspath_parse (s, len, use32bit); if (s) stream_free (s); return as; } static void printbytes (const u_char *bytes, int len) { int i = 0; while (i < len) { if (i % 2) printf ("%02hhx%s", bytes[i], " "); else printf ("0x%02hhx", bytes[i]); i++; } printf ("\n"); } /* validate the given aspath */ static int validate (struct aspath *as, const struct test_spec *sp) { size_t bytes, bytes4; int fails = 0; const u_char *out; static struct stream *s; struct aspath *asinout, *asconfeddel, *asstr, *as4; if (as == NULL && sp->shouldbe == NULL) { printf ("Correctly failed to parse\n"); return fails; } out = aspath_snmp_pathseg (as, &bytes); asinout = make_aspath (out, bytes, 0); /* Excercise AS4 parsing a bit, with a dogfood test */ if (!s) s = stream_new (4096); bytes4 = aspath_put (s, as, 1); as4 = make_aspath (STREAM_DATA(s), bytes4, 1); asstr = aspath_str2aspath (sp->shouldbe); asconfeddel = aspath_delete_confed_seq (aspath_dup (asinout)); printf ("got: %s\n", aspath_print(as)); /* the parsed path should match the specified 'shouldbe' string. * We should pass the "eat our own dog food" test, be able to output * this path and then input it again. Ie the path resulting from: * * aspath_parse(aspath_put(as)) * * should: * * - also match the specified 'shouldbe' value * - hash to same value as original path * - have same hops and confed counts as original, and as the * the specified counts * * aspath_str2aspath() and shouldbe should match * * We do the same for: * * aspath_parse(aspath_put(as,USE32BIT)) * * Confederation related tests: * - aspath_delete_confed_seq(aspath) should match shouldbe_confed * - aspath_delete_confed_seq should be idempotent. */ if (strcmp(aspath_print (as), sp->shouldbe) /* hash validation */ || (aspath_key_make (as) != aspath_key_make (asinout)) /* by string */ || strcmp(aspath_print (asinout), sp->shouldbe) /* By 4-byte parsing */ || strcmp(aspath_print (as4), sp->shouldbe) /* by various path counts */ || (aspath_count_hops (as) != sp->hops) || (aspath_count_confeds (as) != sp->confeds) || (aspath_count_hops (asinout) != sp->hops) || (aspath_count_confeds (asinout) != sp->confeds)) { failed++; fails++; printf ("shouldbe:\n%s\n", sp->shouldbe); printf ("as4:\n%s\n", aspath_print (as4)); printf ("hash keys: in: %d out->in: %d\n", aspath_key_make (as), aspath_key_make (asinout)); printf ("hops: %d, counted %d %d\n", sp->hops, aspath_count_hops (as), aspath_count_hops (asinout) ); printf ("confeds: %d, counted %d %d\n", sp->confeds, aspath_count_confeds (as), aspath_count_confeds (asinout)); printf ("out->in:\n%s\nbytes: ", aspath_print(asinout)); printbytes (out, bytes); } /* basic confed related tests */ if ((aspath_print (asconfeddel) == NULL && sp->shouldbe_delete_confed != NULL) || (aspath_print (asconfeddel) != NULL && sp->shouldbe_delete_confed == NULL) || strcmp(aspath_print (asconfeddel), sp->shouldbe_delete_confed) /* delete_confed_seq should be idempotent */ || (aspath_key_make (asconfeddel) != aspath_key_make (aspath_delete_confed_seq (asconfeddel)))) { failed++; fails++; printf ("confed_del: %s\n", aspath_print (asconfeddel)); printf ("should be: %s\n", sp->shouldbe_delete_confed); } /* aspath_str2aspath test */ if ((aspath_print (asstr) == NULL && sp->shouldbe != NULL) || (aspath_print (asstr) != NULL && sp->shouldbe == NULL) || strcmp(aspath_print (asstr), sp->shouldbe)) { failed++; fails++; printf ("asstr: %s\n", aspath_print (asstr)); } /* loop, private and first as checks */ if ((sp->does_loop && aspath_loop_check (as, sp->does_loop) == 0) || (sp->doesnt_loop && aspath_loop_check (as, sp->doesnt_loop) != 0) || (aspath_private_as_check (as) != sp->private_as) || (aspath_firstas_check (as,sp->first) && sp->first == 0)) { failed++; fails++; printf ("firstas: %d, got %d\n", sp->first, aspath_firstas_check (as,sp->first)); printf ("loop does: %d %d, doesn't: %d %d\n", sp->does_loop, aspath_loop_check (as, sp->does_loop), sp->doesnt_loop, aspath_loop_check (as, sp->doesnt_loop)); printf ("private check: %d %d\n", sp->private_as, aspath_private_as_check (as)); } aspath_unintern (&asinout); aspath_unintern (&as4); aspath_free (asconfeddel); aspath_free (asstr); stream_reset (s); return fails; } static void empty_get_test () { struct aspath *as = aspath_empty_get (); struct test_spec sp = { "", "", 0, 0, 0, 0, 0, 0 }; printf ("empty_get_test, as: %s\n",aspath_print (as)); if (!validate (as, &sp)) printf ("%s\n", OK); else printf ("%s!\n", FAILED); printf ("\n"); aspath_free (as); } /* basic parsing test */ static void parse_test (struct test_segment *t) { struct aspath *asp; printf ("%s: %s\n", t->name, t->desc); asp = make_aspath (t->asdata, t->len, 0); printf ("aspath: %s\nvalidating...:\n", aspath_print (asp)); if (!validate (asp, &t->sp)) printf (OK "\n"); else printf (FAILED "\n"); printf ("\n"); if (asp) aspath_unintern (&asp); } /* prepend testing */ static void prepend_test (struct tests *t) { struct aspath *asp1, *asp2, *ascratch; printf ("prepend %s: %s\n", t->test1->name, t->test1->desc); printf ("to %s: %s\n", t->test2->name, t->test2->desc); asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); asp2 = make_aspath (t->test2->asdata, t->test2->len, 0); ascratch = aspath_dup (asp2); aspath_unintern (&asp2); asp2 = aspath_prepend (asp1, ascratch); printf ("aspath: %s\n", aspath_print (asp2)); if (!validate (asp2, &t->sp)) printf ("%s\n", OK); else printf ("%s!\n", FAILED); printf ("\n"); aspath_unintern (&asp1); aspath_free (asp2); } /* empty-prepend testing */ static void empty_prepend_test (struct test_segment *t) { struct aspath *asp1, *asp2, *ascratch; printf ("empty prepend %s: %s\n", t->name, t->desc); asp1 = make_aspath (t->asdata, t->len, 0); asp2 = aspath_empty (); ascratch = aspath_dup (asp2); aspath_unintern (&asp2); asp2 = aspath_prepend (asp1, ascratch); printf ("aspath: %s\n", aspath_print (asp2)); if (!validate (asp2, &t->sp)) printf (OK "\n"); else printf (FAILED "!\n"); printf ("\n"); if (asp1) aspath_unintern (&asp1); aspath_free (asp2); } /* as2+as4 reconciliation testing */ static void as4_reconcile_test (struct tests *t) { struct aspath *asp1, *asp2, *ascratch; printf ("reconciling %s:\n %s\n", t->test1->name, t->test1->desc); printf ("with %s:\n %s\n", t->test2->name, t->test2->desc); asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); asp2 = make_aspath (t->test2->asdata, t->test2->len, 0); ascratch = aspath_reconcile_as4 (asp1, asp2); if (!validate (ascratch, &t->sp)) printf (OK "\n"); else printf (FAILED "!\n"); printf ("\n"); aspath_unintern (&asp1); aspath_unintern (&asp2); aspath_free (ascratch); } /* aggregation testing */ static void aggregate_test (struct tests *t) { struct aspath *asp1, *asp2, *ascratch; printf ("aggregate %s: %s\n", t->test1->name, t->test1->desc); printf ("with %s: %s\n", t->test2->name, t->test2->desc); asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); asp2 = make_aspath (t->test2->asdata, t->test2->len, 0); ascratch = aspath_aggregate (asp1, asp2); if (!validate (ascratch, &t->sp)) printf (OK "\n"); else printf (FAILED "!\n"); printf ("\n"); aspath_unintern (&asp1); aspath_unintern (&asp2); aspath_free (ascratch); /* aspath_unintern (ascratch);*/ } /* cmp_left tests */ static void cmp_test () { unsigned int i; #define CMP_TESTS_MAX \ (sizeof(left_compare) / sizeof (struct compare_tests)) for (i = 0; i < CMP_TESTS_MAX; i++) { struct test_segment *t1 = &test_segments[left_compare[i].test_index1]; struct test_segment *t2 = &test_segments[left_compare[i].test_index2]; struct aspath *asp1, *asp2; printf ("left cmp %s: %s\n", t1->name, t1->desc); printf ("and %s: %s\n", t2->name, t2->desc); asp1 = make_aspath (t1->asdata, t1->len, 0); asp2 = make_aspath (t2->asdata, t2->len, 0); if (aspath_cmp_left (asp1, asp2) != left_compare[i].shouldbe_cmp || aspath_cmp_left (asp2, asp1) != left_compare[i].shouldbe_cmp || aspath_cmp_left_confed (asp1, asp2) != left_compare[i].shouldbe_confed || aspath_cmp_left_confed (asp2, asp1) != left_compare[i].shouldbe_confed) { failed++; printf (FAILED "\n"); printf ("result should be: cmp: %d, confed: %d\n", left_compare[i].shouldbe_cmp, left_compare[i].shouldbe_confed); printf ("got: cmp %d, cmp_confed: %d\n", aspath_cmp_left (asp1, asp2), aspath_cmp_left_confed (asp1, asp2)); printf("path1: %s\npath2: %s\n", aspath_print (asp1), aspath_print (asp2)); } else printf (OK "\n"); printf ("\n"); aspath_unintern (&asp1); aspath_unintern (&asp2); } } static int handle_attr_test (struct aspath_tests *t) { struct bgp bgp = { 0 }; struct peer peer = { 0 }; struct attr attr = { 0 }; int ret; int initfail = failed; struct aspath *asp; size_t datalen; asp = make_aspath (t->segment->asdata, t->segment->len, 0); peer.ibuf = stream_new (BGP_MAX_PACKET_SIZE); peer.obuf = stream_fifo_new (); peer.bgp = &bgp; peer.host = (char *)"none"; peer.fd = -1; peer.cap = t->cap; stream_write (peer.ibuf, t->attrheader, t->len); datalen = aspath_put (peer.ibuf, asp, t->as4 == AS4_DATA); if (t->old_segment) { char dummyaspath[] = { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, t->old_segment->len }; stream_write (peer.ibuf, dummyaspath, sizeof (dummyaspath)); stream_write (peer.ibuf, t->old_segment->asdata, t->old_segment->len); datalen += sizeof (dummyaspath) + t->old_segment->len; } ret = bgp_attr_parse (&peer, &attr, t->len + datalen, NULL, NULL); if (ret != t->result) { printf ("bgp_attr_parse returned %d, expected %d\n", ret, t->result); printf ("datalen %zd\n", datalen); failed++; } if (ret != 0) goto out; if (t->shouldbe && attr.aspath == NULL) { printf ("aspath is NULL, but should be: %s\n", t->shouldbe); failed++; } if (t->shouldbe && attr.aspath && strcmp (attr.aspath->str, t->shouldbe)) { printf ("attr str and 'shouldbe' mismatched!\n" "attr str: %s\n" "shouldbe: %s\n", attr.aspath->str, t->shouldbe); failed++; } if (!t->shouldbe && attr.aspath) { printf ("aspath should be NULL, but is: %s\n", attr.aspath->str); failed++; } out: if (attr.aspath) aspath_unintern (&attr.aspath); if (asp) aspath_unintern (&asp); return failed - initfail; } static void attr_test (struct aspath_tests *t) { printf ("%s\n", t->desc); printf ("%s\n\n", handle_attr_test (t) ? FAILED : OK); } int main (void) { int i = 0; bgp_master_init (); master = bm->master; bgp_option_set (BGP_OPT_NO_LISTEN); bgp_attr_init (); while (test_segments[i].name) { printf ("test %u\n", i); parse_test (&test_segments[i]); empty_prepend_test (&test_segments[i++]); } i = 0; while (prepend_tests[i].test1) { printf ("prepend test %u\n", i); prepend_test (&prepend_tests[i++]); } i = 0; while (aggregate_tests[i].test1) { printf ("aggregate test %u\n", i); aggregate_test (&aggregate_tests[i++]); } i = 0; while (reconcile_tests[i].test1) { printf ("reconcile test %u\n", i); as4_reconcile_test (&reconcile_tests[i++]); } i = 0; cmp_test(); i = 0; empty_get_test(); i = 0; while (aspath_tests[i].desc) { printf ("aspath_attr test %d\n", i); attr_test (&aspath_tests[i++]); } printf ("failures: %d\n", failed); printf ("aspath count: %ld\n", aspath_count()); return (failed + aspath_count()); } quagga-1.2.4/tests/bgp_capability_test.c000066400000000000000000000437521325323223500203140ustar00rootroot00000000000000/* * Copyright (C) 2007 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "vty.h" #include "stream.h" #include "privs.h" #include "memory.h" #include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" #define VT100_GREEN "\x1b[32m" #define VT100_YELLOW "\x1b[33m" #define CAPABILITY 0 #define DYNCAP 1 #define OPT_PARAM 2 /* need these to link in libbgp */ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; static int failed = 0; static int tty = 0; /* test segments to parse and validate, and use for other tests */ static struct test_segment { const char *name; const char *desc; const u_char data[1024]; int len; #define SHOULD_PARSE 0 #define SHOULD_ERR -1 int parses; /* whether it should parse or not */ as_t peek_for; /* what peek_for_as4_capability should say */ /* AFI/SAFI validation */ int validate_afi; afi_t afi; safi_t safi; #define VALID_AFI 1 #define INVALID_AFI 0 int afi_valid; } test_segments [] = { /* 0 */ { "caphdr", "capability header, and no more", { CAPABILITY_CODE_REFRESH, 0x0 }, 2, SHOULD_PARSE, }, /* 1 */ { "nodata", "header, no data but length says there is", { 0x1, 0xa }, 2, SHOULD_ERR, }, /* 2 */ { "padded", "valid, with padding", { CAPABILITY_CODE_REFRESH, 0x2, 0x0, 0x0 }, 4, SHOULD_PARSE, }, /* 3 */ { "minsize", "violates minsize requirement", { CAPABILITY_CODE_ORF, 0x2, 0x0, 0x0 }, 4, SHOULD_ERR, }, { NULL, NULL, {0}, 0, 0}, }; static struct test_segment mp_segments[] = { { "MP4", "MP IP/Uni", { 0x1, 0x4, 0x0, 0x1, 0x0, 0x1 }, 6, SHOULD_PARSE, 0, 1, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "MPv6", "MP IPv6/Uni", { 0x1, 0x4, 0x0, 0x2, 0x0, 0x1 }, 6, SHOULD_PARSE, 0, 1, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, /* 5 */ { "MP2", "MP IP/Multicast", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x2 }, 6, SHOULD_PARSE, 0, 1, AFI_IP, SAFI_MULTICAST, VALID_AFI, }, /* 6 */ { "MP3", "MP IP6/MPLS-labeled VPN", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x80 }, 6, SHOULD_PARSE, 0, 1, AFI_IP6, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, /* 7 */ { "MP5", "MP IP6/MPLS-VPN", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x4 }, 6, SHOULD_PARSE, 0, 1, AFI_IP6, SAFI_MPLS_VPN, VALID_AFI, }, /* 8 */ { "MP6", "MP IP4/MPLS-laveled VPN", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80 }, 6, SHOULD_PARSE, 0, 1, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, /* 10 */ { "MP8", "MP unknown AFI/SAFI", { CAPABILITY_CODE_MP, 0x4, 0x0, 0xa, 0x0, 0x81 }, 6, SHOULD_PARSE, 0, 1, 0xa, 0x81, INVALID_AFI, /* parses, but unknown */ }, /* 11 */ { "MP-short", "MP IP4/Unicast, length too short (< minimum)", { CAPABILITY_CODE_MP, 0x2, 0x0, 0x1, 0x0, 0x1 }, 6, SHOULD_ERR, }, /* 12 */ { "MP-overflow", "MP IP4/Unicast, length too long", { CAPABILITY_CODE_MP, 0x6, 0x0, 0x1, 0x0, 0x1 }, 6, SHOULD_ERR, 0, 1, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { NULL, NULL, {0}, 0, 0} }; static struct test_segment misc_segments[] = { /* 13 */ { "ORF", "ORF, simple, single entry, single tuple", { /* hdr */ CAPABILITY_CODE_ORF, 0x7, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x1, /* tuples */ 0x40, 0x3 }, 9, SHOULD_PARSE, }, /* 14 */ { "ORF-many", "ORF, multi entry/tuple", { /* hdr */ CAPABILITY_CODE_ORF, 0x21, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, ORF_MODE_BOTH, 0x80, ORF_MODE_RECEIVE, 0x80, ORF_MODE_SEND, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, ORF_MODE_BOTH, 0x80, ORF_MODE_RECEIVE, 0x80, ORF_MODE_SEND, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, ORF_MODE_RECEIVE, 0x80, ORF_MODE_SEND, 0x80, ORF_MODE_BOTH, }, 35, SHOULD_PARSE, }, /* 15 */ { "ORFlo", "ORF, multi entry/tuple, hdr length too short", { /* hdr */ CAPABILITY_CODE_ORF, 0x15, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, }, 35, SHOULD_ERR, /* It should error on invalid Route-Refresh.. */ }, /* 16 */ { "ORFlu", "ORF, multi entry/tuple, length too long", { /* hdr */ 0x3, 0x22, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, }, 35, SHOULD_ERR }, /* 17 */ { "ORFnu", "ORF, multi entry/tuple, entry number too long", { /* hdr */ 0x3, 0x21, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x4, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, }, 35, SHOULD_PARSE, /* parses, but last few tuples should be gibberish */ }, /* 18 */ { "ORFno", "ORF, multi entry/tuple, entry number too short", { /* hdr */ 0x3, 0x21, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x1, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, }, 35, SHOULD_PARSE, /* Parses, but should get gibberish afi/safis */ }, /* 17 */ { "ORFpad", "ORF, multi entry/tuple, padded to align", { /* hdr */ 0x3, 0x22, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, 0x00, }, 36, SHOULD_PARSE, }, /* 19 */ { "AS4", "AS4 capability", { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12 }, /* AS: 2882400018 */ 6, SHOULD_PARSE, 2882400018, }, { "AS4", "AS4 capability: short", { 0x41, 0x4, 0xab, 0xcd, 0xef }, /* AS: 2882400018 */ 5, SHOULD_ERR, }, { "AS4", "AS4 capability: long", { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12, 0x12 }, 7, SHOULD_ERR, 2882400018, }, { "GR", "GR capability", { /* hdr */ CAPABILITY_CODE_RESTART, 0xe, /* R-bit, time */ 0xf1, 0x12, /* afi */ 0x0, 0x1, /* safi */ 0x1, /* flags */ 0xf, /* afi */ 0x0, 0x2, /* safi */ 0x1, /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, /* flags */ 0x1, }, 16, SHOULD_PARSE, }, { "GR-short", "GR capability, but header length too short", { /* hdr */ 0x40, 0xa, /* R-bit, time */ 0xf1, 0x12, /* afi */ 0x0, 0x1, /* safi */ 0x1, /* flags */ 0xf, /* afi */ 0x0, 0x2, /* safi */ 0x1, /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, /* flags */ 0x1, }, 15 /* array is 16 though */, SHOULD_ERR, }, { "GR-long", "GR capability, but header length too long", { /* hdr */ 0x40, 0xf, /* R-bit, time */ 0xf1, 0x12, /* afi */ 0x0, 0x1, /* safi */ 0x1, /* flags */ 0xf, /* afi */ 0x0, 0x2, /* safi */ 0x1, /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, /* flags */ 0x01, }, 16, SHOULD_ERR, }, { "GR-trunc", "GR capability, but truncated", { /* hdr */ 0x40, 0xf, /* R-bit, time */ 0xf1, 0x12, /* afi */ 0x0, 0x1, /* safi */ 0x1, /* flags */ 0xf, /* afi */ 0x0, 0x2, /* safi */ 0x1, /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, /* flags */ 0x1, }, 15, SHOULD_ERR, }, { "GR-empty", "GR capability, but empty.", { /* hdr */ 0x40, 0x0, }, 2, SHOULD_ERR, }, { "MP-empty", "MP capability, but empty.", { /* hdr */ 0x1, 0x0, }, 2, SHOULD_ERR, }, { "ORF-empty", "ORF capability, but empty.", { /* hdr */ 0x3, 0x0, }, 2, SHOULD_ERR, }, { "AS4-empty", "AS4 capability, but empty.", { /* hdr */ 0x41, 0x0, }, 2, SHOULD_ERR, }, { "dyn-empty", "Dynamic capability, but empty.", { /* hdr */ 0x42, 0x0, }, 2, SHOULD_PARSE, }, { "dyn-old", "Dynamic capability (deprecated version)", { CAPABILITY_CODE_DYNAMIC, 0x0 }, 2, SHOULD_PARSE, }, { NULL, NULL, {0}, 0, 0} }; /* DYNAMIC message */ struct test_segment dynamic_cap_msgs[] = { { "DynCap", "Dynamic Capability Message, IP/Multicast", { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2 }, 7, SHOULD_PARSE, /* horrible alignment, just as with ORF */ }, { "DynCapLong", "Dynamic Capability Message, IP/Multicast, truncated", { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2 }, 5, SHOULD_ERR, }, { "DynCapPadded", "Dynamic Capability Message, IP/Multicast, padded", { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2, 0x0 }, 8, SHOULD_ERR, /* No way to tell padding from data.. */ }, { "DynCapMPCpadded", "Dynamic Capability Message, IP/Multicast, cap data padded", { 0x0, 0x1, 0x5, 0x0, 0x1, 0x0, 0x2, 0x0 }, 8, SHOULD_PARSE, /* You can though add padding to the capability data */ }, { "DynCapMPCoverflow", "Dynamic Capability Message, IP/Multicast, cap data != length", { 0x0, 0x1, 0x3, 0x0, 0x1, 0x0, 0x2, 0x0 }, 8, SHOULD_ERR, }, { NULL, NULL, {0}, 0, 0} }; /* Entire Optional-Parameters block */ struct test_segment opt_params[] = { { "Cap-singlets", "One capability per Optional-Param", { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ 0x02, 0x02, 0x80, 0x00, /* RR (old) */ 0x02, 0x02, 0x02, 0x00, /* RR */ }, 24, SHOULD_PARSE, }, { "Cap-series", "Series of capability, one Optional-Param", { 0x02, 0x10, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ 0x80, 0x00, /* RR (old) */ 0x02, 0x00, /* RR */ }, 18, SHOULD_PARSE, }, { "AS4more", "AS4 capability after other caps (singlets)", { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ 0x02, 0x02, 0x80, 0x00, /* RR (old) */ 0x02, 0x02, 0x02, 0x00, /* RR */ 0x02, 0x06, 0x41, 0x04, 0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */ }, 32, SHOULD_PARSE, 196614, }, { "AS4series", "AS4 capability, in series of capabilities", { 0x02, 0x16, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ 0x80, 0x00, /* RR (old) */ 0x02, 0x00, /* RR */ 0x41, 0x04, 0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */ }, 24, SHOULD_PARSE, 196614, }, { "AS4real", "AS4 capability, in series of capabilities", { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/uni */ 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/uni */ 0x02, 0x02, 0x80, 0x00, /* RR old */ 0x02, 0x02, 0x02, 0x00, /* RR */ 0x02, 0x06, 0x41, 0x04, 0x00, 0x03, 0x00, 0x06, /* AS4 */ }, 32, SHOULD_PARSE, 196614, }, { "AS4real2", "AS4 capability, in series of capabilities", { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0xfc, 0x03, 0x02, 0x09, 0x82, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x80, 0x03, 0x02, 0x09, 0x03, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x40, 0x03, 0x02, 0x02, 0x42, 0x00, }, 58, SHOULD_PARSE, 64515, }, { NULL, NULL, {0}, 0, 0} }; /* basic parsing test */ static void parse_test (struct peer *peer, struct test_segment *t, int type) { int ret; int capability = 0; as_t as4 = 0; int oldfailed = failed; int len = t->len; #define RANDOM_FUZZ 35 stream_reset (peer->ibuf); stream_put (peer->ibuf, NULL, RANDOM_FUZZ); stream_set_getp (peer->ibuf, RANDOM_FUZZ); switch (type) { case CAPABILITY: stream_putc (peer->ibuf, BGP_OPEN_OPT_CAP); stream_putc (peer->ibuf, t->len); break; case DYNCAP: /* for (i = 0; i < BGP_MARKER_SIZE; i++) stream_putc (peer->, 0xff); stream_putw (s, 0); stream_putc (s, BGP_MSG_CAPABILITY);*/ break; } stream_write (peer->ibuf, t->data, t->len); printf ("%s: %s\n", t->name, t->desc); switch (type) { case CAPABILITY: len += 2; /* to cover the OPT-Param header */ case OPT_PARAM: printf ("len: %u\n", len); /* peek_for_as4 wants getp at capibility*/ as4 = peek_for_as4_capability (peer, len); printf ("peek_for_as4: as4 is %u\n", as4); /* and it should leave getp as it found it */ assert (stream_get_getp (peer->ibuf) == RANDOM_FUZZ); ret = bgp_open_option_parse (peer, len, &capability); break; case DYNCAP: ret = bgp_capability_receive (peer, t->len); break; default: printf ("unknown type %u\n", type); exit(1); } if (!ret && t->validate_afi) { safi_t safi = t->safi; if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid) failed++; printf ("MP: %u/%u (%u): recv %u, nego %u\n", t->afi, t->safi, safi, peer->afc_recv[t->afi][safi], peer->afc_nego[t->afi][safi]); if (t->afi_valid == VALID_AFI) { if (!peer->afc_recv[t->afi][safi]) failed++; if (!peer->afc_nego[t->afi][safi]) failed++; } } if (as4 != t->peek_for) { printf ("as4 %u != %u\n", as4, t->peek_for); failed++; } printf ("parsed?: %s\n", ret ? "no" : "yes"); if (ret != t->parses) failed++; if (tty) printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET : VT100_GREEN "OK" VT100_RESET); else printf ("%s", (failed > oldfailed) ? "failed!" : "OK" ); if (failed) printf (" (%u)", failed); printf ("\n\n"); } static struct bgp *bgp; static as_t asn = 100; int main (void) { struct peer *peer; int i, j; conf_bgp_debug_fsm = -1UL; conf_bgp_debug_events = -1UL; conf_bgp_debug_packet = -1UL; conf_bgp_debug_normal = -1UL; conf_bgp_debug_as4 = -1UL; term_bgp_debug_fsm = -1UL; term_bgp_debug_events = -1UL; term_bgp_debug_packet = -1UL; term_bgp_debug_normal = -1UL; term_bgp_debug_as4 = -1UL; master = thread_master_create (); bgp_master_init (); bgp_option_set (BGP_OPT_NO_LISTEN); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); if (bgp_get (&bgp, &asn, NULL)) return -1; peer = peer_create_accept (bgp); peer->host = (char *) "foo"; for (i = AFI_IP; i < AFI_MAX; i++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++) { peer->afc[i][j] = 1; peer->afc_adv[i][j] = 1; } i = 0; while (mp_segments[i].name) parse_test (peer, &mp_segments[i++], CAPABILITY); /* These tests assume mp_segments tests set at least * one of the afc_nego's */ i = 0; while (test_segments[i].name) parse_test (peer, &test_segments[i++], CAPABILITY); i = 0; while (misc_segments[i].name) parse_test (peer, &misc_segments[i++], CAPABILITY); i = 0; while (opt_params[i].name) parse_test (peer, &opt_params[i++], OPT_PARAM); SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV); peer->status = Established; i = 0; while (dynamic_cap_msgs[i].name) parse_test (peer, &dynamic_cap_msgs[i++], DYNCAP); printf ("failures: %d\n", failed); return failed; } quagga-1.2.4/tests/bgp_mp_attr_test.c000066400000000000000000000672361325323223500176440ustar00rootroot00000000000000/* * Copyright (C) 2008 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "vty.h" #include "stream.h" #include "privs.h" #include "memory.h" #include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_nexthop.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" #define VT100_GREEN "\x1b[32m" #define VT100_YELLOW "\x1b[33m" #define CAPABILITY 0 #define DYNCAP 1 #define OPT_PARAM 2 /* need these to link in libbgp */ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; static int failed = 0; static int tty = 0; /* test segments to parse and validate, and use for other tests */ static struct test_segment { const char *name; const char *desc; const u_char data[1024]; int len; #define SHOULD_PARSE 0 #define SHOULD_ERR -1 int parses; /* whether it should parse or not */ /* AFI/SAFI validation */ afi_t afi; safi_t safi; #define VALID_AFI 1 #define INVALID_AFI 0 int afi_valid; } mp_reach_segments [] = { { "IPv6", "IPV6 MP Reach, global nexthop, 1 NLRI", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 16, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ }, (4 + 16 + 1 + 5), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-2", "IPV6 MP Reach, global nexthop, 2 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 16, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* ffee:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, }, (4 + 16 + 1 + 5 + 9), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-default", "IPV6 MP Reach, global nexthop, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 16, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 16 + 1 + 5 + 9 + 1), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-lnh", "IPV6 MP Reach, global+local nexthops, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 32, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nhlen", "IPV6 MP Reach, inappropriate nexthop length", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 4, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nhlen2", "IPV6 MP Reach, invalid nexthop length", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 5, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nhlen3", "IPV6 MP Reach, nexthop length overflow", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 32, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, }, (4 + 16), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nhlen4", "IPV6 MP Reach, nexthop length short", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 16, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nlri", "IPV6 MP Reach, NLRI bitlen overflow", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 32, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 120, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv4", "IPv4 MP Reach, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* nexthop bytes */ 4, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (4 + 4 + 1 + 3 + 4 + 1), SHOULD_PARSE, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-nhlen", "IPv4 MP Reach, nexthop lenth overflow", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* nexthop bytes */ 32, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (4 + 4 + 1 + 3 + 4 + 1), SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-nlrilen", "IPv4 MP Reach, nlri lenth overflow", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* nexthop bytes */ 4, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 30, 10, 0, /* 0/0 */ }, (4 + 4 + 1 + 3 + 2 + 1), SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-VPNv4", "IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ 0, 0, 0, 0, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 88 + 16, 0, 1, 2, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_AS */ 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ 10, 1, /* 10.1/16 */ 88 + 17, 0xff, 0, 0, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_IP */ 192, 168, 0, 1, /* IPv4 */ 10, 2, 3, /* 10.2.3/17 */ }, (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), SHOULD_PARSE, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { "IPv4-VPNv4-bogus-plen", "IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, NLRI / bogus p'len", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 1, 2, 0, 0xff, 3, 4, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (3 + 1 + 3*4 + 1 + 3 + 4 + 1), SHOULD_ERR, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { "IPv4-VPNv4-plen1-short", "IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen short", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ 0, 0, 0, 0, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 88 + 1, 0, 1, 2, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_AS */ 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ 10, 1, /* 10.1/16 */ 88 + 17, 0xff, 0, 0, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_IP */ 192, 168, 0, 1, /* IPv4 */ 10, 2, 3, /* 10.2.3/17 */ }, (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), SHOULD_ERR, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { "IPv4-VPNv4-plen1-long", "IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, 1st plen long", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ 0, 0, 0, 0, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 88 + 32, 0, 1, 2, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_AS */ 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ 10, 1, /* 10.1/16 */ 88 + 17, 0xff, 0, 0, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_IP */ 192, 168, 0, 1, /* IPv4 */ 10, 2, 3, /* 10.2.3/17 */ }, (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), SHOULD_ERR, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { "IPv4-VPNv4-plenn-long", "IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRIs, last plen long", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ 0, 0, 0, 0, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 88 + 16, 0, 1, 2, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_AS */ 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ 10, 1, /* 10.1/16 */ 88 + 17, 0xff, 0, 0, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_IP */ 192, 168, 0, 1, /* IPv4 */ 10, 2, 3, /* 10.2.3/17 */ 88 + 1, /* bogus */ }, (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3) + 1), SHOULD_ERR, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { "IPv4-VPNv4-plenn-short", "IPv4/VPNv4 MP Reach, RD, Nexthop, 2 NLRIs, last plen short", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ 0, 0, 0, 0, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 88 + 16, 0, 1, 2, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_AS */ 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ 10, 1, /* 10.1/16 */ 88 + 2, 0xff, 0, 0, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_IP */ 192, 168, 0, 1, /* IPv4 */ 10, 2, 3, /* 10.2.3/17 */ }, (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), SHOULD_ERR, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { "IPv4-VPNv4-bogus-rd-type", "IPv4/VPNv4 MP Reach, RD, NH, 2 NLRI, unknown RD in 1st (log, but parse)", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ 0, 0, 0, 0, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 88 + 16, 0, 1, 2, /* tag */ /* rd, 8 octets */ 0xff, 0, /* Bogus RD */ 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ 10, 1, /* 10.1/16 */ 88 + 17, 0xff, 0, 0, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_IP */ 192, 168, 0, 1, /* IPv4 */ 10, 2, 3, /* 10.2.3/17 */ }, (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3)), SHOULD_PARSE, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { "IPv4-VPNv4-0-nlri", "IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRI, 3rd 0 bogus", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 0, 0, /* RD defined to be 0 */ 0, 0, 0, 0, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 88 + 16, 0, 1, 2, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_AS */ 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ 10, 1, /* 10.1/16 */ 88 + 17, 0xff, 0, 0, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_IP */ 192, 168, 0, 1, /* IPv4 */ 10, 2, 3, /* 10.2.3/17 */ 0 /* 0/0, bogus for vpnv4 ?? */ }, (4 + 12 + 1 + (1+3+8+2) + (1+3+8+3) + 1), SHOULD_ERR, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, /* From bug #385 */ { "IPv6-bug", "IPv6, global nexthop, 1 default NLRI", { /* AFI / SAFI */ 0x0, 0x2, 0x1, /* nexthop bytes */ 0x20, /* Nexthop (global) */ 0x20, 0x01, 0x04, 0x70, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* Nexthop (local) */ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c, 0xdb, 0xff, 0xfe, 0xfe, 0xeb, 0x00, /* SNPA (defunct, MBZ) */ 0, /* NLRI tuples */ /* Should have 0 here for ::/0, but dont */ }, 37, SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { NULL, NULL, {0}, 0, 0} }; /* MP_UNREACH_NLRI tests */ static struct test_segment mp_unreach_segments [] = { { "IPv6-unreach", "IPV6 MP Unreach, 1 NLRI", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ }, (3 + 5), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-unreach2", "IPV6 MP Unreach, 2 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, }, (3 + 5 + 9), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-unreach-default", "IPV6 MP Unreach, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (3 + 5 + 9 + 1), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-unreach-nlri", "IPV6 MP Unreach, NLRI bitlen overflow", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* NLRI tuples */ 120, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0, /* ::/0 */ }, (3 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv4-unreach", "IPv4 MP Unreach, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (3 + 3 + 4 + 1), SHOULD_PARSE, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-unreach-nlrilen", "IPv4 MP Unreach, nlri length overflow", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 30, 10, 0, /* 0/0 */ }, (3 + 3 + 2 + 1), SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-unreach-VPNv4", "IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* NLRI tuples */ 88 + 16, 0, 1, 2, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_AS */ 0, 2, 0, 0xff, 3, 4, /* AS(2):val(4) */ 10, 1, /* 10.1/16 */ 88 + 17, 0xff, 0, 0, /* tag */ /* rd, 8 octets */ 0, 0, /* RD_TYPE_IP */ 192, 168, 0, 1, /* IPv4 */ 10, 2, 3, /* 10.2.3/17 */ }, (3 + (1+3+8+2) + (1+3+8+3)), SHOULD_PARSE, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, { NULL, NULL, {0}, 0, 0} }; /* nlri_parse indicates 0 on successful parse, and -1 otherwise. * attr_parse indicates BGP_ATTR_PARSE_PROCEED/0 on success, * and BGP_ATTR_PARSE_ERROR/-1 or lower negative ret on err. */ static void handle_result (struct peer *peer, struct test_segment *t, int parse_ret, int nlri_ret) { int oldfailed = failed; if (!parse_ret) { safi_t safi = t->safi; if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid) failed++; printf ("MP: %u/%u (%u): recv %u, nego %u\n", t->afi, t->safi, safi, peer->afc_recv[t->afi][safi], peer->afc_nego[t->afi][safi]); } printf ("mp attr parsed?: %s\n", parse_ret ? "no" : "yes"); if (!parse_ret) printf ("nrli parsed?: %s\n", nlri_ret ? "no" : "yes"); printf ("should parse?: %s\n", t->parses ? "no" : "yes"); if ((parse_ret != 0 || nlri_ret != 0) != (t->parses != 0)) failed++; if (tty) printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET : VT100_GREEN "OK" VT100_RESET); else printf ("%s", (failed > oldfailed) ? "failed!" : "OK" ); if (failed) printf (" (%u)", failed); printf ("\n\n"); } /* basic parsing test */ static void parse_test (struct peer *peer, struct test_segment *t, int type) { int parse_ret = 0, nlri_ret = 0; struct attr attr = { }; struct bgp_nlri nlri = { }; struct bgp_attr_parser_args attr_args = { .peer = peer, .length = t->len, .total = 1, .attr = &attr, .type = type, .flags = BGP_ATTR_FLAG_OPTIONAL, .startp = BGP_INPUT_PNT (peer), }; #define RANDOM_FUZZ 35 stream_reset (peer->ibuf); stream_put (peer->ibuf, NULL, RANDOM_FUZZ); stream_set_getp (peer->ibuf, RANDOM_FUZZ); stream_write (peer->ibuf, t->data, t->len); printf ("%s: %s\n", t->name, t->desc); if (type == BGP_ATTR_MP_REACH_NLRI) parse_ret = bgp_mp_reach_parse (&attr_args, &nlri); else parse_ret = bgp_mp_unreach_parse (&attr_args, &nlri); if (parse_ret == 0 && t->afi_valid == VALID_AFI) assert (nlri.afi == t->afi && nlri.safi == t->safi); if (!parse_ret) { if (type == BGP_ATTR_MP_REACH_NLRI) nlri_ret = bgp_nlri_parse (peer, &attr, &nlri); else nlri_ret = bgp_nlri_parse (peer, NULL, &nlri); } handle_result (peer, t, parse_ret, nlri_ret); } static struct bgp *bgp; static as_t asn = 100; int main (void) { struct peer *peer; int i, j; conf_bgp_debug_fsm = -1UL; conf_bgp_debug_events = -1UL; conf_bgp_debug_packet = -1UL; conf_bgp_debug_normal = -1UL; conf_bgp_debug_as4 = -1UL; term_bgp_debug_fsm = -1UL; term_bgp_debug_events = -1UL; term_bgp_debug_packet = -1UL; term_bgp_debug_normal = -1UL; term_bgp_debug_as4 = -1UL; master = thread_master_create (); bgp_master_init (); bgp_option_set (BGP_OPT_NO_LISTEN); bgp_attr_init (); bgp_address_init (); bgp_scan_init (); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); if (bgp_get (&bgp, &asn, NULL)) return -1; peer = peer_create_accept (bgp); peer->host = (char *)"foo"; peer->status = Established; for (i = AFI_IP; i < AFI_MAX; i++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++) { peer->afc[i][j] = 1; peer->afc_adv[i][j] = 1; } i = 0; while (mp_reach_segments[i].name) parse_test (peer, &mp_reach_segments[i++], BGP_ATTR_MP_REACH_NLRI); i = 0; while (mp_unreach_segments[i].name) parse_test (peer, &mp_unreach_segments[i++], BGP_ATTR_MP_UNREACH_NLRI); printf ("failures: %d\n", failed); return failed; } quagga-1.2.4/tests/bgp_mpath_test.c000066400000000000000000000332031325323223500172720ustar00rootroot00000000000000/* $QuaggaId: Format:%an, %ai, %h$ $ * * BGP Multipath Unit Test * Copyright (C) 2010 Google Inc. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "vty.h" #include "stream.h" #include "privs.h" #include "linklist.h" #include "memory.h" #include "zclient.h" #include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mpath.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" #define VT100_GREEN "\x1b[32m" #define VT100_YELLOW "\x1b[33m" #define OK VT100_GREEN "OK" VT100_RESET #define FAILED VT100_RED "failed" VT100_RESET #define TEST_PASSED 0 #define TEST_FAILED -1 #define EXPECT_TRUE(expr, res) \ if (!(expr)) \ { \ printf ("Test failure in %s line %u: %s\n", \ __FUNCTION__, __LINE__, #expr); \ (res) = TEST_FAILED; \ } typedef struct testcase_t__ testcase_t; typedef int (*test_setup_func)(testcase_t *); typedef int (*test_run_func)(testcase_t *); typedef int (*test_cleanup_func)(testcase_t *); struct testcase_t__ { const char *desc; void *test_data; void *verify_data; void *tmp_data; test_setup_func setup; test_run_func run; test_cleanup_func cleanup; }; /* need these to link in libbgp */ struct thread_master *master = NULL; struct zclient *zclient; struct zebra_privs_t bgpd_privs = { .user = NULL, .group = NULL, .vty_group = NULL, }; static int tty = 0; /* Create fake bgp instance */ static struct bgp * bgp_create_fake (as_t *as, const char *name) { struct bgp *bgp; afi_t afi; safi_t safi; if ( (bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp))) == NULL) return NULL; bgp_lock (bgp); //bgp->peer_self = peer_new (bgp); //bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "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; bgp->rsclient = list_new (); //bgp->rsclient->cmp = (int (*)(void*, void*)) peer_cmp; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { bgp->route[afi][safi] = bgp_table_init (afi, safi); bgp->aggregate[afi][safi] = bgp_table_init (afi, safi); bgp->rib[afi][safi] = bgp_table_init (afi, safi); bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; } 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; } /*========================================================= * Testcase for maximum-paths configuration */ static int setup_bgp_cfg_maximum_paths (testcase_t *t) { as_t asn = 1; t->tmp_data = bgp_create_fake (&asn, NULL); if (!t->tmp_data) return -1; return 0; } static int run_bgp_cfg_maximum_paths (testcase_t *t) { afi_t afi; safi_t safi; struct bgp *bgp; int api_result; int test_result = TEST_PASSED; bgp = t->tmp_data; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { /* test bgp_maximum_paths_set */ api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_EBGP, 10); EXPECT_TRUE (api_result == 0, test_result); api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_IBGP, 10); EXPECT_TRUE (api_result == 0, test_result); EXPECT_TRUE (bgp->maxpaths[afi][safi].maxpaths_ebgp == 10, test_result); EXPECT_TRUE (bgp->maxpaths[afi][safi].maxpaths_ibgp == 10, test_result); /* test bgp_maximum_paths_unset */ api_result = bgp_maximum_paths_unset (bgp, afi, safi, BGP_PEER_EBGP); EXPECT_TRUE (api_result == 0, test_result); api_result = bgp_maximum_paths_unset (bgp, afi, safi, BGP_PEER_IBGP); EXPECT_TRUE (api_result == 0, test_result); EXPECT_TRUE ((bgp->maxpaths[afi][safi].maxpaths_ebgp == BGP_DEFAULT_MAXPATHS), test_result); EXPECT_TRUE ((bgp->maxpaths[afi][safi].maxpaths_ibgp == BGP_DEFAULT_MAXPATHS), test_result); } return test_result; } static int cleanup_bgp_cfg_maximum_paths (testcase_t *t) { return bgp_delete ((struct bgp *)t->tmp_data); } testcase_t test_bgp_cfg_maximum_paths = { .desc = "Test bgp maximum-paths config", .setup = setup_bgp_cfg_maximum_paths, .run = run_bgp_cfg_maximum_paths, .cleanup = cleanup_bgp_cfg_maximum_paths, }; /*========================================================= * Testcase for bgp_mp_list */ struct bgp test_mp_bgp; struct peer test_mp_list_peer[] = { { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, { .local_as = 1, .as = 2, .bgp = &test_mp_bgp }, }; int test_mp_list_peer_count = sizeof (test_mp_list_peer)/ sizeof (struct peer); struct attr test_mp_list_attr[4]; struct bgp_info test_mp_list_info[] = { { .peer = &test_mp_list_peer[0], .attr = &test_mp_list_attr[0] }, { .peer = &test_mp_list_peer[1], .attr = &test_mp_list_attr[1] }, { .peer = &test_mp_list_peer[2], .attr = &test_mp_list_attr[1] }, { .peer = &test_mp_list_peer[3], .attr = &test_mp_list_attr[2] }, { .peer = &test_mp_list_peer[4], .attr = &test_mp_list_attr[3] }, }; int test_mp_list_info_count = sizeof (test_mp_list_info)/sizeof (struct bgp_info); static int setup_bgp_mp_list (testcase_t *t) { test_mp_list_attr[0].nexthop.s_addr = 0x01010101; test_mp_list_attr[1].nexthop.s_addr = 0x02020202; test_mp_list_attr[2].nexthop.s_addr = 0x03030303; test_mp_list_attr[3].nexthop.s_addr = 0x04040404; if ((test_mp_list_peer[0].su_remote = sockunion_str2su ("1.1.1.1")) == NULL) return -1; if ((test_mp_list_peer[1].su_remote = sockunion_str2su ("2.2.2.2")) == NULL) return -1; if ((test_mp_list_peer[2].su_remote = sockunion_str2su ("3.3.3.3")) == NULL) return -1; if ((test_mp_list_peer[3].su_remote = sockunion_str2su ("4.4.4.4")) == NULL) return -1; if ((test_mp_list_peer[4].su_remote = sockunion_str2su ("5.5.5.5")) == NULL) return -1; return 0; } static int run_bgp_mp_list (testcase_t *t) { struct list mp_list; struct listnode *mp_node; struct bgp_info *info; int i; int test_result = TEST_PASSED; bgp_mp_list_init (&mp_list); EXPECT_TRUE (listcount(&mp_list) == 0, test_result); bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); bgp_mp_list_add (&mp_list, &test_mp_list_info[4]); bgp_mp_list_add (&mp_list, &test_mp_list_info[2]); bgp_mp_list_add (&mp_list, &test_mp_list_info[3]); bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); for (i = 0, mp_node = mp_list.head; i < test_mp_list_info_count; i++, mp_node = listnextnode(mp_node)) { info = listgetdata(mp_node); EXPECT_TRUE (info == &test_mp_list_info[i], test_result); } bgp_mp_list_clear (&mp_list); EXPECT_TRUE (listcount(&mp_list) == 0, test_result); return test_result; } static int cleanup_bgp_mp_list (testcase_t *t) { int i; for (i = 0; i < test_mp_list_peer_count; i++) sockunion_free (test_mp_list_peer[i].su_remote); return 0; } testcase_t test_bgp_mp_list = { .desc = "Test bgp_mp_list", .setup = setup_bgp_mp_list, .run = run_bgp_mp_list, .cleanup = cleanup_bgp_mp_list, }; /*========================================================= * Testcase for bgp_info_mpath_update */ struct bgp_node test_rn; static int setup_bgp_info_mpath_update (testcase_t *t) { int i; str2prefix ("42.1.1.0/24", &test_rn.p); setup_bgp_mp_list (t); for (i = 0; i < test_mp_list_info_count; i++) bgp_info_add (&test_rn, &test_mp_list_info[i]); return 0; } static int run_bgp_info_mpath_update (testcase_t *t) { struct bgp_info *new_best, *old_best, *mpath; struct list mp_list; test_mp_bgp.maxpaths[AFI_IP][SAFI_UNICAST].maxpaths_ebgp = 3; test_mp_bgp.maxpaths[AFI_IP][SAFI_UNICAST].maxpaths_ibgp = 3; int test_result = TEST_PASSED; bgp_mp_list_init (&mp_list); bgp_mp_list_add (&mp_list, &test_mp_list_info[4]); bgp_mp_list_add (&mp_list, &test_mp_list_info[3]); bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[3]; old_best = NULL; bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, AFI_IP, SAFI_UNICAST); bgp_mp_list_clear (&mp_list); EXPECT_TRUE (bgp_info_mpath_count (new_best) == 2, test_result); mpath = bgp_info_mpath_first (new_best); EXPECT_TRUE (mpath == &test_mp_list_info[0], test_result); EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); mpath = bgp_info_mpath_next (mpath); EXPECT_TRUE (mpath == &test_mp_list_info[1], test_result); EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[0]; old_best = &test_mp_list_info[3]; bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, AFI_IP, SAFI_UNICAST); bgp_mp_list_clear (&mp_list); EXPECT_TRUE (bgp_info_mpath_count (new_best) == 1, test_result); mpath = bgp_info_mpath_first (new_best); EXPECT_TRUE (mpath == &test_mp_list_info[1], test_result); EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); EXPECT_TRUE (!CHECK_FLAG (test_mp_list_info[0].flags, BGP_INFO_MULTIPATH), test_result); return test_result; } static int cleanup_bgp_info_mpath_update (testcase_t *t) { int i; for (i = 0; i < test_mp_list_peer_count; i++) sockunion_free (test_mp_list_peer[i].su_remote); return 0; } testcase_t test_bgp_info_mpath_update = { .desc = "Test bgp_info_mpath_update", .setup = setup_bgp_info_mpath_update, .run = run_bgp_info_mpath_update, .cleanup = cleanup_bgp_info_mpath_update, }; /*========================================================= * Set up testcase vector */ testcase_t *all_tests[] = { &test_bgp_cfg_maximum_paths, &test_bgp_mp_list, &test_bgp_info_mpath_update, }; int all_tests_count = (sizeof(all_tests)/sizeof(testcase_t *)); /*========================================================= * Test Driver Functions */ static int global_test_init (void) { master = thread_master_create (); zclient = zclient_new (master); bgp_master_init (); bgp_option_set (BGP_OPT_NO_LISTEN); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); return 0; } static int global_test_cleanup (void) { if (zclient != NULL) zclient_free (zclient); thread_master_free (master); return 0; } static void display_result (testcase_t *test, int result) { if (tty) printf ("%s: %s\n", test->desc, result == TEST_PASSED ? OK : FAILED); else printf ("%s: %s\n", test->desc, result == TEST_PASSED ? "OK" : "FAILED"); } static int setup_test (testcase_t *t) { int res = 0; if (t->setup) res = t->setup (t); return res; } static int cleanup_test (testcase_t *t) { int res = 0; if (t->cleanup) res = t->cleanup (t); return res; } static void run_tests (testcase_t *tests[], int num_tests, int *pass_count, int *fail_count) { int test_index, result; testcase_t *cur_test; *pass_count = *fail_count = 0; for (test_index = 0; test_index < num_tests; test_index++) { cur_test = tests[test_index]; if (!cur_test->desc) { printf ("error: test %d has no description!\n", test_index); continue; } if (!cur_test->run) { printf ("error: test %s has no run function!\n", cur_test->desc); continue; } if (setup_test (cur_test) != 0) { printf ("error: setup failed for test %s\n", cur_test->desc); continue; } result = cur_test->run (cur_test); if (result == TEST_PASSED) *pass_count += 1; else *fail_count += 1; display_result (cur_test, result); if (cleanup_test (cur_test) != 0) { printf ("error: cleanup failed for test %s\n", cur_test->desc); continue; } } } int main (void) { int pass_count, fail_count; time_t cur_time; time (&cur_time); printf("BGP Multipath Tests Run at %s", ctime(&cur_time)); if (global_test_init () != 0) { printf("Global init failed. Terminating.\n"); exit(1); } run_tests (all_tests, all_tests_count, &pass_count, &fail_count); global_test_cleanup (); printf("Total pass/fail: %d/%d\n", pass_count, fail_count); return fail_count; } quagga-1.2.4/tests/common-cli.c000066400000000000000000000041111325323223500163230ustar00rootroot00000000000000/* * generic CLI test helper functions * * Copyright (C) 2015 by David Lamparter, * for Open Source Routing / NetDEF, Inc. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "memory.h" #include "log.h" #include "common-cli.h" struct thread_master *master; int dump_args(struct vty *vty, const char *descr, int argc, const char **argv) { int i; vty_out (vty, "%s with %d args.%s", descr, argc, VTY_NEWLINE); for (i = 0; i < argc; i++) { vty_out (vty, "[%02d]: %s%s", i, argv[i], VTY_NEWLINE); } return CMD_SUCCESS; } static void vty_do_exit(void) { printf ("\nend.\n"); exit (0); } /* main routine. */ int main (int argc, char **argv) { /* Set umask before anything for security */ umask (0027); /* master init. */ master = thread_master_create (); zlog_default = openzlog ("common-cli", ZLOG_NONE, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); zlog_set_level (NULL, ZLOG_DEST_MONITOR, LOG_DEBUG); /* Library inits. */ cmd_init (1); host.name = strdup ("test"); vty_init (master); memory_init (); test_init (); vty_stdio (vty_do_exit); /* Fetch next active thread. */ thread_main (master); /* Not reached. */ exit (0); } quagga-1.2.4/tests/common-cli.h000066400000000000000000000030701325323223500163330ustar00rootroot00000000000000/* * generic CLI test helper functions * * Copyright (C) 2015 by David Lamparter, * for Open Source Routing / NetDEF, Inc. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _COMMON_CLI_H #define _COMMON_CLI_H #include "zebra.h" #include "vty.h" #include "command.h" /* function to be implemented by test */ extern void test_init (void); /* functions provided by common cli * (includes main()) */ extern struct thread_master *master; extern int dump_args(struct vty *vty, const char *descr, int argc, const char **argv); #define DUMMY_HELPSTR \ "00\n01\n02\n03\n04\n05\n06\n07\n08\n09\n" \ "10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n" \ "20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n" #define DUMMY_DEFUN(name, cmdstr) \ DEFUN (name, name ## _cmd, cmdstr, DUMMY_HELPSTR) \ { return dump_args(vty, #name, argc, argv); } #endif /* _COMMON_CLI_H */ quagga-1.2.4/tests/ecommunity_test.c000066400000000000000000000074121325323223500175250ustar00rootroot00000000000000/* * Copyright (C) 2007 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "vty.h" #include "stream.h" #include "privs.h" #include "memory.h" #include "filter.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" /* need these to link in libbgp */ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; static int failed = 0; /* specification for a test - what the results should be */ struct test_spec { const char *shouldbe; /* the string the path should parse to */ }; /* test segments to parse and validate, and use for other tests */ static struct test_segment { const char *name; const char *desc; const u_int8_t data[1024]; int len; struct test_spec sp; } test_segments [] = { { /* 0 */ "ipaddr", "rt 1.2.3.4:257", { ECOMMUNITY_ENCODE_IP, ECOMMUNITY_ROUTE_TARGET, 0x1,0x2,0x3,0x4, 0x1,0x1 }, 8, { "rt 1.2.3.4:257" } }, { /* 1 */ "ipaddr-so", "soo 1.2.3.4:257", { ECOMMUNITY_ENCODE_IP, ECOMMUNITY_SITE_ORIGIN, 0x1,0x2,0x3,0x4, 0x1,0x1}, 8, { "soo 1.2.3.4:257" } }, { /* 2 */ "asn", "rt 23456:987654321", { ECOMMUNITY_ENCODE_AS, ECOMMUNITY_SITE_ORIGIN, 0x5b,0xa0, 0x3a,0xde,0x68,0xb1 }, 8, { "soo 23456:987654321" } }, { /* 3 */ "asn4", "rt 168450976:4321", { ECOMMUNITY_ENCODE_AS4, ECOMMUNITY_SITE_ORIGIN, 0xa,0xa,0x5b,0xa0, 0x10,0xe1 }, 8, { "soo 168450976:4321" } }, { NULL, NULL, {0}, 0, { NULL } } }; /* validate the given aspath */ static int validate (struct ecommunity *ecom, const struct test_spec *sp) { int fails = 0; struct ecommunity *etmp; char *str1, *str2; printf ("got:\n %s\n", ecommunity_str (ecom)); str1 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST); etmp = ecommunity_str2com (str1, 0, 1); if (etmp) str2 = ecommunity_ecom2str (etmp, ECOMMUNITY_FORMAT_COMMUNITY_LIST); else str2 = NULL; if (strcmp (sp->shouldbe, str1)) { failed++; fails++; printf ("shouldbe: %s\n%s\n", str1, sp->shouldbe); } if (!etmp || strcmp (str1, str2)) { failed++; fails++; printf ("dogfood: in %s\n" " in->out %s\n", str1, (etmp && str2) ? str2 : "NULL"); } ecommunity_free (&etmp); XFREE (MTYPE_ECOMMUNITY_STR, str1); XFREE (MTYPE_ECOMMUNITY_STR, str2); return fails; } /* basic parsing test */ static void parse_test (struct test_segment *t) { struct ecommunity *ecom; printf ("%s: %s\n", t->name, t->desc); ecom = ecommunity_parse ((u_int8_t *)t->data, t->len); printf ("ecom: %s\nvalidating...:\n", ecommunity_str (ecom)); if (!validate (ecom, &t->sp)) printf ("OK\n"); else printf ("failed\n"); printf ("\n"); ecommunity_unintern (&ecom); } int main (void) { int i = 0; ecommunity_init(); while (test_segments[i].name) parse_test (&test_segments[i++]); printf ("failures: %d\n", failed); //printf ("aspath count: %ld\n", aspath_count()); return failed; //return (failed + aspath_count()); } quagga-1.2.4/tests/heavy-thread.c000066400000000000000000000066761325323223500166710ustar00rootroot00000000000000/* * $Id: heavy-thread.c,v 1.2 2005/04/25 16:42:24 paul Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* This programme shows the effects of 'heavy' long-running functions * on the cooperative threading model, as demonstrated by heavy.c, and how * they can be mitigated using a background thread. * * Run it with a config file containing 'password whatever', telnet to it * (it defaults to port 4000) and enter the 'clear foo string' command. * then type whatever and observe that, unlike heavy.c, the vty interface * remains responsive. */ #include #include #include "thread.h" #include "vty.h" #include "command.h" #include "memory.h" #include "log.h" #include "tests.h" extern struct thread_master *master; enum { ITERS_FIRST = 0, ITERS_ERR = 100, ITERS_LATER = 400, ITERS_PRINT = 10, ITERS_MAX = 1000, }; struct work_state { struct vty *vty; char *str; int i; }; static void slow_func (struct vty *vty, const char *str, const int i) { double x = 1; int j; for (j = 0; j < 300; j++) x += sin(x)*j; if ((i % ITERS_LATER) == 0) printf ("%s: %d, temporary error, save this somehow and do it later..\n", __func__, i); if ((i % ITERS_ERR) == 0) printf ("%s: hard error\n", __func__); if ((i % ITERS_PRINT) == 0) printf ("%s did %d, x = %g\n", str, i, x); } static int clear_something (struct thread *thread) { struct work_state *ws = THREAD_ARG(thread); /* this could be like iterating through 150k of route_table * or worse, iterating through a list of peers, to bgp_stop them with * each having 150k route tables to process... */ while (ws->i < ITERS_MAX) { slow_func(ws->vty, ws->str, ws->i); ws->i++; if (thread_should_yield(thread)) { thread_add_background(master, clear_something, ws, 0); return 0; } } /* All done! */ XFREE (MTYPE_TMP, ws->str); XFREE (MTYPE_TMP, ws); return 0; } DEFUN (clear_foo, clear_foo_cmd, "clear foo .LINE", "clear command\n" "arbitrary string\n") { char *str; struct work_state *ws; if (!argc) { vty_out (vty, "%% string argument required%s", VTY_NEWLINE); return CMD_WARNING; } str = argv_concat (argv, argc, 0); if ((ws = XMALLOC(MTYPE_TMP, sizeof(*ws))) == NULL) { zlog_err ("%s: unable to allocate work_state", __func__); return CMD_WARNING; } if (!(ws->str = XSTRDUP (MTYPE_TMP, str))) { zlog_err ("%s: unable to xstrdup", __func__); XFREE (MTYPE_TMP, ws); return CMD_WARNING; } ws->vty = vty; ws->i = ITERS_FIRST; thread_add_background(master, clear_something, ws, 0); return CMD_SUCCESS; } void test_init() { install_element (VIEW_NODE, &clear_foo_cmd); } quagga-1.2.4/tests/heavy-wq.c000066400000000000000000000101131325323223500160260ustar00rootroot00000000000000/* * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* This programme shows the effects of 'heavy' long-running functions * on the cooperative threading model. * * Run it with a config file containing 'password whatever', telnet to it * (it defaults to port 4000) and enter the 'clear foo string' command. * then type whatever and observe that the vty interface is unresponsive * for quite a period of time, due to the clear_something command * taking a very long time to complete. */ #include #include "thread.h" #include "vty.h" #include "command.h" #include "memory.h" #include "log.h" #include "workqueue.h" #include #include "tests.h" extern struct thread_master *master; static struct work_queue *heavy_wq; struct heavy_wq_node { char *str; int i; }; enum { ITERS_FIRST = 0, ITERS_ERR = 100, ITERS_LATER = 400, ITERS_PRINT = 10, ITERS_MAX = 1000, }; static void heavy_wq_add (struct vty *vty, const char *str, int i) { struct heavy_wq_node *hn; if ((hn = XCALLOC (MTYPE_PREFIX_LIST, sizeof(struct heavy_wq_node))) == NULL) { zlog_err ("%s: unable to allocate hn", __func__); return; } hn->i = i; if (!(hn->str = XSTRDUP (MTYPE_PREFIX_LIST_STR, str))) { zlog_err ("%s: unable to xstrdup", __func__); XFREE (MTYPE_PREFIX_LIST, hn); return; } work_queue_add (heavy_wq, hn); return; } static void slow_func_err (struct work_queue *wq, struct work_queue_item *item) { printf ("%s: running error function\n", __func__); } static void slow_func_del (struct work_queue *wq, void *data) { struct heavy_wq_node *hn = data; assert (hn && hn->str); printf ("%s: %s\n", __func__, hn->str); XFREE (MTYPE_PREFIX_LIST_STR, hn->str); hn->str = NULL; XFREE(MTYPE_PREFIX_LIST, hn); } static wq_item_status slow_func (struct work_queue *wq, void *data) { struct heavy_wq_node *hn = data; double x = 1; int j; assert (hn && hn->str); for (j = 0; j < 300; j++) x += sin(x)*j; if ((hn->i % ITERS_LATER) == 0) return WQ_RETRY_LATER; if ((hn->i % ITERS_ERR) == 0) return WQ_RETRY_NOW; if ((hn->i % ITERS_PRINT) == 0) printf ("%s did %d, x = %g\n", hn->str, hn->i, x); return WQ_SUCCESS; } static void clear_something (struct vty *vty, const char *str) { int i; /* this could be like iterating through 150k of route_table * or worse, iterating through a list of peers, to bgp_stop them with * each having 150k route tables to process... */ for (i = ITERS_FIRST; i < ITERS_MAX; i++) heavy_wq_add (vty, str, i); } DEFUN (clear_foo, clear_foo_cmd, "clear foo .LINE", "clear command\n" "arbitrary string\n") { char *str; if (!argc) { vty_out (vty, "%% string argument required%s", VTY_NEWLINE); return CMD_WARNING; } str = argv_concat (argv, argc, 0); clear_something (vty, str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; } static int heavy_wq_init () { if (! (heavy_wq = work_queue_new (master, "heavy_work_queue"))) { zlog_err ("%s: could not get new work queue!", __func__); return -1; } heavy_wq->spec.workfunc = &slow_func; heavy_wq->spec.errorfunc = &slow_func_err; heavy_wq->spec.del_item_data = &slow_func_del; heavy_wq->spec.max_retries = 3; heavy_wq->spec.hold = 1000; return 0; } void test_init() { install_element (VIEW_NODE, &clear_foo_cmd); heavy_wq_init(); } quagga-1.2.4/tests/heavy.c000066400000000000000000000053471325323223500154160ustar00rootroot00000000000000/* * $Id: heavy.c,v 1.3 2005/04/25 16:42:24 paul Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* This programme shows the effects of 'heavy' long-running functions * on the cooperative threading model. * * Run it with a config file containing 'password whatever', telnet to it * (it defaults to port 4000) and enter the 'clear foo string' command. * then type whatever and observe that the vty interface is unresponsive * for quite a period of time, due to the clear_something command * taking a very long time to complete. */ #include #include "thread.h" #include "vty.h" #include "command.h" #include "memory.h" #include #include "tests.h" enum { ITERS_FIRST = 0, ITERS_ERR = 100, ITERS_LATER = 400, ITERS_PRINT = 10, ITERS_MAX = 1000, }; static void slow_func (struct vty *vty, const char *str, const int i) { double x = 1; int j; for (j = 0; j < 300; j++) x += sin(x)*j; if ((i % ITERS_LATER) == 0) printf ("%s: %d, temporary error, save this somehow and do it later..\n", __func__, i); if ((i % ITERS_ERR) == 0) printf ("%s: hard error\n", __func__); if ((i % ITERS_PRINT) == 0) printf ("%s did %d, x = %g%s", str, i, x, VTY_NEWLINE); } static void clear_something (struct vty *vty, const char *str) { int i; /* this could be like iterating through 150k of route_table * or worse, iterating through a list of peers, to bgp_stop them with * each having 150k route tables to process... */ for (i = ITERS_FIRST; i < ITERS_MAX; i++) slow_func (vty, str, i); } DEFUN (clear_foo, clear_foo_cmd, "clear foo .LINE", "clear command\n" "arbitrary string\n") { char *str; if (!argc) { vty_out (vty, "%% string argument required%s", VTY_NEWLINE); return CMD_WARNING; } str = argv_concat (argv, argc, 0); clear_something (vty, str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; } static void slow_vty_init() { install_element (VIEW_NODE, &clear_foo_cmd); } void test_init() { slow_vty_init(); } quagga-1.2.4/tests/main.c000066400000000000000000000103041325323223500152130ustar00rootroot00000000000000/* * $Id: main.c,v 1.1 2005/04/25 16:42:24 paul Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "getopt.h" #include "thread.h" #include "vty.h" #include "command.h" #include "memory.h" extern void test_init(); struct thread_master *master; struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "version", no_argument, NULL, 'v'}, { 0 } }; DEFUN (daemon_exit, daemon_exit_cmd, "daemon-exit", "Make the daemon exit\n") { exit(0); } static int timer_count; static int test_timer (struct thread *thread) { int *count = THREAD_ARG(thread); printf ("run %d of timer\n", (*count)++); thread_add_timer (master, test_timer, count, 5); return 0; } static void test_timer_init() { thread_add_timer (master, test_timer, &timer_count, 10); } static void test_vty_init() { install_element (VIEW_NODE, &daemon_exit_cmd); } /* 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 does 'slow' things.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration 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); } /* main routine. */ int main (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = 4000; int daemon_mode = 0; char *progname; char *config_file = NULL; /* Set umask before anything for security */ umask (0027); /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); /* master init. */ master = thread_master_create (); while (1) { int opt; opt = getopt_long (argc, argv, "dhf:A:P:v", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'f': config_file = optarg; break; case 'd': daemon_mode = 1; break; case 'A': vty_addr = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); vty_port = (vty_port ? vty_port : 4000); break; case 'v': print_version (progname); exit (0); break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Library inits. */ cmd_init (1); vty_init (master); memory_init (); /* OSPF vty inits. */ test_vty_init (); /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { fprintf(stderr, "daemon failed: %s", strerror(errno)); exit (1); } /* Create VTY socket */ vty_serv_sock (vty_addr, vty_port, "/tmp/.heavy.sock"); /* Configuration file read*/ if (!config_file) usage (progname, 1); vty_read_config (config_file, NULL); test_timer_init(); test_init(); /* Fetch next active thread. */ thread_main (master); /* Not reached. */ exit (0); } quagga-1.2.4/tests/prng.c000066400000000000000000000055431325323223500152460ustar00rootroot00000000000000/* * Very simple prng to allow for randomized tests with reproducable * results. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "prng.h" struct prng { unsigned long long state1; unsigned long long state2; }; static char prng_bit(struct prng *prng) { prng->state1 *= 2416; prng->state1 += 374441; prng->state1 %= 1771875; if (prng->state1 % 2) { prng->state2 *= 84589; prng->state2 += 45989; prng->state2 %= 217728; } return prng->state2 % 2; } struct prng* prng_new(unsigned long long seed) { struct prng *rv = calloc(sizeof(*rv), 1); assert(rv); rv->state1 = rv->state2 = seed; return rv; } unsigned int prng_rand(struct prng *prng) { unsigned int i, rv = 0; for (i = 0; i < 32; i++) { rv |= prng_bit(prng); rv <<= 1; } return rv; } const char * prng_fuzz(struct prng *prng, const char *string, const char *charset, unsigned int operations) { static char buf[256]; unsigned int charset_len; unsigned int i; unsigned int offset; unsigned int op; unsigned int character; assert(strlen(string) < sizeof(buf)); strncpy(buf, string, sizeof(buf)); charset_len = strlen(charset); for (i = 0; i < operations; i++) { offset = prng_rand(prng) % strlen(buf); op = prng_rand(prng) % 3; switch (op) { case 0: /* replace */ character = prng_rand(prng) % charset_len; buf[offset] = charset[character]; break; case 1: /* remove */ memmove(buf + offset, buf + offset + 1, strlen(buf) - offset); break; case 2: /* insert */ assert(strlen(buf) + 1 < sizeof(buf)); memmove(buf + offset + 1, buf + offset, strlen(buf) + 1 - offset); character = prng_rand(prng) % charset_len; buf[offset] = charset[character]; break; } } return buf; } void prng_free(struct prng *prng) { free(prng); } quagga-1.2.4/tests/prng.h000066400000000000000000000024141325323223500152450ustar00rootroot00000000000000/* * Very simple prng to allow for randomized tests with reproducable * results. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _PRNG_H #define _PRNG_H struct prng; struct prng* prng_new(unsigned long long seed); unsigned int prng_rand(struct prng*); const char * prng_fuzz(struct prng*, const char *string, const char *charset, unsigned int operations); void prng_free(struct prng *); #endif quagga-1.2.4/tests/table_test.c000066400000000000000000000273341325323223500164300ustar00rootroot00000000000000/* $QuaggaId: Format:%an, %ai, %h$ $ * * Routing table test * Copyright (C) 2012 OSR. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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" /* * test_node_t * * Information that is kept for each node in the radix tree. */ typedef struct test_node_t_ { /* * Human readable representation of the string. Allocated using * malloc()/dup(). */ char *prefix_str; } test_node_t; struct thread_master *master; /* * add_node * * Add the given prefix (passed in as a string) to the given table. */ static void add_node (struct route_table *table, const char *prefix_str) { struct prefix_ipv4 p; test_node_t *node; struct route_node *rn; assert (prefix_str); if (str2prefix_ipv4 (prefix_str, &p) <= 0) { assert (0); } rn = route_node_get (table, (struct prefix *) &p); if (rn->info) { assert (0); return; } node = malloc (sizeof (test_node_t)); assert (node); node->prefix_str = strdup (prefix_str); assert (node->prefix_str); rn->info = node; } /* * add_nodes * * Convenience function to add a bunch of nodes together. * * The arguments must be prefixes in string format, with a NULL as the * last argument. */ static void add_nodes (struct route_table *table, ...) { va_list arglist; char *prefix; va_start (arglist, table); prefix = va_arg (arglist, char *); while (prefix) { add_node (table, prefix); prefix = va_arg (arglist, char *); } va_end (arglist); } /* * print_subtree * * Recursive function to print a route node and its children. * * @see print_table */ static void print_subtree (struct route_node *rn, const char *legend, int indent_level) { char buf[INET_ADDRSTRLEN + 4]; int i; /* * Print this node first. */ for (i = 0; i < indent_level; i++) { printf (" "); } prefix2str (&rn->p, buf, sizeof (buf)); printf ("%s: %s", legend, buf); if (!rn->info) { printf (" (internal)"); } printf ("\n"); if (rn->l_left) { print_subtree (rn->l_left, "Left", indent_level + 1); } if (rn->l_right) { print_subtree (rn->l_right, "Right", indent_level + 1); } } /* * print_table * * Function that prints out the internal structure of a route table. */ static void print_table (struct route_table *table) { struct route_node *rn; rn = table->top; if (!rn) { printf ("\n"); return; } print_subtree (rn, "Top", 0); } /* * clear_table * * Remove all nodes from the given table. */ static void clear_table (struct route_table *table) { route_table_iter_t iter; struct route_node *rn; test_node_t *node; route_table_iter_init (&iter, table); while ((rn = route_table_iter_next (&iter))) { node = rn->info; if (!node) { continue; } rn->info = NULL; route_unlock_node (rn); free (node->prefix_str); free (node); } route_table_iter_cleanup (&iter); assert (table->top == NULL); } /* * verify_next_by_iterating * * Iterate over the tree to make sure that the first prefix after * target_pfx is the expected one. Note that target_pfx may not be * present in the tree. */ static void verify_next_by_iterating (struct route_table *table, struct prefix *target_pfx, struct prefix *next_pfx) { route_table_iter_t iter; struct route_node *rn; route_table_iter_init (&iter, table); while ((rn = route_table_iter_next (&iter))) { if (route_table_prefix_iter_cmp (&rn->p, target_pfx) > 0) { assert (!prefix_cmp (&rn->p, next_pfx)); break; } } if (!rn) { assert (!next_pfx); } route_table_iter_cleanup (&iter); } /* * verify_next * * Verifies that route_table_get_next() returns the expected result * (result) for the prefix string 'target'. */ static void verify_next (struct route_table *table, const char *target, const char *next) { struct prefix_ipv4 target_pfx, next_pfx; struct route_node *rn; char result_buf[INET_ADDRSTRLEN + 4]; if (str2prefix_ipv4 (target, &target_pfx) <= 0) { assert (0); } rn = route_table_get_next (table, (struct prefix *) &target_pfx); if (rn) { prefix2str (&rn->p, result_buf, sizeof (result_buf)); } else { snprintf (result_buf, sizeof (result_buf), "(Null)"); } printf ("\n"); print_table (table); printf ("Verifying successor of %s. Expected: %s, Result: %s\n", target, next ? next : "(Null)", result_buf); if (!rn) { assert (!next); verify_next_by_iterating (table, (struct prefix *) &target_pfx, NULL); return; } assert (next); if (str2prefix_ipv4 (next, &next_pfx) <= 0) { assert (0); } if (prefix_cmp (&rn->p, (struct prefix *) &next_pfx)) { assert (0); } route_unlock_node (rn); verify_next_by_iterating (table, (struct prefix *) &target_pfx, (struct prefix *) &next_pfx); } /* * test_get_next */ static void test_get_next (void) { struct route_table *table; printf ("\n\nTesting route_table_get_next()\n"); table = route_table_init (); /* * Target exists in tree, but has no successor. */ add_nodes (table, "1.0.1.0/24", NULL); verify_next (table, "1.0.1.0/24", NULL); clear_table (table); /* * Target exists in tree, and there is a node in its left subtree. */ add_nodes (table, "1.0.1.0/24", "1.0.1.0/25", NULL); verify_next (table, "1.0.1.0/24", "1.0.1.0/25"); clear_table (table); /* * Target exists in tree, and there is a node in its right subtree. */ add_nodes (table, "1.0.1.0/24", "1.0.1.128/25", NULL); verify_next (table, "1.0.1.0/24", "1.0.1.128/25"); clear_table (table); /* * Target exists in the tree, next node is outside subtree. */ add_nodes (table, "1.0.1.0/24", "1.1.0.0/16", NULL); verify_next (table, "1.0.1.0/24", "1.1.0.0/16"); clear_table (table); /* * The target node does not exist in the tree for all the test cases * below this point. */ /* * There is no successor in the tree. */ add_nodes (table, "1.0.0.0/16", NULL); verify_next (table, "1.0.1.0/24", NULL); clear_table (table); /* * There exists a node that would be in the target's left subtree. */ add_nodes (table, "1.0.0.0/16", "1.0.1.0/25", NULL); verify_next (table, "1.0.1.0/24", "1.0.1.0/25"); clear_table (table); /* * There exists a node would be in the target's right subtree. */ add_nodes (table, "1.0.0.0/16", "1.0.1.128/25", NULL); verify_next (table, "1.0.1.0/24", "1.0.1.128/25"); clear_table (table); /* * A search for the target reaches a node where there are no child * nodes in the direction of the target (left), but the node has a * right child. */ add_nodes (table, "1.0.0.0/16", "1.0.128.0/17", NULL); verify_next (table, "1.0.0.0/17", "1.0.128.0/17"); clear_table (table); /* * A search for the target reaches a node with no children. We have * to go upwards in the tree to find a successor. */ add_nodes (table, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/24", "1.0.128.0/17", NULL); verify_next (table, "1.0.1.0/25", "1.0.128.0/17"); clear_table (table); /* * A search for the target reaches a node where neither the node nor * the target prefix contain each other. * * In first case below the node succeeds the target. * * In the second case, the node comes before the target, so we have * to go up the tree looking for a successor. */ add_nodes (table, "1.0.0.0/16", "1.0.1.0/24", NULL); verify_next (table, "1.0.0.0/24", "1.0.1.0/24"); clear_table (table); add_nodes (table, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/25", "1.0.128.0/17", NULL); verify_next (table, "1.0.1.128/25", "1.0.128.0/17"); clear_table (table); route_table_finish (table); } /* * verify_prefix_iter_cmp */ static void verify_prefix_iter_cmp (const char *p1, const char *p2, int exp_result) { struct prefix_ipv4 p1_pfx, p2_pfx; int result; if (str2prefix_ipv4 (p1, &p1_pfx) <= 0) { assert (0); } if (str2prefix_ipv4 (p2, &p2_pfx) <= 0) { assert (0); } result = route_table_prefix_iter_cmp ((struct prefix *) &p1_pfx, (struct prefix *) &p2_pfx); printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result); assert (exp_result == result); /* * Also check the reverse comparision. */ result = route_table_prefix_iter_cmp ((struct prefix *) &p2_pfx, (struct prefix *) &p1_pfx); if (exp_result) { exp_result = -exp_result; } printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result); assert (result == exp_result); } /* * test_prefix_iter_cmp * * Tests comparision of prefixes according to order of iteration. */ static void test_prefix_iter_cmp () { printf ("\n\nTesting route_table_prefix_iter_cmp()\n"); verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/8", 0); verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/16", -1); verify_prefix_iter_cmp ("1.0.0.0/16", "1.128.0.0/16", -1); } /* * verify_iter_with_pause * * Iterates over a tree using two methods: 'normal' iteration, and an * iterator that pauses at each node. Verifies that the two methods * yield the same results. */ static void verify_iter_with_pause (struct route_table *table) { unsigned long num_nodes; struct route_node *rn, *iter_rn; route_table_iter_t iter_space; route_table_iter_t *iter = &iter_space; route_table_iter_init (iter, table); num_nodes = 0; for (rn = route_top (table); rn; rn = route_next (rn)) { num_nodes++; route_table_iter_pause (iter); assert (iter->current == NULL); if (route_table_iter_started (iter)) { assert (iter->state == RT_ITER_STATE_PAUSED); } else { assert (rn == table->top); assert (iter->state == RT_ITER_STATE_INIT); } iter_rn = route_table_iter_next (iter); /* * Make sure both iterations return the same node. */ assert (rn == iter_rn); } assert (num_nodes == route_table_count (table)); route_table_iter_pause (iter); iter_rn = route_table_iter_next (iter); assert (iter_rn == NULL); assert (iter->state == RT_ITER_STATE_DONE); assert (route_table_iter_next (iter) == NULL); assert (iter->state == RT_ITER_STATE_DONE); route_table_iter_cleanup (iter); print_table (table); printf ("Verified pausing iteration on tree with %lu nodes\n", num_nodes); } /* * test_iter_pause */ static void test_iter_pause (void) { struct route_table *table; int i, num_prefixes; const char *prefixes[] = { "1.0.1.0/24", "1.0.1.0/25", "1.0.1.128/25", "1.0.2.0/24", "2.0.0.0/8" }; num_prefixes = sizeof (prefixes) / sizeof (prefixes[0]); printf ("\n\nTesting that route_table_iter_pause() works as expected\n"); table = route_table_init (); for (i = 0; i < num_prefixes; i++) { add_nodes (table, prefixes[i], NULL); } verify_iter_with_pause (table); clear_table (table); route_table_finish (table); } /* * run_tests */ static void run_tests (void) { test_prefix_iter_cmp (); test_get_next (); test_iter_pause (); } /* * main */ int main (void) { run_tests (); } quagga-1.2.4/tests/test-buffer.c000066400000000000000000000026471325323223500165300ustar00rootroot00000000000000/* * Copyright (C) 2004 Paul Jakma * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 struct thread_master *master; int main(int argc, char **argv) { struct buffer *b1, *b2; int n; char junk[3]; char c = 'a'; memory_init(); if ((argc != 2) || (sscanf(argv[1], "%d%1s", &n, junk) != 1)) { fprintf(stderr, "Usage: %s \n", *argv); return 1; } b1 = buffer_new(0); b2 = buffer_new(1024); while (n-- > 0) { buffer_put(b1, &c, 1); buffer_put(b2, &c, 1); if (c++ == 'z') c = 'a'; buffer_reset(b1); buffer_reset(b2); } buffer_free(b1); buffer_free(b2); return 0; } quagga-1.2.4/tests/test-checksum.c000066400000000000000000000257361325323223500170650ustar00rootroot00000000000000/* * Copyright (C) 2008 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "checksum.h" struct thread_master *master; struct acc_vals { int c0; int c1; }; struct csum_vals { struct acc_vals a; int x; int y; }; static struct csum_vals ospfd_vals, isisd_vals; typedef size_t testsz_t; typedef uint16_t testoff_t; /* Fletcher Checksum -- Refer to RFC1008. */ #define MODX 4102 /* The final reduction phase. * This one should be the original ospfd version */ static u_int16_t reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 x = ((len - off - 1) * c0 - c1) % 255; if (x <= 0) x += 255; y = 510 - c0 - x; if (y > 255) y -= 255; /* take care endian issue. */ return htons ((x << 8) + y); #undef x #undef y #undef c0 #undef c1 } /* slightly different concatenation */ static u_int16_t reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 x = ((len - off - 1) * c0 - c1) % 255; if (x <= 0) x += 255; y = 510 - c0 - x; if (y > 255) y -= 255; /* take care endian issue. */ return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } /* original isisd version */ static u_int16_t reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 u_int32_t mul; mul = (len - off)*(c0); x = mul - c0 - c1; y = c1 - mul - 1; if (y > 0) y++; if (x < 0) x--; x %= 255; y %= 255; if (x == 0) x = 255; if (y == 0) y = 1; return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } /* Is the -1 in y wrong perhaps? */ static u_int16_t reduce_isisd_yfix (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 u_int32_t mul; mul = (len - off)*(c0); x = mul - c0 - c1; y = c1 - mul; if (y > 0) y++; if (x < 0) x--; x %= 255; y %= 255; if (x == 0) x = 255; if (y == 0) y = 1; return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } /* Move the mods yp */ static u_int16_t reduce_isisd_mod (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 u_int32_t mul; mul = (len - off)*(c0); x = mul - c1 - c0; y = c1 - mul - 1; x %= 255; y %= 255; if (y > 0) y++; if (x < 0) x--; if (x == 0) x = 255; if (y == 0) y = 1; return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } /* Move the mods up + fix y */ static u_int16_t reduce_isisd_mody (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 u_int32_t mul; mul = (len - off)*(c0); x = mul - c0 - c1; y = c1 - mul; x %= 255; y %= 255; if (y > 0) y++; if (x < 0) x--; if (x == 0) x = 255; if (y == 0) y = 1; return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } struct reductions_t { const char *name; u_int16_t (*f) (struct csum_vals *, testsz_t, testoff_t); } reducts[] = { { .name = "ospfd", .f = reduce_ospfd }, { .name = "ospfd-1", .f = reduce_ospfd1 }, { .name = "isisd", .f = reduce_isisd }, { .name = "isisd-yfix", .f = reduce_isisd_yfix }, { .name = "isisd-mod", .f = reduce_isisd_mod }, { .name = "isisd-mody", .f = reduce_isisd_mody }, { NULL, NULL }, }; /* The original ospfd checksum */ static u_int16_t ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off) { u_char *sp, *ep, *p, *q; int c0 = 0, c1 = 0; int x, y; u_int16_t checksum, *csum; csum = (u_int16_t *) (buffer + off); *(csum) = 0; sp = buffer; for (ep = sp + len; 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; } ospfd_vals.a.c0 = c0; ospfd_vals.a.c1 = c1; //printf ("%s: len %u, off %u, c0 %d, c1 %d\n", // __func__, len, off, c0, c1); x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255; if (x <= 0) x += 255; y = 510 - c0 - x; if (y > 255) y -= 255; ospfd_vals.x = x; ospfd_vals.y = y; buffer[off] = x; buffer[off + 1] = y; /* take care endian issue. */ checksum = htons ((x << 8) | (y & 0xff)); return (checksum); } /* the original, broken isisd checksum */ static u_int16_t iso_csum_create (u_char * buffer, testsz_t len, testoff_t off) { u_int8_t *p; int x; int y; u_int32_t mul; u_int32_t c0; u_int32_t c1; u_int16_t checksum, *csum; int i, init_len, partial_len; checksum = 0; csum = (u_int16_t *) (buffer + off); *(csum) = checksum; p = buffer; c0 = 0; c1 = 0; init_len = len; while (len != 0) { partial_len = MIN(len, MODX); for (i = 0; i < partial_len; i++) { c0 = c0 + *(p++); c1 += c0; } c0 = c0 % 255; c1 = c1 % 255; len -= partial_len; } isisd_vals.a.c0 = c0; isisd_vals.a.c1 = c1; mul = (init_len - off) * c0; x = mul - c1 - c0; y = c1 - mul - 1; if (y > 0) y++; if (x < 0) x--; x %= 255; y %= 255; if (x == 0) x = 255; if (y == 0) y = 1; isisd_vals.x = x; isisd_vals.y = y; checksum = htons((x << 8) | (y & 0xFF)); *(csum) = checksum; /* return the checksum for user usage */ return checksum; } static int verify (u_char * buffer, testsz_t len) { u_int8_t *p; u_int32_t c0; u_int32_t c1; int i, partial_len; p = buffer; c0 = 0; c1 = 0; while (len) { partial_len = MIN(len, 5803); for (i = 0; i < partial_len; i++) { c0 = c0 + *(p++); c1 += c0; } c0 = c0 % 255; c1 = c1 % 255; len -= partial_len; } if (c0 == 0 && c1 == 0) return 0; return 1; } static int /* return checksum in low-order 16 bits */ in_cksum_optimized(void *parg, int nbytes) { u_short *ptr = parg; register long sum; /* assumes long == 32 bits */ register u_short answer; /* assumes u_short == 16 bits */ register int count; /* * 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; count = nbytes >> 1; /* div by 2 */ for(ptr--; count; --count) sum += *++ptr; if (nbytes & 1) /* Odd */ sum += *(u_char *)(++ptr); /* one byte only */ /* * 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); } static int /* return checksum in low-order 16 bits */ in_cksum_rfc(void *parg, int count) /* from RFC 1071 */ { u_short *addr = parg; /* Compute Internet Checksum for "count" bytes * beginning at location "addr". */ register long sum = 0; while (count > 1) { /* This is the inner loop */ sum += *addr++; count -= 2; } /* Add left-over byte, if any */ if (count > 0) { sum += *(u_char *)addr; } /* Fold 32-bit sum to 16 bits */ while (sum>>16) sum = (sum & 0xffff) + (sum >> 16); return ~sum; } int main(int argc, char **argv) { /* 60017 65629 702179 */ #define MAXDATALEN 60017 #define BUFSIZE MAXDATALEN + sizeof(u_int16_t) u_char buffer[BUFSIZE]; int exercise = 0; #define EXERCISESTEP 257 srandom (time (NULL)); while (1) { u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc; int i,j; exercise += EXERCISESTEP; exercise %= MAXDATALEN; for (i = 0; i < exercise; i += sizeof (long int)) { long int rand = random (); for (j = sizeof (long int); j > 0; j--) buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff; } in_csum = in_cksum(buffer, exercise); in_csum_res = in_cksum_optimized(buffer, exercise); in_csum_rfc = in_cksum_rfc(buffer, exercise); if (in_csum_res != in_csum || in_csum != in_csum_rfc) printf ("verify: in_chksum failed in_csum:%x, in_csum_res:%x," "in_csum_rfc %x, len:%d\n", in_csum, in_csum_res, in_csum_rfc, exercise); ospfd = ospfd_checksum (buffer, exercise + sizeof(u_int16_t), exercise); if (verify (buffer, exercise + sizeof(u_int16_t))) printf ("verify: ospfd failed\n"); isisd = iso_csum_create (buffer, exercise + sizeof(u_int16_t), exercise); if (verify (buffer, exercise + sizeof(u_int16_t))) printf ("verify: isisd failed\n"); lib = fletcher_checksum (buffer, exercise + sizeof(u_int16_t), exercise); if (verify (buffer, exercise + sizeof(u_int16_t))) printf ("verify: lib failed\n"); if (ospfd != lib) { printf ("Mismatch in values at size %u\n" "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n" "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n" "lib: 0x%04x\n", exercise, ospfd, ospfd_vals.a.c0, ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y, isisd, isisd_vals.a.c0, isisd_vals.a.c1, isisd_vals.x, isisd_vals.y, lib ); /* Investigate reduction phase discrepencies */ if (ospfd_vals.a.c0 == isisd_vals.a.c0 && ospfd_vals.a.c1 == isisd_vals.a.c1) { printf ("\n"); for (i = 0; reducts[i].name != NULL; i++) { ospfd = reducts[i].f (&ospfd_vals, exercise + sizeof (u_int16_t), exercise); printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n", reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd); } } printf ("\n u_char testdata [] = {\n "); for (i = 0; i < exercise; i++) { printf ("0x%02x,%s", buffer[i], (i + 1) % 8 ? " " : "\n "); } printf ("\n}\n"); exit (1); } } } quagga-1.2.4/tests/test-cli.c000066400000000000000000000042411325323223500160160ustar00rootroot00000000000000/* * CLI/command dummy handling tester * * Copyright (C) 2015 by David Lamparter, * for Open Source Routing / NetDEF, Inc. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* example usage: * * ./testcli < testcli.in | diff -au testcli.refout - */ #include #include "common-cli.h" DUMMY_DEFUN(cmd0, "arg ipv4 A.B.C.D"); DUMMY_DEFUN(cmd1, "arg ipv4m A.B.C.D/M"); DUMMY_DEFUN(cmd2, "arg ipv6 X:X::X:X"); DUMMY_DEFUN(cmd3, "arg ipv6m X:X::X:X/M"); DUMMY_DEFUN(cmd4, "arg range <5-15>"); DUMMY_DEFUN(cmd5, "pat a ( a|b)"); DUMMY_DEFUN(cmd6, "pat b (a|)"); DUMMY_DEFUN(cmd7, "pat c (a | b|c) A.B.C.D"); DUMMY_DEFUN(cmd8, "pat d { foo A.B.C.D|bar X:X::X:X| baz }"); DUMMY_DEFUN(cmd9, "pat e [ WORD ]"); DUMMY_DEFUN(cmd10, "pat f [key]"); DUMMY_DEFUN(cmd11, "alt a WORD"); DUMMY_DEFUN(cmd12, "alt a A.B.C.D"); DUMMY_DEFUN(cmd13, "alt a X:X::X:X"); void test_init(void) { install_element (ENABLE_NODE, &cmd0_cmd); install_element (ENABLE_NODE, &cmd1_cmd); install_element (ENABLE_NODE, &cmd2_cmd); install_element (ENABLE_NODE, &cmd3_cmd); install_element (ENABLE_NODE, &cmd4_cmd); install_element (ENABLE_NODE, &cmd5_cmd); install_element (ENABLE_NODE, &cmd6_cmd); install_element (ENABLE_NODE, &cmd7_cmd); install_element (ENABLE_NODE, &cmd8_cmd); install_element (ENABLE_NODE, &cmd9_cmd); install_element (ENABLE_NODE, &cmd10_cmd); install_element (ENABLE_NODE, &cmd11_cmd); install_element (ENABLE_NODE, &cmd12_cmd); install_element (ENABLE_NODE, &cmd13_cmd); } quagga-1.2.4/tests/test-commands-defun.c000066400000000000000000044243111325323223500201570ustar00rootroot00000000000000#include #include "command.h" #include "tests.h" DEFSH (0|0|0|0|0, 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 (0, 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 (0, show_bgp_ipv6_safi_neighbor_flap_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system information\n" "BGP information\n" "Address Family Modifier\n" "Address Family Modifier\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 flap statistics of the routes learned from neighbor\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0|0|0|0, 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 (0, ipv6_route_flags_pref_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") DEFSH (0, ipv6_nd_homeagent_lifetime_cmd_vtysh, "ipv6 nd home-agent-lifetime <0-65520>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") DEFSH (0, no_ip_ssmpingd_cmd_vtysh, "no ip ssmpingd [A.B.C.D]", "Negate a command or set its defaults\n" "IP information\n" "Enable ssmpingd operation\n" "Source address\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, 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 (0, ipv6_route_ifname_pref_tag_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, rip_distance_cmd_vtysh, "distance <1-255>", "Administrative distance\n" "Distance value\n") DEFSH (0, 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 (0, no_ipv6_route_flags_pref_tag_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") DEFSH (0, debug_zebra_fpm_cmd_vtysh, "debug zebra fpm", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug zebra FPM events\n") DEFSH (0, show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd_vtysh, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN 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" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, show_ip_bgp_ipv4_lcommunity2_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", "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 large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_neighbor_advertised_route_cmd_vtysh, "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\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 (0, show_bgp_ipv4_safi_rd_prefix_cmd_vtysh, "show bgp ipv4 (encap|vpn) rd ASN:nn_or_IP-address:nn A.B.C.D/M", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, 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 (0, ip_route_mask_flags_tag_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, ipv6_route_ifname_flags_pref_tag_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, show_bgp_view_neighbor_received_routes_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system 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" "Display the received routes from neighbor\n") DEFSH (0, 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 (0, debug_bgp_zebra_cmd_vtysh, "debug bgp zebra", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP Zebra messages\n") DEFSH (0, no_ripng_redistribute_type_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)" " metric <0-16>", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric\n" "Metric value\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, debug_isis_adj_cmd_vtysh, "debug isis adj-packets", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Adjacency related packets\n") DEFSH (0, interface_ip_pim_ssm_cmd_vtysh, "ip pim ssm", "IP information\n" "PIM information\n" "Enable PIM SSM operation\n") DEFSH (0, show_bgp_rsclient_cmd_vtysh, "show bgp rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, ip_route_tag_distance_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, no_ipv6_nd_ra_interval_msec_val_cmd_vtysh, "no ipv6 nd ra-interval msec <1-1800000>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") DEFSH (0, 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 (0, 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 (0, ip_rip_split_horizon_cmd_vtysh, "ip rip split-horizon", "IP information\n" "Routing Information Protocol\n" "Perform split horizon\n") DEFSH (0, show_bgp_view_ipv6_safi_rsclient_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, 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 (0, ipv6_nd_prefix_val_noauto_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration") DEFSH (0, pce_address_cmd_vtysh, "pce address A.B.C.D", "PCE Router Information specific commands\n" "Stable IP address of the PCE\n" "PCE address in IPv4 address format\n") DEFSH (0, clear_ip_bgp_all_encap_soft_in_cmd_vtysh, "clear ip bgp * encap 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 (0, 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 (0, no_isis_hello_multiplier_l2_cmd_vtysh, "no isis hello-multiplier level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-2 IIHs\n") DEFSH (0, 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 (0, no_ip_route_flags_distance2_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, 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 (0, 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 (0, ospf_distance_cmd_vtysh, "distance <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n") DEFSH (0, 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 (0, spf_interval_l2_cmd_vtysh, "spf-interval level-2 <1-120>", "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, 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 (0, no_ip_lcommunity_list_expanded_cmd_vtysh, "no ip large-community-list <100-500> (deny|permit) .LINE", "Negate a command or set its defaults\n" "IP information\n" "Add a large community list entry\n" "Large Community list number (expanded)\n" "Specify large community to reject\n" "Specify large community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, ipv6_route_tag_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>", "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" "Set tag for this route\n" "Tag value\n") DEFSH (0, no_spf_interval_l2_cmd_vtysh, "no spf-interval level-2", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n") DEFSH (0, show_bgp_view_afi_safi_lcommunity4_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, show_bgp_ipv6_safi_rsclient_prefix_cmd_vtysh, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 3ffe::/16\n") DEFSH (0, 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 (0, show_ip_bgp_view_neighbor_advertised_route_cmd_vtysh, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", "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" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, 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 (0, show_ipv6_bgp_lcommunity3_cmd_vtysh, "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, show_ipv6_route_protocol_cmd_vtysh, "show ipv6 route " "(kernel|connected|static|ripng|ospf6|isis|bgp|babel|nhrp)", "Show running system information\n" "IP information\n" "IP routing table\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, vpnv4_network_route_map_cmd_vtysh, "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD route-map 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" "route map\n" "route map name\n") DEFSH (0, 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 (0, show_bgp_view_afi_safi_lcommunity_all_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n") DEFSH (0, rip_passive_interface_cmd_vtysh, "passive-interface (IFNAME|default)", "Suppress routing updates on an interface\n" "Interface name\n" "default for all interfaces\n") DEFSH (0, ipv6_nd_ra_lifetime_cmd_vtysh, "ipv6 nd ra-lifetime <0-9000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" "Router lifetime in seconds (0 stands for a non-default gw)\n") DEFSH (0, no_isis_priority_arg_cmd_vtysh, "no isis priority <0-127>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n") DEFSH (0, 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 (0, no_link_params_admin_grp_cmd_vtysh, "no admin-grp", "Negate a command or set its defaults\n" "Disable Administrative group membership on this interface\n") DEFSH (0, 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 (0, 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 (0, no_lsp_refresh_interval_l1_cmd_vtysh, "no lsp-refresh-interval level-1", "Negate a command or set its defaults\n" "LSP refresh interval for Level 1 only in seconds\n") DEFSH (0, 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 (0, no_ipv6_forwarding_cmd_vtysh, "no ipv6 forwarding", "Negate a command or set its defaults\n" "IPv6 information\n" "Turn off IPv6 forwarding") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, ip_irdp_debug_messages_cmd_vtysh, "ip irdp debug messages", "IP information\n" "ICMP Router discovery debug Averts. and Solicits (short)\n") DEFSH (0, ospf_authentication_key_cmd_vtysh, "ospf authentication-key AUTH_KEY", "OSPF interface commands\n" "Authentication password (key)\n" "The OSPF password (key)") DEFSH (0, show_bgp_ipv6_safi_flap_route_map_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics route-map WORD", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, 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 (0, show_ip_route_prefix_vrf_cmd_vtysh, "show ip route A.B.C.D/M " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, clear_ip_bgp_as_encap_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " encap 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 (0, show_bgp_ipv6_vpn_rd_tags_cmd_vtysh, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn tags", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n") DEFSH (0, show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family modifier\n" "Address Family modifier\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 (0, show_bgp_ipv4_safi_lcommunity_list_cmd_vtysh, "show bgp ipv4 (unicast|multicast) large-community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") DEFSH (0, 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 (0, show_bgp_ipv4_prefix_longer_cmd_vtysh, "show bgp ipv4 A.B.C.D/M longer-prefixes", "Show running system information\n" "BGP information\n" "IP information\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n") DEFSH (0, show_bgp_instance_ipv6_rsclient_summary_cmd_vtysh, "show bgp view WORD ipv6 rsclient summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, 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 (0, 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 (0, no_isis_hello_interval_l1_cmd_vtysh, "no isis hello-interval level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Specify hello-interval for level-1 IIHs\n") DEFSH (0, 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 (0, 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 (0, ospf6_log_adjacency_changes_cmd_vtysh, "log-adjacency-changes", "Log changes in adjacency state\n") DEFSH (0, no_ip_route_mask_flags2_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, 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 (0, 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 (0, 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 (0, ipv6_nd_prefix_noval_rev_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, show_bgp_ipv4_vpn_neighbor_routes_cmd_vtysh, "show bgp ipv4 vpn neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific 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 (0, debug_isis_rtevents_cmd_vtysh, "debug isis route-events", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Route related events\n") DEFSH (0, 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 (0, clear_nhrp_cmd_vtysh, "clear " "(ip|ipv6)" " nhrp (cache|shortcut)", "Reset functions\n" "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Dynamic cache entries\n" "Shortcut entries\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out the existing ORF prefix-list\n") DEFSH (0, no_set_aggregator_as_val_cmd_vtysh, "no set aggregator as " "<1-4294967295>" " 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 (0, clear_ip_bgp_as_vpnv4_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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" "Resend all outbound updates\n") DEFSH (0, 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 (0, ip_ospf_priority_cmd_vtysh, "ip ospf priority <0-255>", "IP Information\n" "OSPF interface commands\n" "Router priority\n" "Priority\n") DEFSH (0, interface_no_ip_pim_ssm_cmd_vtysh, "no ip pim ssm", "Negate a command or set its defaults\n" "IP information\n" "PIM information\n" "Enable PIM SSM operation\n") DEFSH (0, no_ipv6_route_ifname_flags_pref_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") DEFSH (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out the existing ORF prefix-list\n") DEFSH (0, no_terminal_monitor_cmd_vtysh, "no terminal monitor", "Negate a command or set its defaults\n" "Set terminal line parameters\n" "Copy debug output to the current terminal line\n") DEFSH (0, 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 (0, 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 (0, 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 (0, ip_route_mask_flags_distance2_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255> " "vrf <0-65535>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv4_safi_summary_cmd_vtysh, "show bgp ipv4 (unicast|multicast) summary", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, no_ip_route_flags_tag_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n") DEFSH (0, 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 (0, show_ip_bgp_view_rsclient_prefix_cmd_vtysh, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, pce_cap_flag_cmd_vtysh, "pce flag BITPATTERN", "PCE Router Information specific commands\n" "Capabilities of the PCE for path computation\n" "32-bit Hexadecimal value\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv6_safi_community_list_exact_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD) exact-match", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\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 (0, ipv6_nd_prefix_noval_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n") DEFSH (0, ospf_mpls_te_inter_as_cmd_vtysh, "mpls-te inter-as as", "MPLS-TE specific commands\n" "Configure MPLS-TE Inter-AS support\n" "AS native mode self originate INTER_AS LSA with Type 11 (as flooding scope)\n") DEFSH (0, ripng_route_cmd_vtysh, "route IPV6ADDR", "Static route setup\n" "Set static RIPng route announcement\n") DEFSH (0, 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 (0, show_bgp_ipv6_safi_summary_cmd_vtysh, "show bgp ipv6 (unicast|multicast) summary", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, ospf6_stub_router_admin_cmd_vtysh, "stub-router administrative", "Make router a stub router\n" "Advertise inability to be a transit router\n" "Administratively applied, for an indefinite period\n") DEFSH (0, show_bgp_ipv6_safi_prefix_longer_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) X:X::X:X/M longer-prefixes", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\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 (0, ospf_max_metric_router_lsa_admin_cmd_vtysh, "max-metric router-lsa administrative", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") DEFSH (0, ipv6_bgp_network_cmd_vtysh, "network X:X::X:X/M", "Specify a network to announce via BGP\n" "IPv6 prefix /\n") DEFSH (0, 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 (0, 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 (0, 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" "Resend all outbound updates\n") DEFSH (0, 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 (0, no_isis_hello_multiplier_l1_arg_cmd_vtysh, "no isis hello-multiplier <2-100> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") DEFSH (0, rip_redistribute_type_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)" " route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 (0, ip_rip_authentication_mode_authlen_cmd_vtysh, "ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)", "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n" "MD5 authentication data length\n" "RFC compatible\n" "Old ripd compatible\n") DEFSH (0, no_ipv6_route_ifname_flags_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, no_max_lsp_lifetime_l2_arg_cmd_vtysh, "no max-lsp-lifetime level-2 <350-65535>", "Negate a command or set its defaults\n" "Maximum LSP lifetime for Level 2 only\n" "LSP lifetime for Level 2 only in seconds\n") DEFSH (0, no_ipv6_nd_ra_interval_cmd_vtysh, "no ipv6 nd ra-interval", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n") DEFSH (0, 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 (0, no_ospf_timers_min_ls_interval_cmd_vtysh, "no timers throttle lsa all", "Negate a command or set its defaults\n" "Adjust routing timers\n" "Throttling adaptive timer\n" "LSA delay between transmissions\n") DEFSH (0, no_rip_redistribute_type_metric_routemap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)" " metric <0-16> route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, ip_irdp_multicast_cmd_vtysh, "ip irdp multicast", "IP information\n" "ICMP Router discovery on this interface using multicast\n") DEFSH (0, no_debug_bgp_allow_martians_cmd_vtysh, "no debug bgp allow-martians", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP allow martian next hops\n") DEFSH (0, no_ospf6_redistribute_route_map_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|isis|bgp|babel|nhrp)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Route map name\n") DEFSH (0, isis_mpls_te_inter_as_cmd_vtysh, "mpls-te inter-as (level-1|level-1-2|level-2-only)", "MPLS-TE specific commands\n" "Configure MPLS-TE Inter-AS support\n" "AREA native mode self originate INTER-AS LSP with L1 only flooding scope)\n" "AREA native mode self originate INTER-AS LSP with L1 and L2 flooding scope)\n" "AS native mode self originate INTER-AS LSP with L2 only flooding scope\n") DEFSH (0, bgp_redistribute_ipv6_metric_rmap_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 (0, undebug_bgp_normal_cmd_vtysh, "undebug bgp", "Disable debugging functions (see also 'debug')\n" "BGP information\n") DEFSH (0|0|0|0, 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 (0, no_debug_static_cmd_vtysh, "no debug static", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM Static Multicast Route activity\n") DEFSH (0, 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 (0, 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 (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, debug_nhrp_cmd_vtysh, "debug nhrp " "(all|common|event|interface|kernel|route|vici)", "Enable debug messages for specific or all parts.\n" "NHRP information\n" "All messages\n" "Common messages (default)\n" "Event manager messages\n" "Interface messages\n" "Kernel messages\n" "Route messages\n" "VICI messages\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, no_debug_pim_packets_filter_cmd_vtysh, "no debug pim packets (hello|joins)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol packets\n" "PIM Hello protocol packets\n" "PIM Join/Prune protocol packets\n") DEFSH (0, 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 (0, 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 (0, ip_multicast_mode_cmd_vtysh, "ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", "IP information\n" "Multicast options\n" "RPF lookup behavior\n" "Lookup in unicast RIB only\n" "Lookup in multicast RIB only\n" "Try multicast RIB first, fall back to unicast RIB\n" "Lookup both, use entry with lower distance\n" "Lookup both, use entry with longer prefix\n") DEFSH (0, show_bgp_summary_1w_cmd_vtysh, "show bgp (ipv4|ipv6|unicast|multicast|vpn|encap) summary", "Show running system information\n" "BGP information\n" "IP information\n" "IPv6 Information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, show_ipv6_ospf6_database_type_id_router_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, no_debug_ospf_te_cmd_vtysh, "no debug ospf te", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF-TE information\n") DEFSH (0, 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 (0, show_bgp_ipv4_community3_exact_cmd_vtysh, "show bgp ipv4 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" "IP 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 (0, 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 (0, 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 (0, 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 (0, 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 extended community\n") DEFSH (0, vty_no_restricted_mode_cmd_vtysh, "no anonymous restricted", "Negate a command or set its defaults\n" "Enable password checking\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 calculation\n" "Show SPF tree\n") DEFSH (0, ip_irdp_maxadvertinterval_cmd_vtysh, "ip irdp maxadvertinterval <4-1800>", "IP information\n" "ICMP Router discovery on this interface\n" "Set maximum time between advertisement\n" "Maximum advertisement interval in seconds\n") DEFSH (0, show_debugging_ripng_cmd_vtysh, "show debugging ripng", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "RIPng configuration\n") DEFSH (0, clear_bgp_all_out_cmd_vtysh, "clear bgp * out", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Resend all outbound updates\n") DEFSH (0, no_debug_ssmpingd_cmd_vtysh, "no debug ssmpingd", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "ssmpingd activity\n") DEFSH (0, 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 (0, 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 (0, no_ipv6_nd_managed_config_flag_cmd_vtysh, "no ipv6 nd managed-config-flag", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Managed address configuration flag\n") DEFSH (0, 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 (0, show_bgp_view_afi_safi_lcommunity3_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, 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 (0, no_link_params_enable_cmd_vtysh, "no enable", "Negate a command or set its defaults\n" "Disable link parameters on this interface\n") DEFSH (0, show_bgp_ipv6_safi_damp_flap_prefix_list_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics prefix-list WORD", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, no_debug_isis_packet_dump_cmd_vtysh, "no debug isis packet-dump", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS packet dump\n") DEFSH (0, 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 (0, show_bgp_view_ipv6_safi_rsclient_prefix_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 3ffe::/16\n") DEFSH (0, show_bgp_instance_ipv6_safi_summary_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) summary", "Show running system 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 (0, 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 (0, ospf6_distance_cmd_vtysh, "distance <1-255>", "Negate a command or set its defaults\n" "Define an administrative distance\n" "OSPF6 Administrative distance\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, ospf_passive_interface_default_cmd_vtysh, "passive-interface default", "Suppress routing updates on an interface\n" "Suppress routing updates on interfaces by default\n") DEFSH (0, 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 (0, show_bgp_ipv6_safi_rd_route_cmd_vtysh, "show bgp ipv6 (encap|vpn) rd ASN:nn_or_IP-address:nn X:X::X:X", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 (0, show_bgp_ipv6_safi_damp_flap_filter_list_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics filter-list WORD", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, 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 (0, no_ospf6_distance_cmd_vtysh, "no distance <1-255>", "Negate a command or set its defaults\n" "Define an administrative distance\n" "OSPF6 Administrative distance\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv6_safi_damp_flap_regexp_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics regexp .LINE", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\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 (0, undebug_bgp_all_cmd_vtysh, "undebug all bgp", "Disable debugging functions (see also 'debug')\n" "Enable all debugging\n" "BGP information\n") DEFSH (0, clear_ip_bgp_all_rsclient_cmd_vtysh, "clear ip bgp * rsclient", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, 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 (0, no_psnp_interval_cmd_vtysh, "no isis psnp-interval", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n") DEFSH (0, 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 (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, ip_route_mask_flags_tag_distance2_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_ip_route_mask_flags_tag_distance_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, 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 (0, 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 (0, no_pce_domain_cmd_vtysh, "no pce domain as <0-65535>", "Negate a command or set its defaults\n" "PCE Router Information specific commands\n" "Disable PCE domain AS number\n" "AS number where the PCE as visibilities for path computation\n" "AS number in decimal <0-65535>\n") DEFSH (0, interface_ip_igmp_query_max_response_time_dsec_cmd_vtysh, "ip igmp query-max-response-time-dsec" " <10-250>", "IP information\n" "Enable IGMP operation\n" "IGMP max query response value (deciseconds)\n" "Query response value in deciseconds\n") DEFSH (0, ip_ospf_mtu_ignore_cmd_vtysh, "ip ospf mtu-ignore", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") DEFSH (0, no_ip_ospf_area_cmd_vtysh, "no ip ospf area [A.B.C.D]", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Disable OSPF on this interface\n" "Address of interface\n") DEFSH (0, ipv6_nd_prefix_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n" "Set Router Address flag\n") DEFSH (0, debug_zebra_nht_cmd_vtysh, "debug zebra nht", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra next hop tracking\n") DEFSH (0, no_dynamic_hostname_cmd_vtysh, "no hostname dynamic", "Negate a command or set its defaults\n" "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") DEFSH (0, show_bgp_instance_ipv6_summary_cmd_vtysh, "show bgp view WORD ipv6 summary", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family modifier\n" "Address Family modifier\n" "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") DEFSH (0, clear_bgp_ipv6_as_out_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Resend all outbound updates\n") DEFSH (0|0|0|0, 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 (0, show_ip_bgp_lcommunity2_cmd_vtysh, "show ip bgp large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, no_ipv6_route_ifname_flags_tag_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, debug_ospf_zebra_cmd_vtysh, "debug ospf zebra", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Zebra information\n") DEFSH (0, show_ip_route_tag_vrf_cmd_vtysh, "show ip route tag <1-4294967295>" "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "Show only routes with tag\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, ip_rip_split_horizon_poisoned_reverse_cmd_vtysh, "ip rip split-horizon poisoned-reverse", "IP information\n" "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFSH (0, ospf_area_nssa_no_summary_cmd_vtysh, "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") DEFSH (0, lsp_refresh_interval_l2_cmd_vtysh, "lsp-refresh-interval level-2 <1-65235>", "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") DEFSH (0, show_bgp_lcommunity4_cmd_vtysh, "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, no_debug_zebra_fpm_cmd_vtysh, "no debug zebra fpm", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug zebra FPM events\n") DEFSH (0, show_ipv6_ospf6_database_adv_router_linkstate_id_cmd_vtysh, "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, ipv6_nd_homeagent_preference_cmd_vtysh, "ipv6 nd home-agent-preference <0-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" "preference value (default is 0, least preferred)\n") DEFSH (0, show_bgp_neighbor_flap_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", "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 flap statistics of the routes learned from neighbor\n") DEFSH (0, 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 extended community\n" "VPN extended community\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, lsp_refresh_interval_cmd_vtysh, "lsp-refresh-interval <1-65235>", "LSP refresh interval\n" "LSP refresh interval in seconds\n") DEFSH (0, ipv6_route_flags_pref_tag_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0|0|0|0, 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 (0, 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 (0, 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 detailed information\n") DEFSH (0, 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 information\n" ) DEFSH (0, show_bgp_ipv6_safi_prefix_pathtype_cmd_vtysh, "show bgp ipv6 (unicast|multicast) X:X::X:X/M (bestpath|multipath)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Display only the bestpath\n" "Display only multipaths\n") DEFSH (0, 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 (0, clear_ip_bgp_all_encap_out_cmd_vtysh, "clear ip bgp * encap 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 (0, undebug_pim_packets_cmd_vtysh, "undebug pim packets", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM protocol packets\n") DEFSH (0, ospf_area_nssa_translate_cmd_vtysh, "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") DEFSH (0, ip_route_flags_distance_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, 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 (0, 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 (0, show_ipv6_route_prefix_vrf_all_cmd_vtysh, "show ipv6 route X:X::X:X/M " "vrf all", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "IPv6 prefix\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, debug_ospf6_lsa_hex_detail_cmd_vtysh, "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)", "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 (0, show_bgp_ipv6_safi_community3_exact_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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 (0, 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 (0, 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 (0, show_bgp_ipv4_safi_cmd_vtysh, "show bgp ipv4 (unicast|multicast)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n") DEFSH (0, show_ip_pim_dr_cmd_vtysh, "show ip pim designated-router", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface designated router\n") DEFSH (0, 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 (0, no_ip_route_mask_flags_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, no_ospf_timers_throttle_spf_cmd_vtysh, "no timers throttle spf", "Negate a command or set its defaults\n" "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF SPF timers\n") DEFSH (0, ipv6_nd_reachable_time_cmd_vtysh, "ipv6 nd reachable-time <1-3600000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") DEFSH (0, 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 (0, no_ospf_cost_cmd_vtysh, "no ospf cost", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interface cost\n") DEFSH (0, no_ipv6_nd_reachable_time_cmd_vtysh, "no ipv6 nd reachable-time", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n") DEFSH (0, show_bgp_ipv4_community2_exact_cmd_vtysh, "show bgp ipv4 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" "IP 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 (0, show_ipv6_mroute_vrf_cmd_vtysh, "show ipv6 mroute " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IPv6 Multicast routing table\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_bgp_ipv4_vpn_rd_cmd_vtysh, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n") DEFSH (0, if_nhrp_reg_flags_cmd_vtysh, "(ip|ipv6)" " nhrp registration (no-unique)", "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Registration configuration\n" "Don't set unique flag\n") DEFSH (0, 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 (0, no_nhrp_nflog_group_cmd_vtysh, "no nhrp nflog-group [<1-65535>]", "Negate a command or set its defaults\n" "Next Hop Resolution Protocol functions\n" "Specify NFLOG group number\n" "NFLOG group number\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, 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 (0, show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd_vtysh, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\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 (0, isis_passwd_cmd_vtysh, "isis password (md5|clear) WORD", "IS-IS commands\n" "Configure the authentication password for a circuit\n" "HMAC-MD5 authentication\n" "Cleartext password\n" "Circuit password\n") DEFSH (0, no_synchronization_cmd_vtysh, "no synchronization", "Negate a command or set its defaults\n" "Perform IGP synchronization\n") DEFSH (0, show_ipv6_ospf6_route_longer_cmd_vtysh, "show ipv6 ospf6 route X:X::X:X/M longer", "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 longer than the specified route\n" ) DEFSH (0, show_bgp_ipv6_vpn_rd_cmd_vtysh, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n") DEFSH (0, show_ipv6_bgp_summary_cmd_vtysh, "show ipv6 bgp summary", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Summary of BGP neighbor status\n") DEFSH (0, show_bgp_instance_neighbors_peer_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X)", "Show running system 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 (0, 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 (0|0|0|0|0|0, rmap_continue_index_cmd_vtysh, "continue <1-65536>", "Exit policy on matches\n" "Goto Clause number\n") DEFSH (0, 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 (0, 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 (0|0|0|0, 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 (0, show_isis_mpls_te_interface_cmd_vtysh, "show isis mpls-te interface [INTERFACE]", "Show running system information\n" "IS-IS information\n" "MPLS-TE specific commands\n" "Interface information\n" "Interface name\n") DEFSH (0, exec_timeout_min_cmd_vtysh, "exec-timeout <0-35791>", "Set timeout value\n" "Timeout value in minutes\n") DEFSH (0, no_isis_priority_cmd_vtysh, "no isis priority", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n") DEFSH (0, show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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 (0|0|0|0, 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 (0, no_ip_ospf_cost_inet4_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 (0, no_ospf_cost_inet4_cmd_vtysh, "no ospf cost A.B.C.D", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interface cost\n" "Address of interface") DEFSH (0, ospf_mpls_te_router_addr_cmd_vtysh, "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") DEFSH (0, 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 (0, no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" " metric <0-4294967295> route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 (0|0|0|0, clear_ip_prefix_list_cmd_vtysh, "clear ip prefix-list", "Reset functions\n" "IP information\n" "Build a prefix list\n") DEFSH (0, show_bgp_ipv4_safi_damp_flap_regexp_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics regexp .LINE", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\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 (0, ospf_distance_ospf_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 (0, no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" " route-map WORD metric <0-4294967295>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, show_bgp_view_ipv4_safi_rsclient_route_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, no_lsp_gen_interval_cmd_vtysh, "no lsp-gen-interval", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv4_lcommunity3_cmd_vtysh, "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, undebug_bgp_keepalive_cmd_vtysh, "undebug bgp keepalives", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP keepalives\n") DEFSH (0, no_ipv6_nd_homeagent_lifetime_cmd_vtysh, "no ipv6 nd home-agent-lifetime", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n") DEFSH (0, link_params_res_bw_cmd_vtysh, "res-bw BANDWIDTH", "Unidirectional Residual Bandwidth\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, 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 (0, 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 (0, show_ip_ospf_mpls_te_router_cmd_vtysh, "show ip ospf mpls-te router", "Show running system information\n" "IP information\n" "OSPF information\n" "MPLS-TE information\n" "MPLS-TE Router parameters\n") DEFSH (0, debug_pim_trace_cmd_vtysh, "debug pim trace", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM internal daemon activity\n") DEFSH (0, no_debug_bgp_as4_segment_cmd_vtysh, "no debug bgp as4 segment", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") DEFSH (0, 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 (0, show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd_vtysh, "show bgp ipv6 vpn neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\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 (0, clear_bgp_instance_peer_rsclient_cmd_vtysh, "clear bgp view WORD (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "BGP information\n" "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, show_bgp_view_route_cmd_vtysh, "show bgp view WORD X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 (0|0|0|0, 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 (0, if_no_nhrp_reg_flags_cmd_vtysh, "no " "(ip|ipv6)" " nhrp registration (no-unique)", "Negate a command or set its defaults\n" "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Registration configuration\n" "Don't set unique flag\n") DEFSH (0, no_isis_priority_l2_arg_cmd_vtysh, "no isis priority <0-127> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-2 routing\n") DEFSH (0, show_ipv6_route_summary_cmd_vtysh, "show ipv6 route summary", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Summary of all IPv6 routes\n") DEFSH (0, no_ospf_timers_min_ls_arrival_cmd_vtysh, "no timers lsa arrival", "Negate a command or set its defaults\n" "Adjust routing timers\n" "Throttling link state advertisement delays\n" "OSPF minimum arrival interval delay\n") DEFSH (0, clear_bgp_all_in_prefix_filter_cmd_vtysh, "clear bgp * in prefix-filter", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_shutdown_if_cmd_vtysh, "no shutdown", "Negate a command or set its defaults\n" "Shutdown the selected interface\n") DEFSH (0, 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 (0, show_interface_cmd_vtysh, "show interface", "Show running system information\n" "Interface status and configuration\n") DEFSH (0, no_ip_route_flags_tag_distance_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, 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 (0, debug_pim_packetdump_send_cmd_vtysh, "debug pim packet-dump send", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump sent packets\n") DEFSH (0, no_debug_pim_trace_cmd_vtysh, "no debug pim trace", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM internal daemon activity\n") DEFSH (0, show_ip_bgp_ipv4_rsclient_summary_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) rsclient summary", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, undebug_bgp_update_cmd_vtysh, "undebug bgp updates", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP updates\n") DEFSH (0, clear_bgp_ipv6_as_soft_out_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " soft out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, no_ip_route_mask_tag_distance_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <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" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, ospf_default_metric_cmd_vtysh, "default-metric <0-16777214>", "Set metric of redistributed routes\n" "Default metric\n") DEFSH (0, 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 (0, 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 (0, clear_ip_bgp_all_encap_in_cmd_vtysh, "clear ip bgp * encap 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 (0, no_ipv6_route_flags_pref_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") DEFSH (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, 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 (0, ospf_cost_u32_cmd_vtysh, "ospf cost <1-65535>", "OSPF interface commands\n" "Interface cost\n" "Cost") DEFSH (0, no_bgp_maxpaths_arg_cmd_vtysh, "no maximum-paths " "<" "1" "-" "1" ">", "Negate a command or set its defaults\n" "Forward packets over multiple paths\n" "Number of paths\n") DEFSH (0, 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 (0, 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 (0, no_net_cmd_vtysh, "no net WORD", "Negate a command or set its defaults\n" "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") DEFSH (0, 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 (0, clear_bgp_as_in_prefix_filter_cmd_vtysh, "clear bgp " "<1-4294967295>" " in prefix-filter", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, debug_ssmpingd_cmd_vtysh, "debug ssmpingd", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "ssmpingd activity\n") DEFSH (0, interface_no_ip_igmp_query_max_response_time_cmd_vtysh, "no" " " "ip igmp query-max-response-time", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n" "IGMP max query response value (seconds)\n") DEFSH (0|0|0|0, 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 (0|0|0|0, 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 (0, undebug_pim_cmd_vtysh, "undebug pim", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n") DEFSH (0, show_ipv6_ospf6_database_type_linkstate_id_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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 (0, link_params_delay_cmd_vtysh, "delay <0-16777215>", "Unidirectional Average Link Delay\n" "Average delay in micro-second as decimal (0...16777215)\n") DEFSH (0, if_no_nhrp_holdtime_cmd_vtysh, "no " "(ip|ipv6)" " nhrp holdtime [1-65000]", "Negate a command or set its defaults\n" "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Specify NBMA address validity time\n" "Time in seconds that NBMA addresses are advertised valid\n") DEFSH (0, 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 (0, show_bgp_view_afi_safi_route_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) A.B.C.D", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address Family\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 (0, show_bgp_ipv6_encap_route_cmd_vtysh, "show bgp ipv6 encap X:X::X:X", "Show running system information\n" "BGP information\n" "IPv6 Information\n" "Display ENCAP NLRI specific information\n" "Network in the BGP routing table to display\n") DEFSH (0, no_router_isis_cmd_vtysh, "no router isis WORD", "no\n" "Enable a routing process\n" "ISO IS-IS\n" "ISO Routing area tag") DEFSH (0, no_capability_opaque_cmd_vtysh, "no capability opaque", "Negate a command or set its defaults\n" "Enable specific OSPF feature\n" "Opaque LSA\n") DEFSH (0, clear_bgp_all_soft_cmd_vtysh, "clear bgp * soft", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig inbound and outbound updates\n") DEFSH (0, 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 (0, if_no_nhrp_network_id_cmd_vtysh, "no " "(ip|ipv6)" " nhrp network-id [<1-4294967295>]", "Negate a command or set its defaults\n" "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Enable NHRP and specify network-id\n" "System local ID to specify interface group\n") DEFSH (0, lsp_gen_interval_l1_cmd_vtysh, "lsp-gen-interval level-1 <1-120>", "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n" "Minimum interval in seconds\n") DEFSH (0, show_bgp_ipv6_encap_summary_cmd_vtysh, "show bgp ipv6 encap summary", "Show running system information\n" "BGP information\n" "IPv6\n" "Display ENCAP NLRI specific information\n" "Summary of BGP neighbor status\n") DEFSH (0, no_ipv6_route_flags_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, 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 (0, no_ipv6_bgp_distance_source_cmd_vtysh, "no distance <1-255> X:X::X:X/M", "Negate a command or set its defaults\n" "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n") DEFSH (0, no_bgp_timers_cmd_vtysh, "no timers bgp", "Negate a command or set its defaults\n" "Adjust routing timers\n" "BGP timers\n") DEFSH (0, lsp_refresh_interval_l1_cmd_vtysh, "lsp-refresh-interval level-1 <1-65235>", "LSP refresh interval for Level 1 only\n" "LSP refresh interval for Level 1 only in seconds\n") DEFSH (0, no_set_src_cmd_vtysh, "no set src", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Source address for route\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_flap_prefix_list_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics prefix-list WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, ipv6_nd_prefix_val_nortaddr_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n") DEFSH (0, 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 (0, 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 (0, rip_default_metric_cmd_vtysh, "default-metric <1-16>", "Set a metric of redistribute routes\n" "Default metric\n") DEFSH (0, ipv6_route_ifname_pref_tag_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") DEFSH (0|0|0|0|0|0, rmap_call_cmd_vtysh, "call WORD", "Jump to another Route-Map after match+set\n" "Target route-map name\n") DEFSH (0, 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 (0, 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 (0, undebug_igmp_cmd_vtysh, "undebug igmp", "Disable debugging functions (see also 'debug')\n" "IGMP protocol activity\n") DEFSH (0, router_info_area_cmd_vtysh, "router-info area A.B.C.D", "OSPF Router Information specific commands\n" "Enable the Router Information functionality with Area flooding scope\n" "OSPF area ID in IP format") DEFSH (0, show_ip_mroute_count_cmd_vtysh, "show ip mroute count", "Show running system information\n" "IP information\n" "IP multicast routing table\n" "Route and packet count data\n") DEFSH (0, debug_bgp_keepalive_cmd_vtysh, "debug bgp keepalives", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP keepalives\n") DEFSH (0, no_ip_lcommunity_list_standard_cmd_vtysh, "no ip large-community-list <1-99> (deny|permit) .AA:.AA:NN", "Negate a command or set its defaults\n" "IP information\n" "Add a large community list entry\n" "Large Community list number (standard)\n" "Specify large community to reject\n" "Specify large community to accept\n" "large community in 'aa:bb:cc' format\n") DEFSH (0, ospf_rfc1583_flag_cmd_vtysh, "ospf rfc1583compatibility", "OSPF specific commands\n" "Enable the RFC1583Compatibility flag\n") DEFSH (0, interface_no_ip_mroute_cmd_vtysh, "no ip mroute INTERFACE A.B.C.D", "Negate a command or set its defaults\n" "IP information\n" "Add multicast route\n" "Outgoing interface name\n" "Group Address\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, show_ipv6_mbgp_summary_cmd_vtysh, "show ipv6 mbgp summary", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Summary of BGP neighbor status\n") DEFSH (0, ip_route_mask_flags_tag_distance2_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, area_passwd_clear_cmd_vtysh, "(area-password|domain-password) clear WORD", "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n" "Authentication type\n" "Area password\n") DEFSH (0, 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 (0, show_ipv6_route_protocol_vrf_all_cmd_vtysh, "show ipv6 route " "(kernel|connected|static|ripng|ospf6|isis|bgp|babel|nhrp)" " " "vrf all", "Show running system information\n" "IP information\n" "IP routing table\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, no_vty_login_cmd_vtysh, "no login", "Negate a command or set its defaults\n" "Enable password checking\n") DEFSH (0, ripng_redistribute_type_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)" " route-map WORD", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_bgp_ipv4_safi_community_list_cmd_vtysh, "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", "Show running system 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 (0, 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 (0, no_isis_circuit_type_cmd_vtysh, "no isis circuit-type (level-1|level-1-2|level-2-only)", "Negate a command or set its defaults\n" "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") DEFSH (0, 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 (0, no_ipv6_route_ifname_tag_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>", "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" "Set tag for this route\n" "Tag value\n") DEFSH (0, show_ip_igmp_sources_cmd_vtysh, "show ip igmp sources", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP sources information\n") DEFSH (0, no_ip_route_tag_distance_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <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" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, 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 (0|0|0|0, 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 (0, show_ip_ospf_database_type_self_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") (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" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Self-originated link states\n") DEFSH (0, 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 (0, 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 (0, show_ipv6_ripng_status_cmd_vtysh, "show ipv6 ripng status", "Show running system information\n" "IPv6 information\n" "Show RIPng routes\n" "IPv6 routing protocol process parameters and statistics\n") DEFSH (0|0|0|0, 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 (0, no_ip_multicast_mode_cmd_vtysh, "no ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", "Negate a command or set its defaults\n" "IP information\n" "Multicast options\n" "RPF lookup behavior\n" "Lookup in unicast RIB only\n" "Lookup in multicast RIB only\n" "Try multicast RIB first, fall back to unicast RIB\n" "Lookup both, use entry with lower distance\n" "Lookup both, use entry with longer prefix\n") DEFSH (0, 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 (0, show_ip_ospf_cmd_vtysh, "show ip ospf", "Show running system information\n" "IP information\n" "OSPF information\n") DEFSH (0, show_bgp_ipv4_route_map_cmd_vtysh, "show bgp ipv4 route-map WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, show_ipv6_ospf6_database_type_adv_router_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0|0|0|0, 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 (0, show_bgp_ipv4_safi_damp_dampened_paths_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening dampened-paths", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") DEFSH (0, show_bgp_lcommunity_cmd_vtysh, "show bgp large-community (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, ip_mroute_dist_vrf_cmd_vtysh, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255> " "vrf <0-65535>", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_ip_bgp_ipv4_lcommunity3_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "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 large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, 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 (0, show_ip_bgp_prefix_pathtype_cmd_vtysh, "show ip bgp A.B.C.D/M (bestpath|multipath)", "Show running system information\n" "IP information\n" "BGP information\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display only the bestpath\n" "Display only multipaths\n") DEFSH (0, clear_bgp_ipv6_safi_prefix_cmd_vtysh, "clear bgp ipv6 (unicast|multicast) prefix X:X::X:X/M", "Reset functions\n" "BGP information\n" "Address family\n" "Address Family Modifier\n" "Clear bestpath and re-advertise\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, show_bgp_views_cmd_vtysh, "show bgp views", "Show running system information\n" "BGP information\n" "Show the defined BGP views\n") DEFSH (0|0|0|0|0, 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 (0|0|0, 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 (0, interface_ip_pim_hello_cmd_vtysh, "ip pim hello <1-180>", "IP information\n" "PIM information\n" "Hello Interval\n" "Time in seconds for Hello Interval\n") DEFSH (0, interface_no_ip_igmp_cmd_vtysh, "no ip igmp", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n") DEFSH (0, 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 (0, show_bgp_ipv6_safi_lcommunity_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community AA:BB:CC", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, show_bgp_ipv4_safi_rd_route_cmd_vtysh, "show bgp ipv4 (encap|vpn) rd ASN:nn_or_IP-address:nn A.B.C.D", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 (0, 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 (0, no_ip_route_tag_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", "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" "Tag of this route\n" "Tag value\n") DEFSH (0, rip_default_information_originate_cmd_vtysh, "default-information originate", "Control distribution of default route\n" "Distribute a default route\n") DEFSH (0, 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 (0, 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 (0, debug_ospf6_lsa_hex_cmd_vtysh, "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", "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 (0, no_set_overload_bit_cmd_vtysh, "no set-overload-bit", "Reset overload bit to accept transit traffic\n" "Reset overload bit\n") DEFSH (0, no_area_export_list_cmd_vtysh, "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") DEFSH (0, no_debug_pim_packets_cmd_vtysh, "no debug pim packets", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol packets\n" "PIM Hello protocol packets\n" "PIM Join/Prune protocol packets\n") DEFSH (0, show_bgp_ipv4_safi_community2_exact_cmd_vtysh, "show 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" "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 (0, test_pim_receive_assert_cmd_vtysh, "test pim receive assert INTERFACE A.B.C.D A.B.C.D A.B.C.D <0-65535> <0-65535> <0-1>", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test reception of PIM assert\n" "Interface\n" "Neighbor address\n" "Assert multicast group address\n" "Assert unicast source address\n" "Assert metric preference\n" "Assert route metric\n" "Assert RPT bit flag\n") DEFSH (0, 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 (0, show_ip_bgp_ipv4_dampening_dampd_paths_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) dampening dampened-paths", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") DEFSH (0, test_pim_receive_join_cmd_vtysh, "test pim receive join INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM join reception from neighbor\n" "Interface\n" "Neighbor holdtime\n" "Upstream neighbor unicast destination address\n" "Downstream neighbor unicast source address\n" "Multicast group address\n" "Unicast source address\n") DEFSH (0, 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 (0, show_bgp_ipv6_safi_prefix_cmd_vtysh, "show bgp ipv6 (unicast|multicast) X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0|0|0|0, 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 (0, 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 (0, ip_route_flags_distance2_vrf_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole) <1-255> " "vrf <0-65535>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, aggregate_address_cmd_vtysh, "aggregate-address A.B.C.D/M", "Configure BGP aggregate entries\n" "Aggregate prefix\n") DEFSH (0, show_ip_bgp_damp_flap_address_cmd_vtysh, "show ip bgp dampening flap-statistics A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") DEFSH (0, ip_protocol_cmd_vtysh, "ip protocol PROTO route-map ROUTE-MAP", "Negate a command or set its defaults\n" "Apply route map to PROTO\n" "Protocol name\n" "Route map name\n") DEFSH (0, show_bgp_ipv4_safi_dampened_paths_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampened-paths", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display paths suppressed due to dampening\n") DEFSH (0, no_set_aspath_exclude_cmd_vtysh, "no set as-path exclude", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Exclude from the as-path\n") DEFSH (0, no_ospf_default_metric_cmd_vtysh, "no default-metric", "Negate a command or set its defaults\n" "Set metric of redistributed routes\n") DEFSH (0, set_aspath_prepend_cmd_vtysh, "set as-path prepend ." "<1-4294967295>", "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") DEFSH (0, 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 (0, no_ip_route_flags_distance2_vrf_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_isis_default_originate_cmd_vtysh, "no default-information originate (ipv4|ipv6) (level-1|level-2)", "Negate a command or set its defaults\n" "Control distribution of default information\n" "Distribute a default route\n" "Distribute default route for IPv4\n" "Distribute default route for IPv6\n" "Distribute default route into level-1\n" "Distribute default route into level-2\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv6_safi_flap_filter_list_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics filter-list WORD", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, no_bandwidth_if_cmd_vtysh, "no bandwidth", "Negate a command or set its defaults\n" "Set bandwidth informational parameter\n") DEFSH (0, show_bgp_ipv4_safi_damp_flap_address_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 (0, 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 (0, 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 (0, ospf_timers_min_ls_interval_cmd_vtysh, "timers throttle lsa all <0-5000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "LSA delay between transmissions\n" "Negate a command or set its defaults\n" "Delay (msec) between sending LSAs\n") DEFSH (0, clear_bgp_external_out_cmd_vtysh, "clear bgp external out", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Resend all outbound updates\n") DEFSH (0, 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 (0|0|0|0|0, 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 (0, 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 (0, 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 (0, no_set_lcommunity_cmd_vtysh, "no set large-community", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP large community attribute\n" "Large community\n") DEFSH (0, interface_no_ip_igmp_join_cmd_vtysh, "no ip igmp join A.B.C.D A.B.C.D", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n" "IGMP join multicast group\n" "Multicast group address\n" "Source address\n") DEFSH (0, show_bgp_ipv4_safi_neighbor_damp_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system information\n" "BGP information\n" "Address Family Modifier\n" "Address Family Modifier\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 dampened routes received from neighbor\n") DEFSH (0, show_bgp_ipv6_safi_neighbor_routes_cmd_vtysh, "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes", "Show running system 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 address\nIPv6 address\n" "Neighbor address\nIPv6 address\n" "Display routes learned from neighbor\n") DEFSH (0, ip_route_flags_tag_distance_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, no_match_peer_cmd_vtysh, "no match peer", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match peer address\n") DEFSH (0, no_area_import_list_cmd_vtysh, "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") DEFSH (0, 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 (0, ip_route_mask_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_ipv6_nd_suppress_ra_cmd_vtysh, "no ipv6 nd suppress-ra", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Suppress Router Advertisement\n") DEFSH (0, neighbor_local_as_no_prepend_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>" " 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 (0, bgp_rr_allow_outbound_policy_cmd_vtysh, "bgp route-reflector allow-outbound-policy", "BGP specific commands\n" "Allow modifications made by out route-map\n" "on ibgp neighbors\n") DEFSH (0, 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 (0, show_bgp_view_neighbor_routes_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) routes", "Show running system 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" "Display routes learned from neighbor\n") DEFSH (0, show_bgp_view_afi_safi_prefix_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) A.B.C.D/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address Family\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, 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 (0, no_router_ospf6_cmd_vtysh, "no router ospf6", "Negate a command or set its defaults\n" "Enable a routing process\n") DEFSH (0, no_service_advanced_vty_cmd_vtysh, "no service advanced-vty", "Negate a command or set its defaults\n" "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") DEFSH (0, no_ospf6_stub_router_admin_cmd_vtysh, "no stub-router administrative", "Negate a command or set its defaults\n" "Make router a stub router\n" "Advertise ability to be a transit router\n" "Administratively applied, for an indefinite period\n") DEFSH (0, 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 (0, 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 (0, match_peer_local_cmd_vtysh, "match peer local", "Match values from routing table\n" "Match peer address\n" "Static or Redistributed routes\n") DEFSH (0, show_ip_bgp_damp_dampened_paths_cmd_vtysh, "show ip bgp dampening dampened-paths", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") DEFSH (0, 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 (0, clear_bgp_all_soft_out_cmd_vtysh, "clear bgp * soft out", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, show_hostname_cmd_vtysh, "show isis hostname", "Show running system information\n" "IS-IS information\n" "IS-IS Dynamic hostname mapping\n") DEFSH (0, 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 information\n" "Interface name(e.g. ep0)\n" ) DEFSH (0, no_ip_ospf_cost_u32_inet4_cmd_vtysh, "no ip ospf cost <1-65535> A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFSH (0, show_bgp_ipv4_community3_cmd_vtysh, "show bgp ipv4 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" "IP 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 (0, 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 (0, 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 (0, 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 (0, interface_ip_pim_hello_hold_cmd_vtysh, "ip pim hello <1-180> <1-180>", "IP information\n" "PIM information\n" "Hello Interval\n" "Time in seconds for Hello Interval\n" "Time in seconds for Hold Interval\n") DEFSH (0, 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 (0, 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 (0, if_ipv6_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 (0, 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 (0, no_ospf6_log_adjacency_changes_detail_cmd_vtysh, "no log-adjacency-changes detail", "Negate a command or set its defaults\n" "Log changes in adjacency state\n" "Log all state changes\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_flap_statistics_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n") DEFSH (0, no_redistribute_ospf6_cmd_vtysh, "no redistribute ospf6", "Negate a command or set its defaults\n" "Redistribute control\n" "OSPF6 route\n") DEFSH (0, ipv6_nd_router_preference_cmd_vtysh, "ipv6 nd router-preference (high|medium|low)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n" "High default router preference\n" "Low default router preference\n" "Medium default router preference (default)\n") DEFSH (0, no_ip_multicast_mode_noarg_cmd_vtysh, "no ip multicast rpf-lookup-mode", "Negate a command or set its defaults\n" "IP information\n" "Multicast options\n" "RPF lookup behavior\n") DEFSH (0, no_match_pathlimit_as_val_cmd_vtysh, "no match pathlimit as <1-65535>", "Negate a command or set its defaults\n" "Match values from routing table\n" "BGP AS-Pathlimit attribute\n" "Match Pathlimit ASN\n") DEFSH (0, max_lsp_lifetime_cmd_vtysh, "max-lsp-lifetime <350-65535>", "Maximum LSP lifetime\n" "LSP lifetime in seconds\n") DEFSH (0, rip_redistribute_type_metric_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)" " metric <0-16> route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv6_lcommunity3_cmd_vtysh, "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, show_debugging_rip_cmd_vtysh, "show debugging rip", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "RIP information\n") DEFSH (0, show_debugging_bgp_cmd_vtysh, "show debugging bgp", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "BGP information\n") DEFSH (0, 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 (0, router_id_cmd_vtysh, "router-id A.B.C.D", "Manually set the router-id\n" "IP address to use for router-id\n") DEFSH (0, debug_ospf_te_cmd_vtysh, "debug ospf te", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF-TE information\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n") DEFSH (0, show_bgp_ipv6_safi_community2_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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 (0, no_ospf6_distance_ospf6_cmd_vtysh, "no distance ospf6", "Negate a command or set its defaults\n" "Define an administrative distance\n" "OSPF6 Administrative distance\n" "OSPF6 Distance\n") DEFSH (0, no_ospf_refresh_timer_cmd_vtysh, "no refresh timer", "Adjust refresh parameters\n" "Unset refresh timer\n") DEFSH (0, no_rip_distance_cmd_vtysh, "no distance <1-255>", "Negate a command or set its defaults\n" "Administrative distance\n" "Distance value\n") DEFSH (0, 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 (0, ripng_network_cmd_vtysh, "network IF_OR_ADDR", "RIPng enable on specified interface or network.\n" "Interface or address") DEFSH (0, show_debugging_zebra_cmd_vtysh, "show debugging zebra", "Show running system information\n" "Debugging information\n" "Zebra configuration\n") DEFSH (0, debug_ospf_lsa_cmd_vtysh, "debug ospf lsa", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Link State Advertisement\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, show_bgp_ipv6_safi_filter_list_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) filter-list WORD", "Show running system information\n" "BGP information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, no_isis_passwd_arg_cmd_vtysh, "no isis password (md5|clear) WORD", "Negate a command or set its defaults\n" "IS-IS commands\n" "Configure the authentication password for a circuit\n" "HMAC-MD5 authentication\n" "Cleartext password\n" "Circuit password\n") DEFSH (0, show_ip_lcommunity_list_arg_cmd_vtysh, "show ip large-community-list (<1-500>|WORD)", "Show running system information\n" "IP information\n" "List large-community list\n" "large-community-list number\n" "large-community-list name\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, no_ospf6_distance_source_access_list_cmd_vtysh, "no distance <1-255> X:X::X:X/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 (0, debug_bgp_normal_cmd_vtysh, "debug bgp", "Debugging functions (see also 'undebug')\n" "BGP information\n") DEFSH (0, 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 (0, 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 (0, bgp_redistribute_ipv6_rmap_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" " route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, isis_hello_interval_l2_cmd_vtysh, "isis hello-interval <1-600> level-2", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") DEFSH (0, 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 (0, show_ip_ospf_database_type_id_adv_router_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") 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" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Link State ID (as an IP address)\n" "Advertising Router link states\n" "Advertising Router (as an IP address)\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv6_safi_flap_statistics_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n") DEFSH (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, show_ip_pim_assert_winner_metric_cmd_vtysh, "show ip pim assert-winner-metric", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface assert winner metric\n") DEFSH (0, 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 (0, spf_interval_cmd_vtysh, "spf-interval <1-120>", "Minimum interval between SPF calculations\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, show_ipv6_ospf6_database_id_router_detail_cmd_vtysh, "show ipv6 ospf6 database * A.B.C.D A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, ip_ospf_authentication_cmd_vtysh, "ip ospf authentication", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n") DEFSH (0, bgp_redistribute_ipv4_rmap_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" " route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, no_ip_rip_split_horizon_poisoned_reverse_cmd_vtysh, "no ip rip split-horizon poisoned-reverse", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFSH (0, no_link_params_res_bw_cmd_vtysh, "no res-bw", "Negate a command or set its defaults\n" "Disable Unidirectional Residual Bandwidth on this interface\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, no_neighbor_local_as_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>", "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 (0, show_debugging_isis_cmd_vtysh, "show debugging isis", "Show running system information\n" "State of each debugging option\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, show_ip_route_protocol_vrf_all_cmd_vtysh, "show ip route " "(kernel|connected|static|rip|ospf|isis|bgp|pim|babel|nhrp)" " " "vrf all", "Show running system information\n" "IP information\n" "IP routing table\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, clear_bgp_as_cmd_vtysh, "clear bgp " "<1-4294967295>", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n") DEFSH (0|0|0|0|0, match_tag_cmd_vtysh, "match tag <1-4294967295>", "Match values from routing table\n" "Match tag of route\n" "Metric value\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, 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 (0, 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 (0, 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 (0|0|0|0|0|0, rmap_onmatch_next_cmd_vtysh, "on-match next", "Exit policy on matches\n" "Next clause\n") DEFSH (0, bgp_graceful_restart_restart_time_cmd_vtysh, "bgp graceful-restart restart-time <1-3600>", "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") DEFSH (0, show_ip_bgp_rsclient_route_cmd_vtysh, "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, ip_mroute_vrf_cmd_vtysh, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) ""vrf <0-65535>", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_rip_redistribute_type_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)" " metric <0-16>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric\n" "Metric value\n") DEFSH (0, 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 (0, show_ip_bgp_lcommunity_cmd_vtysh, "show ip bgp large-community (AA:BB:CC)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, 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 (0, debug_isis_spftrigg_cmd_vtysh, "debug isis spf-triggers", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS SPF triggering events\n") DEFSH (0, show_ip_ospf_database_type_id_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") 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" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Link State ID (as an IP address)\n") DEFSH (0, 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 (0, 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 (0, 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 (0, key_string_cmd_vtysh, "key-string LINE", "Set key string\n" "The key\n") DEFSH (0, 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 (0, link_params_pkt_loss_cmd_vtysh, "packet-loss PERCENTAGE", "Unidirectional Link Packet Loss\n" "percentage of total traffic by 0.000003tep and less than 50.331642%\n") DEFSH (0, 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 (0, undebug_bgp_fsm_cmd_vtysh, "undebug bgp fsm", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "Finite State Machine\n") DEFSH (0, no_lsp_gen_interval_l1_cmd_vtysh, "no lsp-gen-interval level-1", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n") DEFSH (0, no_multicast_cmd_vtysh, "no multicast", "Negate a command or set its defaults\n" "Unset multicast flag to interface\n") DEFSH (0, ipv6_ripng_split_horizon_cmd_vtysh, "ipv6 ripng split-horizon", "IPv6 information\n" "Routing Information Protocol\n" "Perform split horizon\n") DEFSH (0, no_ospf_log_adjacency_changes_cmd_vtysh, "no log-adjacency-changes", "Negate a command or set its defaults\n" "Log changes in adjacency state\n") DEFSH (0, 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 (0, ripng_default_information_originate_cmd_vtysh, "default-information originate", "Default route information\n" "Distribute default route\n") DEFSH (0, no_ipv6_nd_homeagent_preference_cmd_vtysh, "no ipv6 nd home-agent-preference", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n") DEFSH (0, clear_ip_bgp_all_out_cmd_vtysh, "clear ip bgp * out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Resend all outbound updates\n") DEFSH (0, show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M longer-prefixes", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\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 (0, no_ospf6_redistribute_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|isis|bgp|babel|nhrp)", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" ) DEFSH (0, 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 (0, ospf6_distance_ospf6_external_intra_inter_cmd_vtysh, "distance ospf6 external <1-255> intra-area <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF6 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 (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out the existing ORF prefix-list\n") DEFSH (0, 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 (0, link_params_metric_cmd_vtysh, "metric <0-4294967295>", "Link metric for MPLS-TE purpose\n" "Metric value in decimal\n") DEFSH (0, 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 (0, show_bgp_ipv6_lcommunity_all_cmd_vtysh, "show bgp ipv6 large-community", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the large-communities\n") DEFSH (0, no_ip_lcommunity_list_name_expanded_all_cmd_vtysh, "no ip large-community-list expanded WORD", "Negate a command or set its defaults\n" "IP information\n" "Add a large community list entry\n" "Specify expanded large-community-list\n" "Large Community list name\n") DEFSH (0, ip_route_mask_flags_distance_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, ospf_max_metric_router_lsa_shutdown_cmd_vtysh, "max-metric router-lsa on-shutdown <5-86400>", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Advertise stub-router prior to full shutdown of OSPF\n" "Time (seconds) to wait till full shutdown\n") DEFSH (0, 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 (0, clear_bgp_peer_rsclient_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "BGP information\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, clear_bgp_all_in_cmd_vtysh, "clear bgp * in", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0|0|0|0|0, 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 (0, show_ip_bgp_neighbor_prefix_counts_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts", "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 detailed prefix count information\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, ip_route_mask_flags2_tag_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>" "vrf <0-65535>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_isis_priority_l1_cmd_vtysh, "no isis priority level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Specify priority for level-1 routing\n") DEFSH (0, 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 (0, show_bgp_ipv6_encap_rd_neighbor_routes_cmd_vtysh, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\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 (0, no_ip_address_label_cmd_vtysh, "no ip address A.B.C.D/M label LINE", "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)\n" "Label of this address\n" "Label\n") DEFSH (0, debug_zebra_rib_q_cmd_vtysh, "debug zebra rib queue", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug RIB events\n" "Debug RIB queueing\n") DEFSH (0, ip_route_flags_tag_distance_vrf_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, ipv6_nd_prefix_val_rtaddr_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Set Router Address flag\n") DEFSH (0, default_linkdetect_cmd_vtysh, "default link-detect (on|off)", "Configure defaults of settings\n" "Interface link detection\n" "Interface link-detect defaults to enabled\n" "Interface link-detect defaults to disabled\n") DEFSH (0, show_ip_rpf_addr_vrf_cmd_vtysh, "show ip rpf A.B.C.D " "vrf <0-65535>", "Show running system information\n" "IP information\n" "Display RPF information for multicast source\n" "IP multicast source address (e.g. 10.0.0.0)\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, if_nhrp_mtu_cmd_vtysh, "ip nhrp mtu (<576-1500>|opennhrp)", "IP information\n" "Next Hop Resolution Protocol functions\n" "Configure NHRP advertised MTU\n" "MTU value\n" "Advertise bound interface MTU similar to OpenNHRP") DEFSH (0, 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 (0, no_debug_ospf_nssa_cmd_vtysh, "no debug ospf nssa", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF nssa information\n") DEFSH (0, 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 (0, 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 (0, no_ip_route_vrf_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, isis_default_originate_cmd_vtysh, "default-information originate (ipv4|ipv6) (level-1|level-2) " "{always|metric <0-16777215>|route-map WORD}", "Control distribution of default information\n" "Distribute a default route\n" "Distribute default route for IPv4\n" "Distribute default route for IPv6\n" "Distribute default route into level-1\n" "Distribute default route into level-2\n" "Always advertise default route\n" "Metric for default route\n" "ISIS default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, no_rip_redistribute_type_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0|0|0|0, 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 (0, show_version_ospf6_cmd_vtysh, "show version ospf6", "Show running system information\n" "Displays ospf6d version\n" ) DEFSH (0, no_bgp_maxpaths_ibgp_cmd_vtysh, "no maximum-paths ibgp", "Negate a command or set its defaults\n" "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, 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 (0, rip_allow_ecmp_cmd_vtysh, "allow-ecmp", "Allow Equal Cost MultiPath\n") DEFSH (0, ipv6_route_ifname_flags_pref_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") DEFSH (0, show_bgp_ipv4_community2_cmd_vtysh, "show bgp ipv4 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" "IP 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 (0, show_ip_bgp_view_rsclient_cmd_vtysh, "show ip bgp view WORD rsclient (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" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, no_ip_route_mask_tag_distance_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, isis_hello_interval_l1_cmd_vtysh, "isis hello-interval <1-600> level-1", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") DEFSH (0, show_ipv6_route_prefix_vrf_cmd_vtysh, "show ipv6 route X:X::X:X/M " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "IPv6 prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, debug_igmp_trace_cmd_vtysh, "debug igmp trace", "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP internal daemon activity\n") DEFSH (0, show_ip_bgp_nexthop_detail_cmd_vtysh, "show ip bgp nexthop detail", "Show running system information\n" "IP information\n" "BGP information\n" "BGP nexthop table\n") DEFSH (0, show_bgp_ipv6_safi_cmd_vtysh, "show bgp ipv6 (unicast|multicast)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n") DEFSH (0, 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 (0, 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 (0, show_ipv6_ospf6_database_adv_router_linkstate_id_detail_cmd_vtysh, "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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") DEFSH (0, 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 (0, 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 information\n" "Display connected prefixes to advertise\n" ) DEFSH (0, 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 (0, 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 (0, no_match_lcommunity_cmd_vtysh, "no match large-community (<1-99>|<100-500>|WORD)", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match BGP large community list\n" "Large Community-list number (standard)\n" "Large Community-list number (expanded)\n" "Large Community-list name\n") DEFSH (0, show_ip_route_prefix_longer_vrf_all_cmd_vtysh, "show ip route A.B.C.D/M longer-prefixes " "vrf all", "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" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, show_bgp_ipv4_encap_neighbor_routes_cmd_vtysh, "show bgp ipv4 encap neighbors A.B.C.D routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, show_bgp_view_neighbor_received_prefix_filter_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system 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" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") DEFSH (0, no_lsp_gen_interval_l2_cmd_vtysh, "no lsp-gen-interval level-2", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n") DEFSH (0, no_debug_isis_adj_cmd_vtysh, "no debug isis adj-packets", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Adjacency related packets\n") DEFSH (0, 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 (0, set_aspath_prepend_lastas_cmd_vtysh, "set as-path prepend (last-as) <1-10>", "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "Use the peer's AS-number\n" "Number of times to insert") DEFSH (0, show_ipv6_bgp_lcommunity4_cmd_vtysh, "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, clear_bgp_ipv6_all_cmd_vtysh, "clear bgp ipv6 *", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n") DEFSH (0, 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 (0, 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 (0, neighbor_route_map_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out|import|export)", "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" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") DEFSH (0, debug_igmp_packets_cmd_vtysh, "debug igmp packets", "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP protocol packets\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, show_bgp_ipv6_encap_rd_cmd_vtysh, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "Display BGP tags for prefixes\n") DEFSH (0, no_ripng_allow_ecmp_cmd_vtysh, "no allow-ecmp", "Negate a command or set its defaults\n" "Allow Equal Cost MultiPath\n") DEFSH (0, 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 (0, show_bgp_view_ipv6_neighbor_received_routes_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\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 (0, show_bgp_ipv4_safi_damp_flap_route_map_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics route-map WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, ip_irdp_broadcast_cmd_vtysh, "ip irdp broadcast", "IP information\n" "ICMP Router discovery on this interface using broadcast\n") DEFSH (0, show_ip_route_addr_vrf_all_cmd_vtysh, "show ip route A.B.C.D " "vrf all", "Show running system information\n" "IP information\n" "IP routing table\n" "Network in the IP routing table to display\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, ospf6_distance_ospf6_inter_intra_external_cmd_vtysh, "distance ospf6 inter-area <1-255> intra-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF6 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 (0, no_lsp_refresh_interval_l2_arg_cmd_vtysh, "no lsp-refresh-interval level-2 <1-65235>", "Negate a command or set its defaults\n" "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") DEFSH (0, show_isis_topology_l2_cmd_vtysh, "show isis topology level-2", "Show running system information\n" "IS-IS information\n" "IS-IS paths to Intermediate Systems\n" "Paths to all level-2 routers in the domain\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, 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 (0, no_isis_hello_multiplier_cmd_vtysh, "no isis hello-multiplier", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n") DEFSH (0, no_debug_isis_spfstats_cmd_vtysh, "no debug isis spf-statistics", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS SPF Timing and Statistic Data\n") DEFSH (0|0|0|0, 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 (0, no_ip_route_mask_flags_tag_distance2_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, 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 (0, 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 (0, 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 (0|0|0|0|0|0, no_rmap_onmatch_goto_cmd_vtysh, "no on-match goto", "Negate a command or set its defaults\n" "Exit policy on matches\n" "Goto Clause number\n") DEFSH (0, show_bgp_ipv4_safi_cidr_only_cmd_vtysh, "show bgp ipv4 (unicast|multicast) cidr-only", "Show running system 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 (0, ospf6_distance_ospf6_intra_inter_external_cmd_vtysh, "distance ospf6 intra-area <1-255> inter-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF6 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 (0, 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 (0, dynamic_hostname_cmd_vtysh, "hostname dynamic", "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") DEFSH (0, ipv6_ospf6_mtu_ignore_cmd_vtysh, "ipv6 ospf6 mtu-ignore", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Ignore MTU mismatch on this interface\n" ) DEFSH (0, show_bgp_statistics_vpnv4_cmd_vtysh, "show bgp (ipv4) (vpnv4) statistics", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFSH (0|0, 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 (0, show_isis_interface_cmd_vtysh, "show isis interface", "Show running system information\n" "ISIS network information\n" "ISIS interface\n") DEFSH (0, no_ip_irdp_cmd_vtysh, "no ip irdp", "Negate a command or set its defaults\n" "IP information\n" "Disable ICMP Router discovery on this interface\n") DEFSH (0, ipv6_nd_prefix_noval_offlink_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for onlink determination\n") DEFSH (0, ospf6_log_adjacency_changes_detail_cmd_vtysh, "log-adjacency-changes detail", "Log changes in adjacency state\n" "Log all state changes\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, show_ip_bgp_damp_flap_statistics_cmd_vtysh, "show ip bgp dampening flap-statistics", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") DEFSH (0, test_pim_receive_hello_cmd_vtysh, "test pim receive hello INTERFACE A.B.C.D <0-65535> <0-65535> <0-65535> <0-32767> <0-65535> <0-1>[LINE]", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM hello reception from neighbor\n" "Interface\n" "Neighbor address\n" "Neighbor holdtime\n" "Neighbor DR priority\n" "Neighbor generation ID\n" "Neighbor propagation delay (msec)\n" "Neighbor override interval (msec)\n" "Neighbor LAN prune delay T-bit\n" "Neighbor secondary addresses\n") DEFSH (0, test_igmp_receive_report_cmd_vtysh, "test igmp receive report <0-65535> A.B.C.D <1-6> .LINE", "Test\n" "Test IGMP protocol\n" "Test IGMP message\n" "Test IGMP report\n" "Socket\n" "IGMP group address\n" "Record type\n" "Sources\n") DEFSH (0, no_debug_pim_cmd_vtysh, "no debug pim", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n") DEFSH (0, debug_rip_events_cmd_vtysh, "debug rip events", "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP events\n") DEFSH (0, 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" "Display Intra-Area routes\n" "Display Inter-Area routes\n" "Display Type-1 External routes\n" "Display Type-2 External routes\n" "Detailed information\n" ) DEFSH (0, show_isis_interface_arg_cmd_vtysh, "show isis interface WORD", "Show running system information\n" "ISIS network information\n" "ISIS interface\n" "ISIS interface name\n") DEFSH (0|0|0|0, 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 (0, show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd_vtysh, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN 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" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, show_zebra_client_summary_cmd_vtysh, "show zebra client summary", "Show running system information\n" "Zebra information brief" "Client information brief") DEFSH (0, 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 (0, 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 (0, 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 (0, link_params_maxbw_cmd_vtysh, "max-bw BANDWIDTH", "Maximum bandwidth that can be used\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, 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 (0, debug_pim_cmd_vtysh, "debug pim", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n") DEFSH (0, 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 (0, no_debug_isis_csum_cmd_vtysh, "no debug isis checksum-errors", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS LSP checksum errors\n") DEFSH (0, show_ip_bgp_damp_flap_route_map_cmd_vtysh, "show ip bgp dampening flap-statistics route-map WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, debug_zebra_rib_cmd_vtysh, "debug zebra rib", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug RIB events\n") DEFSH (0, 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 (0, if_no_nhrp_flags_cmd_vtysh, "no " "(ip|ipv6)" " nhrp (shortcut|redirect)", "Negate a command or set its defaults\n" "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Allow shortcut establishment\n" "Send redirect notifications\n") DEFSH (0, 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 (0, show_ipv6_ospf6_database_linkstate_id_cmd_vtysh, "show ipv6 ospf6 database linkstate-id A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0|0|0|0|0, no_match_tag_val_cmd_vtysh, "no match tag <1-4294967295>", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match tag of route\n" "Metric value\n") DEFSH (0, 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 (0, show_bgp_ipv4_cidr_only_cmd_vtysh, "show bgp ipv4 cidr-only", "Show running system information\n" "BGP information\n" "IP information\n" "Display only routes with non-natural netmasks\n") DEFSH (0, no_ip_ospf_dead_interval_addr_cmd_vtysh, "no ip ospf dead-interval <1-65535> 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" "Seconds\n" "Address of interface") DEFSH (0, 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 (0, no_isis_hello_interval_l2_arg_cmd_vtysh, "no isis hello-interval <1-600> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") DEFSH (0, debug_bgp_as4_cmd_vtysh, "debug bgp as4", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP AS4 actions\n") DEFSH (0, 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 (0, no_ip_route_flags_tag_distance_vrf_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_bgp_ipv4_safi_community2_cmd_vtysh, "show 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" "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 (0, 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 (0, isis_priority_l1_cmd_vtysh, "isis priority <0-127> level-1", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-1 routing\n") DEFSH (0, ip_irdp_address_preference_cmd_vtysh, "ip irdp address A.B.C.D preference <0-2147483647>", "IP information\n" "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") DEFSH (0, no_ripng_offset_list_ifname_cmd_vtysh, "no offset-list WORD (in|out) <0-16> IFNAME", "Negate a command or set its defaults\n" "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") DEFSH (0, 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 (0, no_csnp_interval_l1_cmd_vtysh, "no isis csnp-interval level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "Specify interval for level-1 CSNPs\n") DEFSH (0, show_bgp_ipv4_community_list_exact_cmd_vtysh, "show bgp ipv4 community-list (<1-500>|WORD) exact-match", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") DEFSH (0, no_lsp_refresh_interval_arg_cmd_vtysh, "no lsp-refresh-interval <1-65235>", "Negate a command or set its defaults\n" "LSP refresh interval\n" "LSP refresh interval in seconds\n") DEFSH (0|0|0, no_router_zebra_cmd_vtysh, "no router zebra", "Negate a command or set its defaults\n" "Disable a routing process\n" "Stop connection to zebra daemon\n") DEFSH (0, 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 (0, 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 (0, show_zebra_cmd_vtysh, "show zebra", "Show running system information\n" "Zebra information\n") DEFSH (0, show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family modifier\n" "Address Family modifier\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 (0, 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 (0, no_exec_timeout_cmd_vtysh, "no exec-timeout", "Negate a command or set its defaults\n" "Set the EXEC timeout\n") DEFSH (0, ipv6_route_ifname_tag_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_ip_route_flags_distance_vrf_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, area_passwd_md5_cmd_vtysh, "(area-password|domain-password) md5 WORD", "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n" "Authentication type\n" "Level-wide password\n") DEFSH (0, show_ipv6_route_summary_vrf_all_cmd_vtysh, "show ipv6 route summary " "vrf all", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, no_debug_isis_events_cmd_vtysh, "no debug isis events", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Events\n") DEFSH (0, no_debug_zebra_rib_q_cmd_vtysh, "no debug zebra rib queue", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug zebra RIB\n" "Debug RIB queueing\n") DEFSH (0, neighbor_update_source_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source " "(A.B.C.D|X:X::X:X|WORD)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Source of routing updates\n" "IPv4 address\n" "IPv6 address\n" "Interface name (requires zebra to be running)\n") DEFSH (0, 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 (0, no_ip_ospf_mtu_ignore_cmd_vtysh, "no ip ospf mtu-ignore", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") DEFSH (0, 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 (0, 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 (0, clear_bgp_ipv6_as_in_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, rip_redistribute_type_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)" " metric <0-16>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric\n" "Metric value\n") DEFSH (0, show_ipv6_route_addr_vrf_all_cmd_vtysh, "show ipv6 route X:X::X:X " "vrf all", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "IPv6 Address\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, match_local_pref_cmd_vtysh, "match local-preference <0-4294967295>", "Match values from routing table\n" "Match local-preference of route\n" "Metric value\n") DEFSH (0, 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 (0, 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 (0, show_ip_igmp_interface_cmd_vtysh, "show ip igmp interface", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP interface information\n") DEFSH (0, no_rip_allow_ecmp_cmd_vtysh, "no allow-ecmp", "Negate a command or set its defaults\n" "Allow Equal Cost MultiPath\n") DEFSH (0, no_debug_ospf6_lsa_hex_cmd_vtysh, "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", "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 (0, ipv6_route_ifname_flags_tag_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, 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 (0, link_params_enable_cmd_vtysh, "enable", "Activate link parameters on this interface\n") DEFSH (0, 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 (0, 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 (0, 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 (0, link_params_delay_var_cmd_vtysh, "delay-variation <0-16777215>", "Unidirectional Link Delay Variation\n" "delay variation in micro-second as decimal (0...16777215)\n") DEFSH (0|0|0|0, 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 (0, no_dump_bgp_all_cmd_vtysh, "no dump bgp (all|updates|routes-mrt) [PATH] [INTERVAL]", "Negate a command or set its defaults\n" "Stop dump packet\n" "Stop BGP packet dump\n" "Stop dump process all/all-et\n" "Stop dump process updates/updates-et\n" "Stop dump process route-mrt\n") DEFSH (0, match_peer_cmd_vtysh, "match peer (A.B.C.D|X:X::X:X)", "Match values from routing table\n" "Match peer address\n" "IP address of peer\n" "IPv6 address of peer\n") DEFSH (0, 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 (0|0|0|0, 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 (0, ip_route_mask_flags_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, no_isis_priority_l1_arg_cmd_vtysh, "no isis priority <0-127> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-1 routing\n") DEFSH (0, no_psnp_interval_arg_cmd_vtysh, "no isis psnp-interval <1-120>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n") DEFSH (0, 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 (0, show_ipv6_ospf6_database_self_originated_cmd_vtysh, "show ipv6 ospf6 database self-originated", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Self-originated LSAs\n" ) DEFSH (0, show_bgp_ipv6_safi_rsclient_route_cmd_vtysh, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 (0, 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 (0, no_isis_network_cmd_vtysh, "no isis network point-to-point", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set network type for circuit\n" "point-to-point network type\n") DEFSH (0, no_ipv6_route_ifname_flags_pref_tag_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") DEFSH (0, 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 (0, 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 (0, 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 (0, show_bgp_ipv4_encap_summary_cmd_vtysh, "show bgp ipv4 encap summary", "Show running system information\n" "BGP information\n" "IPv4\n" "Display ENCAP NLRI specific information\n" "Summary of BGP neighbor status\n") DEFSH (0, 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 (0, 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 (0, 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 (0, no_isis_mpls_te_on_cmd_vtysh, "no mpls-te", "Negate a command or set its defaults\n" "Disable the MPLS-TE functionality\n") DEFSH (0, 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 (0, bgp_redistribute_ipv6_rmap_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, show_bgp_instance_ipv4_summary_cmd_vtysh, "show bgp view WORD ipv4 summary", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family modifier\n" "Address Family modifier\n" "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") DEFSH (0, show_bgp_view_ipv4_rsclient_cmd_vtysh, "show bgp view WORD ipv4 rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address Family\n" "Information about Route Server Client\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n") DEFSH (0, 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 (0, 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 (0, no_rip_passive_interface_cmd_vtysh, "no passive-interface (IFNAME|default)", "Negate a command or set its defaults\n" "Suppress routing updates on an interface\n" "Interface name\n" "default for all interfaces\n") DEFSH (0, rip_route_cmd_vtysh, "route A.B.C.D/M", "RIP static route configuration\n" "IP prefix /\n") DEFSH (0, 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 (0, clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, 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 (0, show_ipv6_mroute_vrf_all_cmd_vtysh, "show ipv6 mroute " "vrf all", "Show running system information\n" "IP information\n" "IPv6 Multicast routing table\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, show_bgp_ipv6_vpn_neighbor_routes_cmd_vtysh, "show bgp ipv6 vpn neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific 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 (0, bgp_graceful_restart_cmd_vtysh, "bgp graceful-restart", "BGP specific commands\n" "Graceful restart capability parameters\n") DEFSH (0, no_isis_hello_interval_arg_cmd_vtysh, "no isis hello-interval <1-600>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n") DEFSH (0, 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 (0, show_bgp_ipv4_vpn_rd_neighbor_routes_cmd_vtysh, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family modifier\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 (0, 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 (0, show_ip_bgp_ipv4_lcommunity_list_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) large-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 large-community-list\n" "large-community-list number\n" "large-community-list name\n") DEFSH (0, area_export_list_cmd_vtysh, "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") DEFSH (0, no_ip_lcommunity_list_name_standard_cmd_vtysh, "no ip large-community-list standard WORD (deny|permit) .AA:.AA:NN", "Negate a command or set its defaults\n" "IP information\n" "Add a large community list entry\n" "Specify standard large-community-list\n" "Large Community list name\n" "Specify large community to reject\n" "Specify large community to accept\n" "large community in 'aa:bb:cc' format\n") DEFSH (0, no_debug_ospf6_brouter_area_cmd_vtysh, "no debug ospf6 border-routers area-id", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" "Debug border routers in specific Area\n" ) DEFSH (0, no_debug_mroute_cmd_vtysh, "no debug mroute", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM interaction with kernel MFC cache\n") DEFSH (0, 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 (0, 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 (0, 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 (0, show_ipv6_route_cmd_vtysh, "show ipv6 route", "Show running system information\n" "IP information\n" "IPv6 routing table\n") DEFSH (0, ip_route_mask_tag_distance_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, no_area_filter_list_cmd_vtysh, "no area A.B.C.D filter-list prefix WORD (in|out)", "Negate a command or set its defaults\n" "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") DEFSH (0, show_bgp_view_neighbor_flap_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system 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" "Display flap statistics of the routes learned from neighbor\n") DEFSH (0, clear_zebra_fpm_stats_cmd_vtysh, "clear zebra fpm stats", "Reset functions\n" "Zebra information\n" "Clear Forwarding Path Manager information\n" "Statistics\n") DEFSH (0, ip_forwarding_cmd_vtysh, "ip forwarding", "IP information\n" "Turn on IP forwarding") DEFSH (0, no_isis_passive_cmd_vtysh, "no isis passive", "Negate a command or set its defaults\n" "IS-IS commands\n" "Configure the passive mode for interface\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, clear_bgp_as_out_cmd_vtysh, "clear bgp " "<1-4294967295>" " out", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Resend all outbound updates\n") DEFSH (0, isis_hello_multiplier_l2_cmd_vtysh, "isis hello-multiplier <2-100> level-2", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") DEFSH (0, 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 (0, show_bgp_instance_ipv6_neighbors_peer_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\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 (0, 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 (0, neighbor_send_community_type_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|all|extended|standard|large)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Send Community attribute to this neighbor\n" "Send Standard, Large and Extended Community attributes\n" "Send Standard, Large and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n" "Send Large Community attributes\n") DEFSH (0, no_ip_ospf_hello_interval_seconds_cmd_vtysh, "no ip ospf hello-interval <1-65535>", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") DEFSH (0, 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 (0, ipv6_route_ifname_flags_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, no_ip_mroute_dist_vrf_cmd_vtysh, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255> " "vrf <0-65535>", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_bgp_redistribute_ipv4_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" " metric <0-4294967295>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, set_metric_rtt_cmd_vtysh, "set metric (rtt|+rtt|-rtt)", "Set values in destination routing protocol\n" "Metric value for destination routing protocol\n" "Assign round trip time\n" "Add round trip time\n" "Subtract round trip time\n") DEFSH (0, 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 (0, 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 (0, ip_route_mask_flags_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, 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 (0, clear_ip_mroute_cmd_vtysh, "clear ip mroute", "Reset functions\n" "IP information\n" "Reset multicast routes\n") DEFSH (0, isis_hello_multiplier_l1_cmd_vtysh, "isis hello-multiplier <2-100> level-1", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") DEFSH (0, clear_ip_bgp_all_encap_soft_out_cmd_vtysh, "clear ip bgp * encap 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 (0, show_bgp_rsclient_prefix_cmd_vtysh, "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, ospf_area_authentication_message_digest_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) authentication message-digest", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Enable authentication\n" "Use message-digest authentication\n") DEFSH (0, clear_ip_bgp_all_cmd_vtysh, "clear ip bgp *", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n") DEFSH (0, show_ip_pim_interface_cmd_vtysh, "show ip pim interface", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface information\n") DEFSH (0, show_ip_pim_jp_override_interval_cmd_vtysh, "show ip pim jp-override-interval", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface J/P override interval\n") DEFSH (0, show_bgp_ipv4_safi_damp_flap_prefix_list_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics prefix-list WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, 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 (0, 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 calculation\n" "Show SPF tree\n" "Specify root's router-id to calculate another router's SPF tree\n") DEFSH (0, neighbor_timers_connect_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "timers connect <1-65535>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") DEFSH (0, no_max_lsp_lifetime_arg_cmd_vtysh, "no max-lsp-lifetime <350-65535>", "Negate a command or set its defaults\n" "Maximum LSP lifetime\n" "LSP lifetime in seconds\n") DEFSH (0, 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 (0, 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 (0, no_vrf_netns_cmd_vtysh, "no vrf <1-65535> netns NAME", "Negate a command or set its defaults\n" "Enable a VRF\n" "Specify the VRF identifier\n" "Associate with a NETNS\n" "The file name in " "/var/run/netns" ", or a full pathname\n") DEFSH (0, show_ip_bgp_damp_flap_cidr_only_cmd_vtysh, "show ip bgp dampening flap-statistics cidr-only", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") DEFSH (0, 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 (0, 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 (0, 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 (0, no_ip_ospf_dead_interval_seconds_cmd_vtysh, "no ip ospf dead-interval <1-65535>", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd_vtysh, "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts", "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 detailed prefix count information\n") DEFSH (0, no_debug_isis_upd_cmd_vtysh, "no debug isis update-packets", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Update related packets\n") DEFSH (0, show_bgp_ipv6_lcommunity2_cmd_vtysh, "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, 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 (0, clear_ip_bgp_peer_encap_out_cmd_vtysh, "clear ip bgp A.B.C.D encap 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 (0, show_bgp_ipv6_safi_neighbor_damp_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system information\n" "BGP information\n" "Address Family Modifier\n" "Address Family Modifier\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 dampened routes received from neighbor\n") DEFSH (0, ipv6_route_ifname_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_bgp_view_prefix_cmd_vtysh, "show bgp view WORD X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "IPv6 prefix /\n") DEFSH (0, 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 (0, 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 (0, 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 (0, ipv6_address_cmd_vtysh, "ipv6 address X:X::X:X/M", "Interface IPv6 config commands\n" "Set the IP address of an interface\n" "IPv6 address (e.g. 3ffe:506::1/48)\n") DEFSH (0, 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 (0, show_ip_pim_join_cmd_vtysh, "show ip pim join", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface join information\n") DEFSH (0, show_ip_bgp_rsclient_cmd_vtysh, "show ip bgp rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "IP information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, no_debug_igmp_events_cmd_vtysh, "no debug igmp events", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP protocol events\n") DEFSH (0, 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 (0, 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 (0, link_params_unrsv_bw_cmd_vtysh, "unrsv-bw <0-7> BANDWIDTH", "Unreserved bandwidth at each priority level\n" "Priority\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, 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 (0, no_ipv6_ospf6_mtu_ignore_cmd_vtysh, "no ipv6 ospf6 mtu-ignore", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Ignore MTU mismatch on this interface\n" ) DEFSH (0, 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 (0, 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 (0, clear_bgp_all_cmd_vtysh, "clear bgp *", "Reset functions\n" "BGP information\n" "Clear all peers\n") DEFSH (0, 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 (0, show_ipv6_mbgp_lcommunity_all_cmd_vtysh, "show ipv6 mbgp large-community", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the large-communities\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n") DEFSH (0, no_set_metric_addsub_cmd_vtysh, "no set metric <+/-metric>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Metric value for destination routing protocol\n" "Add or subtract metric\n") DEFSH (0, 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 (0, no_csnp_interval_l1_arg_cmd_vtysh, "no isis csnp-interval <1-600> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") DEFSH (0, clear_ip_bgp_as_soft_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, show_bgp_ipv6_vpn_prefix_cmd_vtysh, "show bgp ipv6 vpn X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0|0, 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 (0, clear_ip_bgp_as_in_prefix_filter_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_isis_priority_l2_cmd_vtysh, "no isis priority level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Specify priority for level-2 routing\n") DEFSH (0, show_bgp_view_neighbor_advertised_route_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system 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" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, show_bgp_ipv4_vpn_prefix_cmd_vtysh, "show bgp ipv4 vpn A.B.C.D/M", "Show running system information\n" "BGP information\n" "IP information\n" "Display VPN NLRI specific information\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_ip_route_mask_flags_tag_distance_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_lcommunity3_cmd_vtysh, "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, no_area_passwd_cmd_vtysh, "no (area-password|domain-password)", "Negate a command or set its defaults\n" "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n") DEFSH (0, 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 (0, show_bgp_ipv6_rsclient_prefix_cmd_vtysh, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, 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 (0, 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 (0, 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 (0, ripng_allow_ecmp_cmd_vtysh, "allow-ecmp", "Allow Equal Cost MultiPath\n") DEFSH (0, 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 (0, no_ip_route_mask_flags_distance_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, 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 (0, 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 (0, no_if_ipv6_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 (0, 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 (0, 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 (0, 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 (0, 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 (0, no_is_type_cmd_vtysh, "no is-type (level-1|level-1-2|level-2-only)", "Negate a command or set its defaults\n" "IS Level for this routing process (OSI only)\n" "Act as a station router only\n" "Act as both a station router and an area router\n" "Act as an area router only\n") DEFSH (0, show_ip_community_list_cmd_vtysh, "show ip community-list", "Show running system information\n" "IP information\n" "List community-list\n") DEFSH (0, no_ipv6_nd_homeagent_preference_val_cmd_vtysh, "no ipv6 nd home-agent-preference <0-65535>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" "preference value (default is 0, least preferred)\n") DEFSH (0, debug_bgp_as4_segment_cmd_vtysh, "debug bgp as4 segment", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") DEFSH (0, show_ip_ospf_router_info_cmd_vtysh, "show ip ospf router-info", "Show running system information\n" "IP information\n" "OSPF information\n" "Router Information\n") DEFSH (0, isis_network_cmd_vtysh, "isis network point-to-point", "IS-IS commands\n" "Set network type\n" "point-to-point network type\n") DEFSH (0, show_zebra_client_cmd_vtysh, "show zebra client", "Show running system information\n" "Zebra information" "Client information") DEFSH (0, ipv6_route_tag_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, clear_bgp_all_rsclient_cmd_vtysh, "clear bgp * rsclient", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0|0, no_debug_isis_lsp_sched_cmd_vtysh, "no debug isis lsp-gen", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS scheduling of LSP generation\n") DEFSH (0, show_ipv6_ospf6_database_type_linkstate_id_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, no_ip_irdp_shutdown_cmd_vtysh, "no ip irdp shutdown", "Negate a command or set its defaults\n" "IP information\n" "ICMP Router discovery no shutdown on this interface\n") DEFSH (0, no_ip_route_distance_vrf_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255> " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_bgp_ipv6_safi_flap_prefix_list_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics prefix-list WORD", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, debug_bgp_events_cmd_vtysh, "debug bgp events", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP events\n") DEFSH (0, show_bgp_ipv4_safi_damp_flap_filter_list_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics filter-list WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, ipv6_nd_prefix_val_rev_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n") DEFSH (0, 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 (0, metric_style_cmd_vtysh, "metric-style (narrow|transition|wide)", "Use old-style (ISO 10589) or new-style packet formats\n" "Use old style of TLVs with narrow metric\n" "Send and accept both styles of TLVs during transition\n" "Use new style of TLVs to carry wider metric\n") DEFSH (0|0, 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 (0, 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 (0, show_bgp_ipv4_safi_flap_cidr_only_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics cidr-only", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") DEFSH (0, 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 (0, 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" "View name\n" "Network in the BGP routing table to display\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, set_atomic_aggregate_cmd_vtysh, "set atomic-aggregate", "Set values in destination routing protocol\n" "BGP atomic aggregate attribute\n" ) DEFSH (0, 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 (0, show_ipv6_ospf6_database_adv_router_cmd_vtysh, "show ipv6 ospf6 database adv-router A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" ) DEFSH (0, show_bgp_ipv6_vpn_rd_route_cmd_vtysh, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn X:X::X:X", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN 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 (0, ip_lcommunity_list_expanded_cmd_vtysh, "ip large-community-list <100-500> (deny|permit) .LINE", "IP information\n" "Add a large community list entry\n" "Large Community list number (expanded)\n" "Specify large community to reject\n" "Specify large community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, ospf6_routemap_set_forwarding_cmd_vtysh, "set forwarding-address X:X::X:X", "Set value\n" "Forwarding Address\n" "IPv6 Address\n") DEFSH (0, no_ospf_opaque_capable_cmd_vtysh, "no ospf opaque-lsa", "Negate a command or set its defaults\n" "OSPF specific commands\n" "Disable the Opaque-LSA capability (rfc2370)\n") DEFSH (0, no_ipv6_route_ifname_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_lsp_refresh_interval_cmd_vtysh, "no lsp-refresh-interval", "Negate a command or set its defaults\n" "LSP refresh interval in seconds\n") DEFSH (0, ipv6_route_ifname_flags_pref_tag_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") DEFSH (0, show_bgp_instance_ipv4_safi_summary_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) summary", "Show running system 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 (0, 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 inbound and outbound updates\n") DEFSH (0, no_lsp_refresh_interval_l2_cmd_vtysh, "no lsp-refresh-interval level-2", "Negate a command or set its defaults\n" "LSP refresh interval for Level 2 only in seconds\n") DEFSH (0, 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 (0, rip_redistribute_rip_cmd_vtysh, "redistribute rip", "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") DEFSH (0, debug_bgp_nht_cmd_vtysh, "debug bgp nht", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP nexthop tracking events\n") DEFSH (0, 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 (0, debug_isis_events_cmd_vtysh, "debug isis events", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Events\n") DEFSH (0, show_bgp_ipv6_lcommunity_list_cmd_vtysh, "show bgp ipv6 large-community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") DEFSH (0, no_debug_isis_lupd_cmd_vtysh, "no debug isis local-updates", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS local update packets\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, ip_route_mask_flags_distance2_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, no_max_lsp_lifetime_l1_arg_cmd_vtysh, "no max-lsp-lifetime level-1 <350-65535>", "Negate a command or set its defaults\n" "Maximum LSP lifetime for Level 1 only\n" "LSP lifetime for Level 1 only in seconds\n") DEFSH (0, show_bgp_ipv4_safi_prefix_cmd_vtysh, "show bgp ipv4 (unicast|multicast) A.B.C.D/M", "Show running system 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 (0, show_bgp_ipv4_safi_flap_route_map_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics route-map WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, 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 (0, clear_ip_bgp_peer_encap_soft_out_cmd_vtysh, "clear ip bgp A.B.C.D encap 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 (0, 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 (0, no_ipv6_route_ifname_flags_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, if_nhrp_nhs_cmd_vtysh, "(ip|ipv6)" " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)", "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Nexthop Server configuration\n" "IPv4 protocol address\n" "IPv6 protocol address\n" "Automatic detection of protocol address\n" "IPv4 NBMA address\n" "Fully qualified domain name for NBMA address(es)\n") DEFSH (0, 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 (0, show_ipv6_route_summary_prefix_cmd_vtysh, "show ipv6 route summary prefix", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Prefix routes\n") DEFSH (0, 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 (0|0|0|0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, no_isis_hello_padding_cmd_vtysh, "no isis hello padding", "Negate a command or set its defaults\n" "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") DEFSH (0, ospf_hello_interval_cmd_vtysh, "ospf hello-interval <1-65535>", "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") DEFSH (0, no_neighbor_peer_group_remote_as_cmd_vtysh, "no neighbor WORD remote-as " "<1-4294967295>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor tag\n" "Specify a BGP neighbor\n" "AS number\n") DEFSH (0, 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 (0, match_probability_cmd_vtysh, "match probability <0-100>", "Match values from routing table\n" "Match portion of routes defined by percentage value\n" "Percentage of routes\n") DEFSH (0, ospf6_distance_ospf6_inter_intra_cmd_vtysh, "distance ospf6 inter-area <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "Intra-area routes\n" "Distance for intra-area routes\n") DEFSH (0, show_ip_ospf_neighbor_int_detail_cmd_vtysh, "show ip ospf neighbor IFNAME detail", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n" "Interface name\n" "detail of all neighbors") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, ip_router_isis_cmd_vtysh, "(ip|ipv6) router isis WORD", "Interface Internet Protocol config commands\n" "IP router interface commands\n" "IS-IS Routing for IP\n" "Routing process tag\n") DEFSH (0, 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 (0, 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 (0, ip_irdp_debug_packet_cmd_vtysh, "ip irdp debug packet", "IP information\n" "ICMP Router discovery debug Averts. and Solicits (short)\n") DEFSH (0, show_isis_neighbor_cmd_vtysh, "show isis neighbor", "Show running system information\n" "ISIS network information\n" "ISIS neighbor adjacencies\n") DEFSH (0, clear_bgp_instance_all_rsclient_cmd_vtysh, "clear bgp view WORD * rsclient", "Reset functions\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, 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 (0, no_debug_pim_zebra_cmd_vtysh, "no debug pim zebra", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "ZEBRA protocol activity\n") DEFSH (0|0|0|0, 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 (0, no_neighbor_local_as_val2_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>" " 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 (0, 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 (0, ipv6_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 (0|0|0|0, 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 (0, 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 (0, 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 (0, 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 (0, no_match_ipv6_address_cmd_vtysh, "no match ipv6 address", "Negate a command or set its defaults\n" "Match values from routing table\n" "IPv6 information\n" "Match IPv6 address of route\n" ) DEFSH (0|0, 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 (0, 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" "Community-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") DEFSH (0, no_isis_passwd_cmd_vtysh, "no isis password", "Negate a command or set its defaults\n" "IS-IS commands\n" "Configure the authentication password for a circuit\n") DEFSH (0, interface_no_ip_pim_hello_cmd_vtysh, "no ip pim hello {<1-180> <1-180>}", "Negate a command or set its defaults\n" "IP information\n" "PIM information\n" "Hello Interval\n" "Time in seconds for Hello Interval\n" "Time in seconds for Hold Interval\n") DEFSH (0, 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 (0|0|0, 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 (0, no_bgp_redistribute_ipv4_rmap_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_ipv6_ospf6_database_linkstate_id_detail_cmd_vtysh, "show ipv6 ospf6 database linkstate-id A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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 (0, no_ip_route_flags_tag_distance2_vrf_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, undebug_pim_packetdump_send_cmd_vtysh, "undebug pim packet-dump send", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump sent packets\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, show_bgp_instance_rsclient_summary_cmd_vtysh, "show bgp view WORD rsclient summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, no_csnp_interval_l2_cmd_vtysh, "no isis csnp-interval level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "Specify interval for level-2 CSNPs\n") DEFSH (0, no_nhrp_event_socket_cmd_vtysh, "no nhrp event socket [SOCKET]", "Negate a command or set its defaults\n" "Next Hop Resolution Protocol functions\n" "Event Manager commands\n" "Event Manager unix socket path\n" "Unix path for the socket\n") DEFSH (0|0|0|0, 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 (0, 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 (0, show_bgp_ipv4_encap_rd_neighbor_routes_cmd_vtysh, "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\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 (0, 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 (0, undebug_bgp_as4_cmd_vtysh, "undebug bgp as4", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP AS4 actions\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, show_bgp_ipv6_safi_rsclient_summary_cmd_vtysh, "show bgp ipv6 (unicast|multicast) rsclient summary", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, encap_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" "ENCAP Route Distinguisher\n" "BGP tag\n" "tag value\n") DEFSH (0|0|0|0|0, no_set_tag_cmd_vtysh, "no set tag", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Tag value for routing protocol\n") DEFSH (0, ip_route_mask_flags_tag_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") DEFSH (0, show_ipv6_route_summary_prefix_vrf_all_cmd_vtysh, "show ipv6 route summary prefix " "vrf all", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Prefix routes\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_community4_exact_cmd_vtysh, "show 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" "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 (0, show_bgp_lcommunity3_cmd_vtysh, "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, no_isis_redistribute_cmd_vtysh, "no redistribute (ipv4|ipv6) " "(kernel|connected|static|rip|ripng|ospf|ospf6|bgp|pim|babel|nhrp)" " (level-1|level-2)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Redistribute IPv4 routes\n" "Redistribute IPv6 routes\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (OSPFv2)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Redistribute into level-1\n" "Redistribute into level-2\n") DEFSH (0, show_bgp_ipv4_lcommunity2_cmd_vtysh, "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, show_ip_bgp_route_pathtype_cmd_vtysh, "show ip bgp A.B.C.D (bestpath|multipath)", "Show running system information\n" "IP information\n" "BGP information\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display only the bestpath\n" "Display only multipaths\n") DEFSH (0|0|0|0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, no_ospf6_distance_source_cmd_vtysh, "no distance <1-255> X:X::X:X/M", "Negate a command or set its defaults\n" "Administrative distance\n" "Distance value\n" "IP source prefix\n") DEFSH (0, clear_ip_bgp_as_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Resend all outbound updates\n") DEFSH (0, no_bgp_maxpaths_cmd_vtysh, "no maximum-paths", "Negate a command or set its defaults\n" "Forward packets over multiple paths\n" "Number of paths\n") DEFSH (0, 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 (0, ip_route_flags_distance_vrf_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_ospf_mpls_te_inter_as_cmd_vtysh, "no mpls-te inter-as", "Negate a command or set its defaults\n" "MPLS-TE specific commands\n" "Disable MPLS-TE Inter-AS support\n") DEFSH (0, show_bgp_ipv4_safi_lcommunity2_cmd_vtysh, "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, 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 (0, show_ipv6_bgp_lcommunity_all_cmd_vtysh, "show ipv6 bgp large-community", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the large-communities\n") DEFSH (0, ipv6_route_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, debug_ospf6_brouter_cmd_vtysh, "debug ospf6 border-routers", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" ) DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, 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" "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n") DEFSH (0, 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 (0, 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 (0, show_ip_route_protocol_vrf_cmd_vtysh, "show ip route " "(kernel|connected|static|rip|ospf|isis|bgp|pim|babel|nhrp)" " " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, show_ip_ospf_database_type_adv_router_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") 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" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Advertising Router link states\n" "Advertising Router (as an IP address)\n") DEFSH (0, no_ipv6_route_flags_pref_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, 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 (0|0|0|0, 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 (0, ospf_redistribute_source_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|isis|bgp|pim|babel|nhrp)" " {metric <0-16777214>|metric-type (1|2)|route-map WORD}", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\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 (0, 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 (0, ospf_opaque_capable_cmd_vtysh, "ospf opaque-lsa", "OSPF specific commands\n" "Enable the Opaque-LSA capability (rfc2370)\n") DEFSH (0, no_bgp_maxpaths_ibgp_arg_cmd_vtysh, "no maximum-paths ibgp " "<" "1" "-" "1" ">", "Negate a command or set its defaults\n" "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") DEFSH (0, show_bgp_view_ipv6_rsclient_prefix_cmd_vtysh, "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "IPv6 Information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, no_ip_lcommunity_list_expanded_all_cmd_vtysh, "no ip large-community-list <100-500>", "Negate a command or set its defaults\n" "IP information\n" "Add a large community list entry\n" "Large Community list number (expanded)\n") DEFSH (0, debug_isis_err_cmd_vtysh, "debug isis protocol-errors", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS LSP protocol errors\n") DEFSH (0, no_ipv6_route_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv4_safi_neighbor_received_routes_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\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 (0, no_ip_route_mask_flags_tag_distance2_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_bgp_rsclient_summary_cmd_vtysh, "show bgp rsclient summary", "Show running system information\n" "BGP information\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, ipv6_nd_prefix_prefix_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n") DEFSH (0, 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 (0, no_bgp_bestpath_aspath_confed_cmd_vtysh, "no bgp bestpath as-path confed", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Compare path lengths including confederation sets & sequences in selecting a route\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_debug_pim_packetdump_send_cmd_vtysh, "no debug pim packet-dump send", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump sent packets\n") DEFSH (0|0|0, ospf6_routemap_match_address_prefixlist_cmd_vtysh, "match ipv6 address prefix-list WORD", "Match values\n" "IPv6 information\n" "Match address of route\n" "Match entries of prefix-lists\n" "IPv6 prefix-list name\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_flap_prefix_longer_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M longer-prefixes", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\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 (0, isis_hello_multiplier_cmd_vtysh, "isis hello-multiplier <2-100>", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") DEFSH (0, clear_ip_pim_oil_cmd_vtysh, "clear ip pim oil", "Reset functions\n" "IP information\n" "PIM clear commands\n" "Rescan PIM OIL (output interface list)\n") DEFSH (0, no_ip_route_mask_flags2_tag_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n") DEFSH (0, clear_ip_bgp_as_encap_soft_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " encap 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 (0, 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 (0, 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 (0, bandwidth_if_cmd_vtysh, "bandwidth <1-10000000>", "Set bandwidth informational parameter\n" "Bandwidth in kilobits\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M longer-prefixes", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\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 (0, ipv6_route_pref_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255> " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_set_lcommunity_none_cmd_vtysh, "no set large-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 (0, show_ipv6_ospf6_database_self_originated_detail_cmd_vtysh, "show ipv6 ospf6 database self-originated " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Self-originated LSAs\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, show_ip_route_vrf_cmd_vtysh, "show ip route " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, bgp_confederation_peers_cmd_vtysh, "bgp confederation peers ." "<1-4294967295>", "BGP specific commands\n" "AS confederation parameters\n" "Peer ASs in BGP confederation\n" "AS number\n") DEFSH (0, ipv6_nd_prefix_val_rev_rtaddr_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n" "Set Router Address flag\n") DEFSH (0, ipv6_nd_mtu_cmd_vtysh, "ipv6 nd mtu <1-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n" "MTU in bytes\n") DEFSH (0, clear_ip_bgp_instance_peer_rsclient_cmd_vtysh, "clear ip bgp view WORD (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, show_ipv6_mroute_cmd_vtysh, "show ipv6 mroute", "Show running system information\n" "IP information\n" "IPv6 Multicast routing table\n") DEFSH (0, show_bgp_ipv4_safi_route_pathtype_cmd_vtysh, "show bgp ipv4 (unicast|multicast) A.B.C.D (bestpath|multipath)", "Show running system 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 only the bestpath\n" "Display only multipaths\n") DEFSH (0, 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 (0, show_bgp_ipv4_vpn_cmd_vtysh, "show bgp ipv4 vpn", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n") DEFSH (0, show_bgp_view_afi_safi_community3_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (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" "BGP information\n" "BGP view\n" "View name\n" "Address family\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 (0|0|0|0, 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 (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, show_bgp_ipv4_encap_tags_cmd_vtysh, "show bgp ipv4 encap tags", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display BGP tags for prefixes\n") DEFSH (0, 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 (0, ospf_refresh_timer_cmd_vtysh, "refresh timer <10-1800>", "Adjust refresh parameters\n" "Set refresh timer\n" "Timer value in seconds\n") DEFSH (0, exec_timeout_sec_cmd_vtysh, "exec-timeout <0-35791> <0-2147483>", "Set the EXEC timeout\n" "Timeout in minutes\n" "Timeout in seconds\n") DEFSH (0, ipv6_nd_adv_interval_config_option_cmd_vtysh, "ipv6 nd adv-interval-option", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertisement Interval Option\n") DEFSH (0, no_encap_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" "ENCAP Route Distinguisher\n" "BGP tag\n" "tag value\n") DEFSH (0, 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 (0, 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 information\n" "Display connected prefixes to advertise\n" "Display the route\n" "Display the route matches the prefix\n" "Display details of the prefixes\n" ) DEFSH (0, show_interface_vrf_cmd_vtysh, "show interface " "vrf <0-65535>", "Show running system information\n" "Interface status and configuration\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, ipv6_route_flags_pref_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0|0|0|0, show_ipv6_prefix_list_cmd_vtysh, "show ipv6 prefix-list", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n") DEFSH (0, 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 (0, 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 (0, ospf_mpls_te_inter_as_area_cmd_vtysh, "mpls-te inter-as area (A.B.C.D|<0-4294967295>)", "MPLS-TE specific commands\n" "Configure MPLS-TE Inter-AS support\n" "AREA native mode self originate INTER_AS LSA with Type 10 (area flooding scope)\n" "OSPF area ID in IP format\n" "OSPF area ID as decimal value\n") DEFSH (0, no_debug_bgp_nht_cmd_vtysh, "no debug bgp nht", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP nexthop tracking events\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_route_cmd_vtysh, "show bgp ipv4 (unicast|multicast) A.B.C.D", "Show running system 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 (0, 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 (0, ipv6_nd_homeagent_config_flag_cmd_vtysh, "ipv6 nd home-agent-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent configuration flag\n") DEFSH (0|0|0|0, 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 (0, 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 (0, 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 (0, 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 (0, ripng_redistribute_type_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)" " metric <0-16>", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric\n" "Metric value\n") DEFSH (0, ip_ssmpingd_cmd_vtysh, "ip ssmpingd [A.B.C.D]", "IP information\n" "Enable ssmpingd operation\n" "Source address\n") DEFSH (0, debug_ospf6_brouter_router_cmd_vtysh, "debug ospf6 border-routers router-id A.B.C.D", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" "Debug specific border router\n" "Specify border-router's router-id\n" ) DEFSH (0|0|0|0, 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 (0, show_bgp_view_ipv6_cmd_vtysh, "show bgp view WORD ipv6", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n") DEFSH (0, debug_static_cmd_vtysh, "debug static", "Debugging functions (see also 'undebug')\n" "PIM Static Multicast Route activity\n") DEFSH (0, no_set_lcommunity_delete_cmd_vtysh, "no set large-comm-list", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "set BGP large community list (for deletion)\n") DEFSH (0, show_ipv6_access_list_cmd_vtysh, "show ipv6 access-list", "Show running system information\n" "IPv6 information\n" "List IPv6 access lists\n") DEFSH (0, 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 (0, ip_ospf_cost_u32_cmd_vtysh, "ip ospf cost <1-65535>", "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost") DEFSH (0, show_bgp_ipv4_encap_cmd_vtysh, "show bgp ipv4 encap", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n") DEFSH (0, ospf_max_metric_router_lsa_startup_cmd_vtysh, "max-metric router-lsa on-startup <5-86400>", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Automatically advertise stub Router-LSA on startup of OSPF\n" "Time (seconds) to advertise self as stub-router\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, set_lcommunity_delete_cmd_vtysh, "set large-comm-list (<1-99>|<100-500>|WORD) delete", "Set values in destination routing protocol\n" "set BGP large community list (for deletion)\n" "Large Community-list number (standard)\n" "Large Communitly-list number (expanded)\n" "Large Community-list name\n" "Delete matching large communities\n") DEFSH (0, 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 (0, no_debug_isis_rtevents_cmd_vtysh, "no debug isis route-events", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Route related events\n") DEFSH (0, bgp_network_mask_natural_cmd_vtysh, "network A.B.C.D", "Specify a network to announce via BGP\n" "Network number\n") DEFSH (0, ipv6_route_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 (0, redistribute_ospf6_cmd_vtysh, "redistribute ospf6", "Redistribute control\n" "OSPF6 route\n") DEFSH (0, no_tunnel_protection_cmd_vtysh, "no tunnel protection", "Negate a command or set its defaults\n" "NHRP/GRE integration\n" "IPsec protection\n") DEFSH (0, 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 (0, no_match_probability_val_cmd_vtysh, "no match probability <1-99>", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match portion of routes defined by percentage value\n" "Percentage of routes\n") DEFSH (0, 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 (0, 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 (0, show_ip_route_summary_prefix_vrf_all_cmd_vtysh, "show ip route summary prefix " "vrf all", "Show running system information\n" "IP information\n" "IP routing table\n" "Summary of all routes\n" "Prefix routes\n" "Specify the VRF\nAll VRFs\n") DEFSH (0|0|0|0, 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 (0, no_neighbor_nexthop_self_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self {all}", "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" "Apply also to ibgp-learned routes when acting as a route reflector\n") DEFSH (0, 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 (0, 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 (0, no_router_ripng_cmd_vtysh, "no router ripng", "Negate a command or set its defaults\n" "Enable a routing process\n" "Make RIPng instance command\n") DEFSH (0, undebug_igmp_packets_cmd_vtysh, "undebug igmp packets", "Disable debugging functions (see also 'debug')\n" "IGMP protocol activity\n" "IGMP protocol packets\n") DEFSH (0, no_ip_route_mask_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, bgp_maxpaths_ibgp_cmd_vtysh, "maximum-paths ibgp " "<" "1" "-" "1" ">", "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") DEFSH (0, 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 (0|0|0|0|0|0, 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 (0, show_bgp_ipv4_encap_neighbor_advertised_routes_cmd_vtysh, "show bgp ipv4 encap neighbors A.B.C.D advertised-routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\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 (0, show_bgp_ipv4_safi_filter_list_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) filter-list WORD", "Show running system information\n" "BGP information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, no_csnp_interval_l2_arg_cmd_vtysh, "no isis csnp-interval <1-600> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") DEFSH (0, no_ospf6_log_adjacency_changes_cmd_vtysh, "no log-adjacency-changes", "Negate a command or set its defaults\n" "Log changes in adjacency state\n") DEFSH (0, no_link_params_inter_as_cmd_vtysh, "no neighbor", "Negate a command or set its defaults\n" "Remove Neighbor IP address and AS number for Inter-AS TE\n") DEFSH (0, 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 (0, 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 (0, 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 (0, show_ip_rib_cmd_vtysh, "show ip rib A.B.C.D", "Show running system information\n" "IP information\n" "IP unicast routing table\n" "Unicast address\n") DEFSH (0, test_pim_receive_upcall_cmd_vtysh, "test pim receive upcall (nocache|wrongvif|wholepkt) <0-65535> A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test reception of kernel upcall\n" "NOCACHE kernel upcall\n" "WRONGVIF kernel upcall\n" "WHOLEPKT kernel upcall\n" "Input interface vif index\n" "Multicast group address\n" "Multicast source address\n") DEFSH (0, show_ip_route_supernets_vrf_cmd_vtysh, "show ip route supernets-only " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "Show supernet entries only\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv6_encap_cmd_vtysh, "show bgp ipv6 encap", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n") DEFSH (0, router_info_as_cmd_vtysh, "router-info as", "OSPF Router Information specific commands\n" "Enable the Router Information functionality with AS flooding scope\n") DEFSH (0, no_neighbor_password_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "password", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Set a password\n") DEFSH (0|0|0|0, 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 (0, no_ipv6_bgp_distance_source_access_list_cmd_vtysh, "no distance <1-255> X:X::X:X/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 (0, clear_ip_bgp_as_vpnv4_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, if_no_nhrp_nhs_cmd_vtysh, "no " "(ip|ipv6)" " nhrp nhs (A.B.C.D|X:X::X:X|dynamic) nbma (A.B.C.D|FQDN)", "Negate a command or set its defaults\n" "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Nexthop Server configuration\n" "IPv4 protocol address\n" "IPv6 protocol address\n" "Automatic detection of protocol address\n" "IPv4 NBMA address\n" "Fully qualified domain name for NBMA address(es)\n") DEFSH (0, 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 (0, ip_ospf_mtu_ignore_addr_cmd_vtysh, "ip ospf mtu-ignore A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n" "Address of interface") DEFSH (0, 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 (0, show_bgp_ipv6_safi_community4_exact_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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 (0, interface_ip_pim_drprio_cmd_vtysh, "ip pim drpriority <1-4294967295>", "IP information\n" "PIM information\n" "Set the Designated Router Election Priority\n" "Value of the new DR Priority\n") DEFSH (0, ipv6_route_flags_tag_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_set_aspath_prepend_val_cmd_vtysh, "no set as-path prepend ." "<1-4294967295>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") DEFSH (0, ip_route_mask_flags2_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole) " "vrf <0-65535>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, show_ipv6_route_prefix_longer_vrf_all_cmd_vtysh, "show ipv6 route X:X::X:X/M longer-prefixes " "vrf all", "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" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, 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 (0|0|0|0, 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 (0, no_match_peer_local_cmd_vtysh, "no match peer local", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match peer address\n" "Static or Redistributed routes\n") DEFSH (0, no_ip_rip_authentication_mode_type_authlen_cmd_vtysh, "no ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)", "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" "MD5 authentication data length\n" "RFC compatible\n" "Old ripd compatible\n") DEFSH (0, debug_zebra_packet_direct_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") DEFSH (0|0|0|0|0|0, 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 (0, 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 (0, show_ip_pim_hello_cmd_vtysh, "show ip pim hello", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface hello information\n") DEFSH (0, 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 (0, vty_access_class_cmd_vtysh, "access-class WORD", "Filter connections based on an IP access list\n" "IP access list\n") DEFSH (0, 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 (0, 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" "Resend all outbound updates\n") DEFSH (0, show_ip_route_prefix_vrf_all_cmd_vtysh, "show ip route A.B.C.D/M " "vrf all", "Show running system information\n" "IP information\n" "IP routing table\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, 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 (0, no_ipv6_nd_ra_lifetime_cmd_vtysh, "no ipv6 nd ra-lifetime", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n") DEFSH (0, ripng_redistribute_ripng_cmd_vtysh, "redistribute ripng", "Redistribute information from another routing protocol\n" "RIPng route\n") DEFSH (0, no_isis_metric_arg_cmd_vtysh, "no isis metric <0-16777215>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") DEFSH (0, show_bgp_ipv4_safi_lcommunity4_cmd_vtysh, "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, no_bgp_confederation_peers_cmd_vtysh, "no bgp confederation peers ." "<1-4294967295>", "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 (0, show_ipv6_ospf6_database_id_detail_cmd_vtysh, "show ipv6 ospf6 database * A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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 (0, show_ipv6_ospf6_database_router_detail_cmd_vtysh, "show ipv6 ospf6 database * * A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, show_ip_bgp_ipv4_dampening_flap_stats_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) dampening flap-statistics", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") DEFSH (0, show_bgp_ipv6_safi_flap_regexp_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\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 (0, show_bgp_ipv4_safi_community_cmd_vtysh, "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", "Show running system 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, bgp_redistribute_ipv4_metric_rmap_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 (0, 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 (0, 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 (0, debug_isis_spfevents_cmd_vtysh, "debug isis spf-events", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Shortest Path First Events\n") DEFSH (0, 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 (0, no_rip_version_cmd_vtysh, "no version", "Negate a command or set its defaults\n" "Set routing protocol version\n") DEFSH (0, 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 (0, show_ip_ospf_border_routers_cmd_vtysh, "show ip ospf border-routers", "Show running system information\n" "IP information\n" "show all the ABR's and ASBR's\n" "for this area\n") DEFSH (0, 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 information\n" "Interface name(e.g. ep0)\n" "Display connected prefixes to advertise\n" "Display the route bestmatches the address\n" "Display the route\n" "Display details of the prefixes\n" ) DEFSH (0, no_ip_irdp_address_preference_cmd_vtysh, "no ip irdp address A.B.C.D preference <0-2147483647>", "Negate a command or set its defaults\n" "IP information\n" "Alter ICMP Router discovery preference this interface\n" "Removes IRDP non-default preference\n" "Select IRDP address\n" "Old preference level\n") DEFSH (0, show_bgp_view_ipv6_neighbor_damp_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\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 dampened routes received from neighbor\n") DEFSH (0|0|0|0|0, match_interface_cmd_vtysh, "match interface WORD", "Match values from routing table\n" "match first hop interface of route\n" "Interface name\n") DEFSH (0, 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 (0, show_ip_route_summary_cmd_vtysh, "show ip route summary", "Show running system information\n" "IP information\n" "IP routing table\n" "Summary of all routes\n") DEFSH (0, no_ipv6_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 (0, 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 (0, 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 information\n" "Display connected prefixes to advertise\n" "Display the route bestmatches the address\n" "Display the route\n" "Display details of the prefixes\n" ) DEFSH (0, ip_route_tag_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", "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" "Set tag for this route\n" "Tag value\n") DEFSH (0, 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 (0, isis_priority_cmd_vtysh, "isis priority <0-127>", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n") DEFSH (0, show_ipv6_mbgp_cmd_vtysh, "show ipv6 mbgp", "Show running system information\n" "IP information\n" "MBGP information\n") DEFSH (0, show_ip_bgp_rsclient_prefix_cmd_vtysh, "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, 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 (0, show_ip_route_summary_prefix_cmd_vtysh, "show ip route summary prefix", "Show running system information\n" "IP information\n" "IP routing table\n" "Summary of all routes\n" "Prefix routes\n") DEFSH (0, show_bgp_ipv4_safi_rsclient_cmd_vtysh, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, 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 (0, 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 (0|0|0|0, 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 (0, no_ip_route_mask_flags_distance2_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0|0|0|0, 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 (0, no_vty_access_class_cmd_vtysh, "no access-class [WORD]", "Negate a command or set its defaults\n" "Filter connections based on an IP access list\n" "IP access list\n") DEFSH (0, undebug_bgp_nht_cmd_vtysh, "undebug bgp nht", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP next-hop tracking updates\n") DEFSH (0, 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 (0, isis_circuit_type_cmd_vtysh, "isis circuit-type (level-1|level-1-2|level-2-only)", "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") DEFSH (0, no_debug_isis_snp_cmd_vtysh, "no debug isis snp-packets", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS CSNP/PSNP packets\n") DEFSH (0, clear_bgp_ipv6_all_rsclient_cmd_vtysh, "clear bgp ipv6 * rsclient", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, no_spf_interval_l1_cmd_vtysh, "no spf-interval level-1", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n") DEFSH (0, 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 (0, 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 (0, no_ipv6_nd_homeagent_lifetime_val_cmd_vtysh, "no ipv6 nd home-agent-lifetime <0-65520>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") DEFSH (0, no_isis_hello_multiplier_l1_cmd_vtysh, "no isis hello-multiplier level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-1 IIHs\n") DEFSH (0, 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 (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, show_ip_nht_cmd_vtysh, "show ip nht", "Show running system information\n" "IP information\n" "IP nexthop tracking table\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, debug_ospf_nssa_cmd_vtysh, "debug ospf nssa", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF nssa information\n") DEFSH (0, undebug_bgp_filter_cmd_vtysh, "undebug bgp filters", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP filters\n") DEFSH (0, show_bgp_ipv4_safi_community_exact_cmd_vtysh, "show bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system 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 (0, 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 (0, 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 (0, 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 (0, no_ip_route_flags_tag_distance2_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, 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 (0, no_ripng_redistribute_type_routemap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, debug_ospf_nsm_cmd_vtysh, "debug ospf nsm", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Neighbor State Machine\n") DEFSH (0, ipv6_aggregate_address_cmd_vtysh, "aggregate-address X:X::X:X/M", "Configure BGP aggregate entries\n" "Aggregate prefix\n") DEFSH (0, show_ipv6_mbgp_lcommunity_cmd_vtysh, "show ipv6 mbgp large-community (AA:BB:CC)", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, 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 (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0|0|0|0|0, 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 (0, show_bgp_ipv6_prefix_pathtype_cmd_vtysh, "show bgp ipv6 X:X::X:X/M (bestpath|multipath)", "Show running system information\n" "BGP information\n" "Address family\n" "IPv6 prefix /\n" "Display only the bestpath\n" "Display only multipaths\n") DEFSH (0, no_ip_router_isis_cmd_vtysh, "no (ip|ipv6) router isis WORD", "Negate a command or set its defaults\n" "Interface Internet Protocol config commands\n" "IP router interface commands\n" "IS-IS Routing for IP\n" "Routing process tag\n") DEFSH (0, show_ip_pim_local_membership_cmd_vtysh, "show ip pim local-membership", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface local-membership\n") DEFSH (0, show_ip_pim_upstream_rpf_cmd_vtysh, "show ip pim upstream-rpf", "Show running system information\n" "IP information\n" "PIM information\n" "PIM upstream source rpf\n") DEFSH (0, 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 (0, 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 (0, debug_rip_zebra_cmd_vtysh, "debug rip zebra", "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP and ZEBRA communication\n") DEFSH (0, show_ip_rpf_cmd_vtysh, "show ip rpf", "Show running system information\n" "IP information\n" "Display RPF information for multicast source\n") DEFSH (0, no_ospf_redistribute_source_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|isis|bgp|pim|babel|nhrp)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, no_ipv6_route_pref_tag_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") DEFSH (0, 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 (0, 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 (0|0|0|0, 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 (0, no_bgp_graceful_restart_restart_time_cmd_vtysh, "no bgp graceful-restart restart-time", "Negate a command or set its defaults\n" "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\n") DEFSH (0, show_ipv6_route_tag_cmd_vtysh, "show ipv6 route tag <1-4294967295>", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Show only routes with tag\n" "Tag value\n") DEFSH (0, no_ipv6_nd_router_preference_cmd_vtysh, "no ipv6 nd router-preference", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n") DEFSH (0, no_neighbor_advertise_interval_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "advertisement-interval", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Minimum interval between sending BGP routing updates\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, vty_ipv6_access_class_cmd_vtysh, "ipv6 access-class WORD", "IPv6 information\n" "Filter connections based on an IP access list\n" "IPv6 access list\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, 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 (0, 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 (0|0|0|0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, ospf_transmit_delay_cmd_vtysh, "ospf transmit-delay <1-65535>", "OSPF interface commands\n" "Link state transmit delay\n" "Seconds\n") DEFSH (0, show_ipv6_ospf6_database_type_self_originated_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, show_bgp_ipv4_lcommunity_cmd_vtysh, "show bgp ipv4 large-community (AA:BB:CC)", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, no_isis_metric_l2_arg_cmd_vtysh, "no isis metric <0-16777215> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-2 routing\n") DEFSH (0, no_max_lsp_lifetime_l1_cmd_vtysh, "no max-lsp-lifetime level-1", "Negate a command or set its defaults\n" "LSP lifetime for Level 1 only in seconds\n") DEFSH (0, no_ipv6_bgp_distance2_cmd_vtysh, "no distance bgp", "Negate a command or set its defaults\n" "Define an administrative distance\n" "BGP distance\n") DEFSH (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0|0|0|0, 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 (0, undebug_ssmpingd_cmd_vtysh, "undebug ssmpingd", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "ssmpingd activity\n") DEFSH (0, no_spf_interval_l1_arg_cmd_vtysh, "no spf-interval level-1 <1-120>", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, 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 (0, show_bgp_view_ipv6_route_cmd_vtysh, "show bgp view WORD ipv6 X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, no_debug_ospf6_brouter_cmd_vtysh, "no debug ospf6 border-routers", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" ) DEFSH (0, 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 (0, isis_mpls_te_on_cmd_vtysh, "mpls-te on", "MPLS-TE specific commands\n" "Enable MPLS-TE functionality\n") DEFSH (0, 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 (0, no_ospf_cost_u32_cmd_vtysh, "no ospf cost <1-65535>", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interface cost\n" "Cost") DEFSH (0, bgp_redistribute_ipv4_rmap_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0|0|0|0, 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 (0, 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 (0|0, 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 (0, show_ip_pim_rpf_cmd_vtysh, "show ip pim rpf", "Show running system information\n" "IP information\n" "PIM information\n" "PIM cached source rpf information\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, show_bgp_ipv4_safi_community4_cmd_vtysh, "show 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" "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 (0, show_ip_ospf_database_type_id_self_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") 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" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Link State ID (as an IP address)\n" "Self-originated link states\n" "\n") DEFSH (0, no_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 (0, ospf6_distance_ospf6_external_inter_cmd_vtysh, "distance ospf6 external <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "External routes\n" "Distance for external routes\n" "Inter-area routes\n" "Distance for inter-area routes\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv4_vpn_route_cmd_vtysh, "show bgp ipv4 vpn A.B.C.D", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "Network in the BGP routing table to display\n") DEFSH (0, show_ip_igmp_querier_cmd_vtysh, "show ip igmp querier", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP querier information\n") DEFSH (0, 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 (0, show_bgp_ipv6_rsclient_summary_cmd_vtysh, "show bgp ipv6 rsclient summary", "Show running system information\n" "BGP information\n" "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, show_bgp_ipv4_vpn_rd_route_cmd_vtysh, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn A.B.C.D", "Show running system information\n" "BGP information\n" "IP information\n" "Display VPN 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 (0, show_bgp_ipv6_route_pathtype_cmd_vtysh, "show bgp ipv6 X:X::X:X (bestpath|multipath)", "Show running system information\n" "BGP information\n" "Address family\n" "Network in the BGP routing table to display\n" "Display only the bestpath\n" "Display only multipaths\n") DEFSH (0, if_nhrp_flags_cmd_vtysh, "(ip|ipv6)" " nhrp (shortcut|redirect)", "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Allow shortcut establishment\n" "Send redirect notifications\n") DEFSH (0, show_database_arg_cmd_vtysh, "show isis database WORD", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n" "LSP ID\n") DEFSH (0, undebug_pim_trace_cmd_vtysh, "undebug pim trace", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM internal daemon activity\n") DEFSH (0, bgp_log_neighbor_changes_cmd_vtysh, "bgp log-neighbor-changes", "BGP specific commands\n" "Log neighbor up/down and reset reason\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_prefix_longer_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) A.B.C.D/M longer-prefixes", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\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 (0, show_debugging_nhrp_cmd_vtysh, "show debugging nhrp", "Show running system information\n" "Debugging information\n" "NHRP configuration\n") DEFSH (0, ip_route_flags_tag_vrf_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, show_bgp_ipv6_rsclient_route_cmd_vtysh, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "IPv6 Information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, no_spf_interval_cmd_vtysh, "no spf-interval", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n") DEFSH (0, 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 (0, 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 (0, 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 (0|0|0|0|0|0, 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 (0, 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 (0, 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 (0, show_bgp_ipv4_encap_prefix_cmd_vtysh, "show bgp ipv4 encap A.B.C.D/M", "Show running system information\n" "BGP information\n" "IP information\n" "Display ENCAP NLRI specific information\n" "Display information about ENCAP NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, 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 (0, show_bgp_ipv6_neighbor_flap_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", "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 flap statistics of the routes learned from neighbor\n") DEFSH (0, show_ip_bgp_ipv4_lcommunity_all_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) large-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 large-communities\n") DEFSH (0, show_bgp_ipv4_safi_prefix_pathtype_cmd_vtysh, "show bgp ipv4 (unicast|multicast) A.B.C.D/M (bestpath|multipath)", "Show running system 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 only the bestpath\n" "Display only multipaths\n") DEFSH (0, 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 (0, 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 (0, no_ip_route_flags2_vrf_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, isis_priority_l2_cmd_vtysh, "isis priority <0-127> level-2", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-2 routing\n") DEFSH (0, ripng_default_metric_cmd_vtysh, "default-metric <1-16>", "Set a metric of redistribute routes\n" "Default metric\n") DEFSH (0, no_router_info_cmd_vtysh, "no router-info", "Negate a command or set its defaults\n" "Disable the Router Information functionality\n") DEFSH (0|0, 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 (0, no_csnp_interval_arg_cmd_vtysh, "no isis csnp-interval <1-600>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") DEFSH (0|0|0|0, 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 (0, show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\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 advertised routes to neighbor\n" "Display the received routes from neighbor\n") DEFSH (0, pce_neighbor_cmd_vtysh, "pce neighbor as <0-65535>", "PCE Router Information specific commands\n" "Configure PCE neighbor domain AS number\n" "AS number of PCE neighbors\n" "AS number in decimal <0-65535>\n") DEFSH (0, 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 (0, 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 (0, no_ipv6_nd_ra_lifetime_val_cmd_vtysh, "no ipv6 nd ra-lifetime <0-9000>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" "Router lifetime in seconds (0 stands for a non-default gw)\n") DEFSH (0, isis_hello_interval_cmd_vtysh, "isis hello-interval <1-600>", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 seconds, interval depends on multiplier\n") DEFSH (0, 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 (0, ripng_redistribute_type_metric_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)" " metric <0-16> route-map WORD", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, clear_bgp_external_in_cmd_vtysh, "clear bgp external in", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, show_bgp_ipv6_safi_damp_flap_statistics_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") DEFSH (0, no_ipv6_ospf6_network_cmd_vtysh, "no ipv6 ospf6 network", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Network Type\n" "Default to whatever interface type system specifies" ) DEFSH (0, show_ip_forwarding_cmd_vtysh, "show ip forwarding", "Show running system information\n" "IP information\n" "IP forwarding status\n") DEFSH (0, ip_mroute_cmd_vtysh, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n") DEFSH (0, ip_route_mask_tag_distance_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, clear_bgp_as_soft_in_cmd_vtysh, "clear bgp " "<1-4294967295>" " soft in", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, show_bgp_view_afi_safi_community4_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (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" "BGP information\n" "BGP view\n" "View name\n" "Address family\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 (0, 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 (0, ipv6_route_flags_tag_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") DEFSH (0, no_ipv6_nd_reachable_time_val_cmd_vtysh, "no ipv6 nd reachable-time <1-3600000>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") DEFSH (0, 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 (0, show_ip_bgp_cmd_vtysh, "show ip bgp", "Show running system information\n" "IP information\n" "BGP information\n") DEFSH (0, clear_bgp_external_soft_cmd_vtysh, "clear bgp external soft", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig inbound and outbound updates\n") DEFSH (0, 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 (0, no_ip_route_flags2_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0|0|0|0, 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 (0, 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 (0, show_bgp_ipv4_safi_flap_prefix_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_ipv6_ospf6_database_type_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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 (0, show_bgp_lcommunity2_cmd_vtysh, "show bgp large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, link_params_use_bw_cmd_vtysh, "use-bw BANDWIDTH", "Unidirectional Utilised Bandwidth\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, 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 (0, no_psnp_interval_l1_cmd_vtysh, "no isis psnp-interval level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "Specify interval for level-1 PSNPs\n") DEFSH (0, 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 (0, no_debug_pim_events_cmd_vtysh, "no debug pim events", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol events\n") DEFSH (0, 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 (0, no_bgp_redistribute_ipv6_rmap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 (0, show_ipv6_ospf6_database_type_adv_router_linkstate_id_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, clear_ip_bgp_as_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0|0|0|0, 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 (0, show_bgp_ipv4_community_cmd_vtysh, "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "IP 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 (0, no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" " route-map WORD metric <0-4294967295>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 information\n" "Interface name(e.g. ep0)\n" "Display connected prefixes to advertise\n" ) DEFSH (0, bgp_bestpath_aspath_multipath_relax_cmd_vtysh, "bgp bestpath as-path multipath-relax", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Allow load sharing across routes that have different AS paths (but same length)\n") DEFSH (0, 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 (0, show_bgp_ipv4_community_exact_cmd_vtysh, "show bgp ipv4 community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "IP 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 (0, 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 (0, rip_version_cmd_vtysh, "version <1-2>", "Set routing protocol version\n" "version\n") DEFSH (0, area_filter_list_cmd_vtysh, "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") DEFSH (0, show_ipv6_route_tag_vrf_cmd_vtysh, "show ipv6 route tag <1-4294967295>" "vrf <0-65535>", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Show only routes with tag\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_ipv6_nd_prefix_cmd_vtysh, "no ipv6 nd prefix IPV6PREFIX", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n") DEFSH (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, no_linkdetect_cmd_vtysh, "no link-detect", "Negate a command or set its defaults\n" "Disable link detection on interface\n") DEFSH (0, 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 (0, show_ipv6_ospf6_database_adv_router_detail_cmd_vtysh, "show ipv6 ospf6 database adv-router A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, set_aspath_exclude_cmd_vtysh, "set as-path exclude ." "<1-4294967295>", "Set values in destination routing protocol\n" "Transform BGP AS-path attribute\n" "Exclude from the as-path\n" "AS number\n") DEFSH (0, show_ip_route_vrf_all_cmd_vtysh, "show ip route " "vrf all", "Show running system information\n" "IP information\n" "IP routing table\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, no_ospf_distribute_list_out_cmd_vtysh, "no distribute-list WORD out " "(kernel|connected|static|rip|isis|bgp|pim|babel|nhrp)", "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 (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, show_bgp_route_pathtype_cmd_vtysh, "show bgp X:X::X:X (bestpath|multipath)", "Show running system information\n" "BGP information\n" "Network in the BGP routing table to display\n" "Display only the bestpath\n" "Display only multipaths\n") DEFSH (0, 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 (0, show_ip_pim_secondary_cmd_vtysh, "show ip pim secondary", "Show running system information\n" "IP information\n" "PIM information\n" "PIM neighbor addresses\n") DEFSH (0, clear_ip_bgp_as_ipv4_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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" "Resend all outbound updates\n") DEFSH (0, bgp_config_type_cmd_vtysh, "bgp config-type (cisco|zebra)", "BGP information\n" "Configuration type\n" "cisco\n" "zebra\n") DEFSH (0|0|0|0|0, 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 (0, 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 (0, 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 (0, 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 (0, debug_pim_zebra_cmd_vtysh, "debug pim zebra", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "ZEBRA protocol activity\n") DEFSH (0, show_ip_rpf_addr_cmd_vtysh, "show ip rpf A.B.C.D", "Show running system information\n" "IP information\n" "Display RPF information for multicast source\n" "IP multicast source address (e.g. 10.0.0.0)\n") DEFSH (0, ipv6_ospf6_network_cmd_vtysh, "ipv6 ospf6 network (broadcast|point-to-point)", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Network Type\n" "Specify OSPFv6 broadcast network\n" "Specify OSPF6 point-to-point network\n" ) DEFSH (0, show_bgp_ipv4_safi_rsclient_summary_cmd_vtysh, "show bgp ipv4 (unicast|multicast) rsclient summary", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0|0|0|0, 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 (0, debug_isis_lsp_gen_cmd_vtysh, "debug isis lsp-gen", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS generation of own LSPs\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, ipv6_route_ifname_pref_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255> " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, set_attached_bit_cmd_vtysh, "set-attached-bit", "Set attached bit to identify as L1/L2 router for inter-area traffic\n" "Set attached bit\n") DEFSH (0|0|0|0, show_ip_prefix_list_cmd_vtysh, "show ip prefix-list", "Show running system information\n" "IP information\n" "Build a prefix list\n") DEFSH (0, 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 (0, 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 (0|0|0|0, 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 (0, clear_ip_bgp_as_ipv4_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, show_bgp_ipv6_rsclient_cmd_vtysh, "show bgp ipv6 rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Address Family\n" "Information about Route Server Client\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv4_encap_rd_cmd_vtysh, "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n") DEFSH (0, 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 (0, show_bgp_ipv6_vpn_cmd_vtysh, "show bgp ipv6 vpn", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n") DEFSH (0, clear_ip_igmp_interfaces_cmd_vtysh, "clear ip igmp interfaces", "Reset functions\n" "IP information\n" "IGMP clear commands\n" "Reset IGMP interfaces\n") DEFSH (0, ripng_offset_list_cmd_vtysh, "offset-list WORD (in|out) <0-16>", "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0|0|0|0|0|0, 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 (0, no_ospf6_timers_throttle_spf_cmd_vtysh, "no timers throttle spf", "Negate a command or set its defaults\n" "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF6 SPF timers\n") DEFSH (0, no_tunnel_source_cmd_vtysh, "no tunnel source", "NHRP/GRE integration\n" "Tunnel device binding tracking\n" "Interface name\n") DEFSH (0, 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 (0, 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 (0, clear_bgp_ipv6_as_soft_in_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " soft in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, show_bgp_ipv6_safi_damp_flap_prefix_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_ospf_area_nssa_no_summary_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) nssa 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 nssa\n" "Do not inject inter-area routes into nssa\n") DEFSH (0, 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 (0, show_ip_bgp_ipv4_prefix_pathtype_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M (bestpath|multipath)", "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 only the bestpath\n" "Display only multipaths\n") DEFSH (0, 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 (0, no_ip_route_mask_flags2_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole) " "vrf <0-65535>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, ipv6_route_ifname_tag_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>", "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" "Set tag for this route\n" "Tag value\n") DEFSH (0, nhrp_event_socket_cmd_vtysh, "nhrp event socket SOCKET", "Next Hop Resolution Protocol functions\n" "Event Manager commands\n" "Event Manager unix socket path\n" "Unix path for the socket\n") DEFSH (0, show_ip_mroute_cmd_vtysh, "show ip mroute", "Show running system information\n" "IP information\n" "IP multicast routing table\n") DEFSH (0, 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 (0, clear_ip_bgp_peer_rsclient_cmd_vtysh, "clear ip bgp (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, 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 (0, 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 (0, no_ripng_redistribute_type_metric_routemap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)" " metric <0-16> route-map WORD", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_bgp_ipv4_encap_route_cmd_vtysh, "show bgp ipv4 encap A.B.C.D", "Show running system information\n" "BGP information\n" "IP information\n" "Display ENCAP NLRI specific information\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 (0, 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 (0, 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 (0, no_set_weight_val_cmd_vtysh, "no set weight <0-4294967295>", "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 (0, show_bgp_view_ipv4_safi_rsclient_prefix_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_bgp_rsclient_route_cmd_vtysh, "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, clear_bgp_ipv6_all_in_cmd_vtysh, "clear bgp ipv6 * in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, show_bgp_ipv6_safi_damp_flap_route_map_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening flap-statistics route-map WORD", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, clear_ip_bgp_as_ipv4_soft_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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 inbound and outbound updates\n") DEFSH (0, show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd_vtysh, "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\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 (0, no_ip_route_flags_vrf_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, show_ip_pim_assert_cmd_vtysh, "show ip pim assert", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface assert\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, show_bgp_ipv6_safi_neighbor_advertised_route_cmd_vtysh, "show bgp ipv6 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Address Family modifier\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 (0, 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 (0, no_match_ipv6_address_prefix_list_cmd_vtysh, "no match ipv6 address prefix-list", "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") DEFSH (0, no_ip_route_mask_flags_distance_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, if_no_nhrp_mtu_cmd_vtysh, "no ip nhrp mtu [(<576-1500>|opennhrp)]", "Negate a command or set its defaults\n" "IP information\n" "Next Hop Resolution Protocol functions\n" "Configure NHRP advertised MTU\n" "MTU value\n" "Advertise bound interface MTU similar to OpenNHRP") DEFSH (0, match_lcommunity_cmd_vtysh, "match large-community (<1-99>|<100-500>|WORD)", "Match values from routing table\n" "Match BGP large community list\n" "Large Community-list number (standard)\n" "Large Community-list number (expanded)\n" "Large Community-list name\n") DEFSH (0, 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 (0, show_ipv6_route_addr_vrf_cmd_vtysh, "show ipv6 route X:X::X:X " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "IPv6 Address\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_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 (0, link_params_max_rsv_bw_cmd_vtysh, "max-rsv-bw BANDWIDTH", "Maximum bandwidth that may be reserved\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, show_bgp_prefix_cmd_vtysh, "show bgp X:X::X:X/M", "Show running system information\n" "BGP information\n" "IPv6 prefix /\n") DEFSH (0, ip_lcommunity_list_name_expanded_cmd_vtysh, "ip large-community-list expanded WORD (deny|permit) .LINE", "IP information\n" "Add a large community list entry\n" "Specify expanded large-community-list\n" "Large Community list name\n" "Specify large community to reject\n" "Specify large community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, set_lcommunity_none_cmd_vtysh, "set large-community none", "Set values in destination routing protocol\n" "BGP large community attribute\n" "No large community attribute\n") DEFSH (0, 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 (0, 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 (0, 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 (0|0|0|0|0|0, rmap_description_cmd_vtysh, "description .LINE", "Route-map comment\n" "Comment describing this route-map rule\n") DEFSH (0, show_bgp_ipv4_lcommunity_list_cmd_vtysh, "show bgp ipv4 large-community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") DEFSH (0, show_bgp_view_ipv6_rsclient_cmd_vtysh, "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "BGP view name\n" "Address Family\n" "Information about Route Server Client\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n") DEFSH (0, 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 (0, show_bgp_lcommunity_list_cmd_vtysh, "show bgp large-community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") DEFSH (0, 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 information\n" "Interface name(e.g. ep0)\n" "Display connected prefixes to advertise\n" "Display the route\n" "Display the route matches the prefix\n" "Display details of the prefixes\n" ) DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 /, e.g., 3ffe::/16\n") DEFSH (0, show_bgp_memory_cmd_vtysh, "show bgp memory", "Show running system information\n" "BGP information\n" "Global BGP memory statistics\n") DEFSH (0, show_bgp_ipv4_prefix_list_cmd_vtysh, "show bgp ipv4 prefix-list WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, rip_neighbor_cmd_vtysh, "neighbor A.B.C.D", "Specify a neighbor router\n" "Neighbor address\n") DEFSH (0, 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 (0, ip_route_mask_tag_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", "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" "Set tag for this route\n" "Tag value\n") DEFSH (0, show_bgp_afi_safi_view_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (encap|mulicast|unicast|vpn)", "Show running system information\n" "BGP information\n" "BGP view\n" "BGP view name\n" "Address Family\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" ) DEFSH (0, show_bgp_ipv6_safi_route_cmd_vtysh, "show bgp ipv6 (unicast|multicast) X:X::X:X", "Show running system 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 (0, 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 (0, 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 (0, ospf_log_adjacency_changes_detail_cmd_vtysh, "log-adjacency-changes detail", "Log changes in adjacency state\n" "Log all state changes\n") DEFSH (0, rip_redistribute_type_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, no_spf_interval_arg_cmd_vtysh, "no spf-interval <1-120>", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, show_bgp_ipv6_safi_dampened_paths_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampened-paths", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display paths suppressed due to dampening\n") DEFSH (0, 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 (0, 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 (0|0|0|0, 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 (0, 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 (0, no_psnp_interval_l2_arg_cmd_vtysh, "no isis psnp-interval <1-120> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-2 PSNPs\n") DEFSH (0, show_ip_igmp_sources_retransmissions_cmd_vtysh, "show ip igmp sources retransmissions", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP sources information\n" "IGMP source retransmissions\n") DEFSH (0, no_debug_igmp_packets_cmd_vtysh, "no debug igmp packets", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP protocol packets\n") DEFSH (0, ipv6_bgp_distance_source_access_list_cmd_vtysh, "distance <1-255> X:X::X:X/M WORD", "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n" "Access list name\n") DEFSH (0, set_weight_cmd_vtysh, "set weight <0-4294967295>", "Set values in destination routing protocol\n" "BGP weight for routing table\n" "Weight value\n") DEFSH (0, show_bgp_ipv6_safi_flap_prefix_longer_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M longer-prefixes", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\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 (0, ipv6_forwarding_cmd_vtysh, "ipv6 forwarding", "IPv6 information\n" "Turn on IPv6 forwarding") DEFSH (0, 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 (0, ospf_area_nssa_translate_no_summary_cmd_vtysh, "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") DEFSH (0, show_bgp_ipv6_safi_lcommunity2_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0|0|0|0, 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 (0, show_ipv6_ospf6_database_type_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, show_bgp_ipv4_safi_flap_address_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, debug_rip_packet_cmd_vtysh, "debug rip packet", "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP packet\n") DEFSH (0, no_ip_forwarding_cmd_vtysh, "no ip forwarding", "Negate a command or set its defaults\n" "IP information\n" "Turn off IP forwarding") DEFSH (0, show_ipv6_ospf6_database_id_cmd_vtysh, "show ipv6 ospf6 database * A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, 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 (0, 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 (0, set_overload_bit_cmd_vtysh, "set-overload-bit", "Set overload bit to avoid any transit traffic\n" "Set overload bit\n") DEFSH (0, ospf_log_adjacency_changes_cmd_vtysh, "log-adjacency-changes", "Log changes in adjacency state\n") DEFSH (0, show_bgp_ipv6_encap_rd_tags_cmd_vtysh, "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn tags", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "Display BGP tags for prefixes\n") DEFSH (0, 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 (0, show_bgp_view_rsclient_route_cmd_vtysh, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, show_ip_route_prefix_longer_vrf_cmd_vtysh, "show ip route A.B.C.D/M longer-prefixes " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, clear_ipv6_ospf6_interface_cmd_vtysh, "clear ipv6 ospf6 interface [IFNAME]", "Reset functions\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface information\n" "Interface name(e.g. ep0)\n" ) DEFSH (0, 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 (0, 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 (0, ip_lcommunity_list_standard_cmd_vtysh, "ip large-community-list <1-99> (deny|permit) .AA:BB:CC", "IP information\n" "Add a large community list entry\n" "Large Community list number (standard)\n" "Specify large community to reject\n" "Specify large community to accept\n" "large community in 'aa:bb:cc' format\n") DEFSH (0, show_ipv6_ospf6_database_router_cmd_vtysh, "show ipv6 ospf6 database * * A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Any Link state Type\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" ) DEFSH (0, 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 (0, show_isis_topology_cmd_vtysh, "show isis topology", "Show running system information\n" "IS-IS information\n" "IS-IS paths to Intermediate Systems\n") DEFSH (0, show_ip_bgp_lcommunity4_cmd_vtysh, "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, isis_passive_cmd_vtysh, "isis passive", "IS-IS commands\n" "Configure the passive mode for interface\n") DEFSH (0, show_bgp_ipv4_lcommunity4_cmd_vtysh, "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0|0|0|0, 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 (0, fpm_remote_ip_cmd_vtysh, "fpm connection ip A.B.C.D port <1-65535>", "fpm connection remote ip and port\n" "Remote fpm server ip A.B.C.D\n" "Enter ip ") DEFSH (0, isis_hello_padding_cmd_vtysh, "isis hello padding", "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, no_csnp_interval_cmd_vtysh, "no isis csnp-interval", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n") DEFSH (0, show_ip_route_summary_vrf_all_cmd_vtysh, "show ip route summary " "vrf all", "Show running system information\n" "IP information\n" "IP routing table\n" "Summary of all routes\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, show_ip_ospf_neighbor_int_cmd_vtysh, "show ip ospf neighbor IFNAME", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n" "Interface name\n") DEFSH (0, no_ipv6_route_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 (0, 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 (0, no_neighbor_route_map_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out|import|export)", "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" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") DEFSH (0, ip_route_mask_flags2_tag_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") DEFSH (0|0|0|0, 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 (0, 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 (0, no_debug_bgp_as4_cmd_vtysh, "no debug bgp as4", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP AS4 actions\n") DEFSH (0, ip_ospf_dead_interval_minimal_addr_cmd_vtysh, "ip ospf dead-interval minimal hello-multiplier <1-10> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Minimal 1s dead-interval with fast sub-second hellos\n" "Hello multiplier factor\n" "Number of Hellos to send each second\n" "Address of interface\n") DEFSH (0|0|0, match_metric_cmd_vtysh, "match metric <0-4294967295>", "Match values from routing table\n" "Match metric of route\n" "Metric value\n") DEFSH (0, clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " in prefix-filter", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_ip_ospf_mtu_ignore_addr_cmd_vtysh, "no ip ospf mtu-ignore A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n" "Address of interface") DEFSH (0, no_area_lsp_mtu_arg_cmd_vtysh, "no lsp-mtu <128-4352>", "Negate a command or set its defaults\n" "Configure the maximum size of generated LSPs\n" "Maximum size of generated LSPs\n") DEFSH (0, bgp_multiple_instance_cmd_vtysh, "bgp multiple-instance", "BGP information\n" "Enable bgp multiple instance\n") DEFSH (0, clear_ip_bgp_peer_encap_in_cmd_vtysh, "clear ip bgp A.B.C.D encap 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 (0, net_cmd_vtysh, "net WORD", "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") DEFSH (0, shutdown_if_cmd_vtysh, "shutdown", "Shutdown the selected interface\n") DEFSH (0|0|0|0|0, 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 (0, 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 (0, show_bgp_ipv6_safi_rsclient_cmd_vtysh, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, 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 (0, no_isis_hello_interval_l1_arg_cmd_vtysh, "no isis hello-interval <1-600> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") DEFSH (0, 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 (0, show_bgp_ipv6_safi_flap_prefix_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, 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 (0, no_area_lsp_mtu_cmd_vtysh, "no lsp-mtu", "Negate a command or set its defaults\n" "Configure the maximum size of generated LSPs\n") DEFSH (0, no_ripng_redistribute_type_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, no_ip_multicast_routing_cmd_vtysh, "no" " " "ip multicast-routing", "Negate a command or set its defaults\n" "IP information\n" "Global IP configuration subcommands\n" "Enable IP multicast forwarding\n") DEFSH (0, show_bgp_ipv6_safi_lcommunity4_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, interface_ip_mroute_source_cmd_vtysh, "ip mroute INTERFACE A.B.C.D A.B.C.D", "IP information\n" "Add multicast route\n" "Outgoing interface name\n" "Group address\n" "Source address\n") DEFSH (0, 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 (0, show_bgp_view_ipv6_prefix_cmd_vtysh, "show bgp view WORD ipv6 X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "IPv6 prefix /\n") DEFSH (0, debug_bgp_update_cmd_vtysh, "debug bgp updates", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP updates\n") DEFSH (0, show_bgp_ipv6_vpn_summary_cmd_vtysh, "show bgp ipv6 vpn summary", "Show running system information\n" "BGP information\n" "IPv6\n" "Display VPN NLRI specific information\n" "Summary of BGP neighbor status\n") DEFSH (0, no_ospf_distance_ospf_cmd_vtysh, "no distance ospf {intra-area|inter-area|external}", "Negate a command or set its defaults\n" "Define an administrative distance\n" "OSPF Administrative distance\n" "OSPF Distance\n" "Intra-area routes\n" "Inter-area routes\n" "External routes\n") DEFSH (0, 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 (0, 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 (0, bgp_maxpaths_cmd_vtysh, "maximum-paths " "<" "1" "-" "1" ">", "Forward packets over multiple paths\n" "Number of paths\n") DEFSH (0|0|0|0|0|0, 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 (0, set_lcommunity_cmd_vtysh, "set large-community .AA:BB:CC", "Set values in destination routing protocol\n" "BGP large community attribute\n" "Large Community number in aa:bb:cc format or additive\n") DEFSH (0, isis_mpls_te_router_addr_cmd_vtysh, "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") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, 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 (0|0|0|0, 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 (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, show_ipv6_mbgp_lcommunity_list_cmd_vtysh, "show ipv6 mbgp large-community-list WORD", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the large-community-list\n" "large-community-list name\n") DEFSH (0, undebug_bgp_zebra_cmd_vtysh, "undebug bgp zebra", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP Zebra messages\n") DEFSH (0, 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 (0, no_ip_route_mask_flags_tag_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n") DEFSH (0, interface_no_ip_igmp_query_interval_cmd_vtysh, "no" " " "ip igmp query-interval", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n" "IGMP host query interval\n") DEFSH (0, show_bgp_ipv4_safi_community3_cmd_vtysh, "show 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" "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 (0, show_bgp_ipv6_safi_route_pathtype_cmd_vtysh, "show bgp ipv6 (unicast|multicast) X:X::X:X (bestpath|multipath)", "Show running system 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" "Display only the bestpath\n" "Display only multipaths\n") DEFSH (0, 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 (0, spf_interval_l1_cmd_vtysh, "spf-interval level-1 <1-120>", "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, 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 (0, no_ipv6_nd_router_preference_val_cmd_vtysh, "no ipv6 nd router-preference (high|medium|low)", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n" "High default router preference\n" "Low default router preference\n" "Medium default router preference (default)\n") DEFSH (0, dump_bgp_all_cmd_vtysh, "dump bgp (all|all-et|updates|updates-et|routes-mrt) PATH [INTERVAL]", "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\nDump all BGP packets (Extended Tiemstamp Header)\n" "Dump BGP updates only\nDump BGP updates only (Extended Tiemstamp Header)\n" "Dump whole BGP routing table\n" "Output filename\n" "Interval of output\n") DEFSH (0, show_ip_ospf_mpls_te_link_cmd_vtysh, "show ip ospf mpls-te interface [INTERFACE]", "Show running system information\n" "IP information\n" "OSPF information\n" "MPLS-TE information\n" "Interface information\n" "Interface name\n") DEFSH (0, ospf_compatible_rfc1583_cmd_vtysh, "compatible rfc1583", "OSPF compatibility list\n" "compatible with RFC 1583\n") DEFSH (0, set_src_cmd_vtysh, "set src A.B.C.D", "Set values in destination routing protocol\n" "src address for route\n" "src address\n") DEFSH (0, show_bgp_view_afi_safi_lcommunity2_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, linkdetect_cmd_vtysh, "link-detect [default]", "Enable link detection on interface\n" "Leave link-detect to the default\n") DEFSH (0, 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 (0, no_debug_isis_spfevents_cmd_vtysh, "no debug isis spf-events", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Shortest Path First Events\n") DEFSH (0, clear_ip_bgp_all_encap_soft_cmd_vtysh, "clear ip bgp * encap 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, undebug_igmp_trace_cmd_vtysh, "undebug igmp trace", "Disable debugging functions (see also 'debug')\n" "IGMP protocol activity\n" "IGMP internal daemon activity\n") DEFSH (0, ospf6_distance_ospf6_intra_external_inter_cmd_vtysh, "distance ospf6 intra-area <1-255> external <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF6 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 (0, ipv6_nd_ra_interval_msec_cmd_vtysh, "ipv6 nd ra-interval msec <70-1800000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") DEFSH (0, ipv6_nd_prefix_noval_noauto_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for autoconfiguration\n") DEFSH (0, show_bgp_ipv6_vpn_route_cmd_vtysh, "show bgp ipv6 vpn X:X::X:X", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "Network in the BGP routing table to display\n") DEFSH (0|0|0|0, 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 (0, clear_ip_bgp_as_soft_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, ripng_passive_interface_cmd_vtysh, "passive-interface IFNAME", "Suppress routing updates on an interface\n" "Interface name\n") DEFSH (0, 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 (0, interface_ip_igmp_query_interval_cmd_vtysh, "ip igmp query-interval" " <1-1800>", "IP information\n" "Enable IGMP operation\n" "IGMP host query interval\n" "Query interval in seconds\n") DEFSH (0, no_ipv6_route_pref_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255> " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, clear_bgp_ipv6_as_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n") DEFSH (0|0|0|0, 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 (0|0|0|0, 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 (0, ospf6_distance_ospf6_intra_cmd_vtysh, "distance ospf6 intra-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n") DEFSH (0, show_bgp_instance_ipv6_neighbors_cmd_vtysh, "show bgp view WORD ipv6 neighbors", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, if_nhrp_map_cmd_vtysh, "(ip|ipv6)" " nhrp map (A.B.C.D|X:X::X:X) (A.B.C.D|local)", "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Nexthop Server configuration\n" "IPv4 protocol address\n" "IPv6 protocol address\n" "IPv4 NBMA address\n" "Handle protocol address locally\n") DEFSH (0, clear_bgp_all_soft_in_cmd_vtysh, "clear bgp * soft in", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, show_bgp_view_ipv6_neighbor_flap_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\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 dampened routes received from neighbor\n") DEFSH (0, 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 (0, no_ip_lcommunity_list_standard_all_cmd_vtysh, "no ip large-community-list <1-99>", "Negate a command or set its defaults\n" "IP information\n" "Add a large community list entry\n" "Large Community list number (standard)\n") DEFSH (0, ospf6_distance_ospf6_inter_cmd_vtysh, "distance ospf6 inter-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n") DEFSH (0, ip_route_distance_vrf_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255> " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_ipv6_mbgp_lcommunity3_cmd_vtysh, "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, clear_ip_bgp_prefix_cmd_vtysh, "clear ip bgp prefix A.B.C.D/M", "Reset functions\n" "IP information\n" "BGP information\n" "Clear bestpath and re-advertise\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_ospf_log_adjacency_changes_detail_cmd_vtysh, "no log-adjacency-changes detail", "Negate a command or set its defaults\n" "Log changes in adjacency state\n" "Log all state changes\n") DEFSH (0, 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 (0, no_ip_protocol_cmd_vtysh, "no ip protocol PROTO", "Negate a command or set its defaults\n" "Remove route map from PROTO\n" "Protocol name\n") DEFSH (0, max_lsp_lifetime_l1_cmd_vtysh, "max-lsp-lifetime level-1 <350-65535>", "Maximum LSP lifetime for Level 1 only\n" "LSP lifetime for Level 1 only in seconds\n") DEFSH (0, 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 (0, 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 (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, neighbor_nexthop_local_unchanged_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "nexthop-local unchanged", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Configure treatment of outgoing link-local nexthop attribute\n" "Leave link-local nexthop unchanged for this peer\n") DEFSH (0, show_bgp_cmd_vtysh, "show bgp", "Show running system information\n" "BGP information\n") DEFSH (0|0|0|0|0|0, rmap_onmatch_goto_cmd_vtysh, "on-match goto <1-65535>", "Exit policy on matches\n" "Goto Clause number\n" "Number\n") DEFSH (0, no_ipv6_ospf6_cost_cmd_vtysh, "no ipv6 ospf6 cost", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Calculate interface cost from bandwidth\n" ) DEFSH (0, 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 (0, no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" " metric <0-4294967295> route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, no_rip_timers_val_cmd_vtysh, "no timers basic <0-65535> <0-65535> <0-65535>", "Negate a command or set its defaults\n" "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 (0, 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 (0, ip_lcommunity_list_standard2_cmd_vtysh, "ip large-community-list <1-99> (deny|permit)", "IP information\n" "Add a large community list entry\n" "Large Community list number (standard)\n" "Specify large community to reject\n" "Specify large community to accept\n") DEFSH (0, 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 (0, 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 (0, show_isis_topology_l1_cmd_vtysh, "show isis topology level-1", "Show running system information\n" "IS-IS information\n" "IS-IS paths to Intermediate Systems\n" "Paths to all level-1 routers in the area\n") DEFSH (0, 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 (0, no_set_aspath_exclude_val_cmd_vtysh, "no set as-path exclude ." "<1-4294967295>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Exclude from the as-path\n" "AS number\n") DEFSH (0, no_link_params_delay_var_cmd_vtysh, "no delay-variation", "Negate a command or set its defaults\n" "Disable Unidirectional Delay Variation on this interface\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv4_safi_lcommunity_cmd_vtysh, "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, psnp_interval_l1_cmd_vtysh, "isis psnp-interval <1-120> level-1", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-1 PSNPs\n") DEFSH (0, 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 (0, no_bgp_rr_allow_outbound_policy_cmd_vtysh, "no bgp route-reflector allow-outbound-policy", "Negate a command or set its defaults\n" "BGP specific commands\n" "Allow modifications made by out route-map\n" "on ibgp neighbors\n") DEFSH (0, ip_route_flags_tag_distance2_vrf_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, link_params_ava_bw_cmd_vtysh, "ava-bw BANDWIDTH", "Unidirectional Available Bandwidth\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, 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 (0, set_community_none_cmd_vtysh, "set community none", "Set values in destination routing protocol\n" "BGP community attribute\n" "No community attribute\n") DEFSH (0, 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 (0, 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 (0|0|0|0, 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 (0, 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 (0, no_ip_route_flags_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, show_ip_bgp_view_neighbor_received_routes_cmd_vtysh, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", "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" "Display the received routes from neighbor\n") DEFSH (0, ipv6_route_flags_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, clear_bgp_ipv6_instance_peer_rsclient_cmd_vtysh, "clear bgp ipv6 view WORD (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "BGP information\n" "Address family\n" "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, 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 (0, 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 (0, clear_ip_bgp_as_encap_soft_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " encap 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 (0, ip_route_mask_flags2_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole)", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0|0|0|0, 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 (0, 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 (0, debug_bgp_allow_martians_cmd_vtysh, "debug bgp allow-martians", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP allow martian next hops\n") DEFSH (0, no_ospf_area_nssa_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) nssa", "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 nssa\n") DEFSH (0, 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 (0, ospf_mpls_te_on_cmd_vtysh, "mpls-te on", "MPLS-TE specific commands\n" "Enable the MPLS-TE functionality\n") DEFSH (0, ip_address_label_cmd_vtysh, "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") DEFSH (0, show_ipv6_route_vrf_cmd_vtysh, "show ipv6 route " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, no_ripng_timers_val_cmd_vtysh, "no timers basic <0-65535> <0-65535> <0-65535>", "Negate a command or set its defaults\n" "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 (0, no_ip_route_mask_tag_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", "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" "Tag of this route\n" "Tag value\n") DEFSH (0, ip_route_mask_distance_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255> " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, no_ipv6_nd_mtu_val_cmd_vtysh, "no ipv6 nd mtu <1-65535>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n" "MTU in bytes\n") DEFSH (0, bgp_timers_cmd_vtysh, "timers bgp <0-65535> <0-65535>", "Adjust routing timers\n" "BGP timers\n" "Keepalive interval\n" "Holdtime\n") DEFSH (0, ip_route_vrf_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_bgp_ipv4_community_list_cmd_vtysh, "show bgp ipv4 community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") DEFSH (0, show_bgp_ipv6_cmd_vtysh, "show bgp ipv6", "Show running system information\n" "BGP information\n" "Address family\n") DEFSH (0, no_ip_mroute_vrf_cmd_vtysh, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) " "vrf <0-65535>", "Negate a command or set its defaults\n" "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, ipv6_route_ifname_flags_tag_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") DEFSH (0, show_ipv6_bgp_lcommunity2_cmd_vtysh, "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, ipv6_route_flags_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, no_router_id_vrf_cmd_vtysh, "no router-id " "vrf <0-65535>", "Negate a command or set its defaults\n" "Remove the manually configured router-id\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, undebug_bgp_allow_martians_cmd_vtysh, "undebug bgp allow-martians", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP allow martian next hops\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, 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 (0, 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 (0, no_link_params_use_bw_cmd_vtysh, "no use-bw", "Negate a command or set its defaults\n" "Disable Unidirectional Utilised Bandwidth on this interface\n") DEFSH (0, 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" "View name\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_ip_bgp_lcommunity_all_cmd_vtysh, "show ip bgp large-community", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the large-communities\n") DEFSH (0, show_ip_bgp_rsclient_summary_cmd_vtysh, "show ip bgp rsclient summary", "Show running system information\n" "IP information\n" "BGP information\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, 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 (0, 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 (0, show_ip_ospf_router_info_pce_cmd_vtysh, "show ip ospf router-info pce", "Show running system information\n" "IP information\n" "OSPF information\n" "Router Information\n" "PCE information\n") DEFSH (0, link_params_inter_as_cmd_vtysh, "neighbor A.B.C.D as <1-4294967295>", "Configure remote ASBR information (Neighbor IP address and AS number)\n" "Remote IP address in dot decimal A.B.C.D\n" "Remote AS number\n" "AS number in the range <1-4294967295>\n") DEFSH (0, 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 (0, capability_opaque_cmd_vtysh, "capability opaque", "Enable specific OSPF feature\n" "Opaque LSA\n") DEFSH (0, tunnel_protection_cmd_vtysh, "tunnel protection vici profile PROFILE {fallback-profile FALLBACK}", "NHRP/GRE integration\n" "IPsec protection\n" "VICI (StrongSwan)\n" "IPsec profile\n" "IPsec profile name\n" "Fallback IPsec profile\n" "Fallback IPsec profile name\n") DEFSH (0|0|0|0, 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 (0, undebug_pim_events_cmd_vtysh, "undebug pim events", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM protocol events\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, clear_ip_bgp_as_cmd_vtysh, "clear ip bgp " "<1-4294967295>", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n") DEFSH (0, pce_path_scope_cmd_vtysh, "pce scope BITPATTERN", "PCE Router Information specific commands\n" "Path scope visibilities of the PCE for path computation\n" "32-bit Hexadecimal value\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, interface_ip_igmp_join_cmd_vtysh, "ip igmp join A.B.C.D A.B.C.D", "IP information\n" "Enable IGMP operation\n" "IGMP join multicast group\n" "Multicast group address\n" "Source address\n") DEFSH (0, 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 (0, no_ip_route_flags2_tag_vrf_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_ip_pim_assert_metric_cmd_vtysh, "show ip pim assert-metric", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface assert metric\n") DEFSH (0|0, 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 (0, show_bgp_neighbor_damp_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X) dampened-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 dampened routes received from neighbor\n") DEFSH (0, ip_route_mask_flags_tag_distance_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_link_params_pkt_loss_cmd_vtysh, "no packet-loss", "Negate a command or set its defaults\n" "Disable Unidirectional Link Packet Loss on this interface\n") DEFSH (0, no_lsp_gen_interval_l2_arg_cmd_vtysh, "no lsp-gen-interval level-2 <1-120>", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n" "Minimum interval in seconds\n") DEFSH (0, 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 (0, show_bgp_view_ipv6_neighbor_advertised_route_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\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 (0, show_ip_bgp_instance_ipv4_rsclient_summary_cmd_vtysh, "show ip bgp view WORD ipv4 (unicast|multicast) rsclient 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" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, 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 (0, 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 (0, debug_pim_packets_cmd_vtysh, "debug pim packets", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol packets\n") DEFSH (0, 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 (0, isis_metric_l2_cmd_vtysh, "isis metric <0-16777215> level-2", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-2 routing\n") DEFSH (0, no_psnp_interval_l1_arg_cmd_vtysh, "no isis psnp-interval <1-120> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-1 PSNPs\n") DEFSH (0, 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 (0, clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, ip_irdp_debug_disable_cmd_vtysh, "ip irdp debug disable", "IP information\n" "ICMP Router discovery debug Averts. and Solicits (short)\n") DEFSH (0, show_ip_route_summary_prefix_vrf_cmd_vtysh, "show ip route summary prefix " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "Summary of all routes\n" "Prefix routes\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_ip_route_addr_vrf_cmd_vtysh, "show ip route A.B.C.D " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "Network in the IP routing table to display\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_ip_ospf_hello_interval_addr_cmd_vtysh, "no ip ospf hello-interval <1-65535> A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n" "Address of interface") DEFSH (0, show_ipv6_ospf6_database_type_self_originated_linkstate_id_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, debug_igmp_events_cmd_vtysh, "debug igmp events", "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP protocol events\n") DEFSH (0, debug_bgp_fsm_cmd_vtysh, "debug bgp fsm", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP Finite State Machine\n") DEFSH (0, 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 (0, neighbor_local_as_no_prepend_replace_as_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>" " no-prepend replace-as", "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" "Do not prepend local-as to updates from ibgp peers\n") DEFSH (0, ripng_offset_list_ifname_cmd_vtysh, "offset-list WORD (in|out) <0-16> IFNAME", "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") DEFSH (0, ip_route_flags2_vrf_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole) " "vrf <0-65535>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_ip_igmp_join_cmd_vtysh, "show ip igmp join", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP static join information\n") DEFSH (0|0|0|0, 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 (0|0, 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 (0, neighbor_nexthop_self_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self {all}", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Disable the next hop calculation for this neighbor\n" "Apply also to ibgp-learned routes when acting as a route reflector\n") DEFSH (0, 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 (0, clear_ip_interfaces_cmd_vtysh, "clear ip interfaces", "Reset functions\n" "IP information\n" "Reset interfaces\n") DEFSH (0, show_table_cmd_vtysh, "show table", "Show running system information\n" "default routing table to use for all clients\n") DEFSH (0, no_ospf_priority_cmd_vtysh, "no ospf priority", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Router priority\n") DEFSH (0, show_ipv6_bgp_cmd_vtysh, "show ipv6 bgp", "Show running system information\n" "IP information\n" "BGP information\n") DEFSH (0, bgp_redistribute_ipv6_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, show_bgp_lcommunity_all_cmd_vtysh, "show bgp large-community", "Show running system information\n" "BGP information\n" "Display routes matching the large-communities\n") DEFSH (0, show_bgp_instance_ipv4_safi_rsclient_summary_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) rsclient summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, ospf_passive_interface_cmd_vtysh, "passive-interface IFNAME", "Suppress routing updates on an interface\n" "Interface's name\n") DEFSH (0, 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 (0, 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 (0, 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 (0, no_lsp_gen_interval_l1_arg_cmd_vtysh, "no lsp-gen-interval level-1 <1-120>", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n" "Minimum interval in seconds\n") DEFSH (0, show_debugging_ospf_cmd_vtysh, "show debugging ospf", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n") DEFSH (0, ip_irdp_shutdown_cmd_vtysh, "ip irdp shutdown", "IP information\n" "ICMP Router discovery shutdown on this interface\n") DEFSH (0|0|0|0, 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 (0, no_fpm_remote_ip_cmd_vtysh, "no fpm connection ip A.B.C.D port <1-65535>", "fpm connection remote ip and port\n" "Connection\n" "Remote fpm server ip A.B.C.D\n" "Enter ip ") DEFSH (0, clear_isis_neighbor_cmd_vtysh, "clear isis neighbor", "Reset functions\n" "Reset ISIS network information\n" "Reset ISIS neighbor adjacencies\n") DEFSH (0, ipv6_nd_prefix_val_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n") DEFSH (0, 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 (0, rip_distance_source_cmd_vtysh, "distance <1-255> A.B.C.D/M", "Administrative distance\n" "Distance value\n" "IP source prefix\n") DEFSH (0, 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 (0, 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 (0, no_ip_lcommunity_list_name_standard_all_cmd_vtysh, "no ip large-community-list standard WORD", "Negate a command or set its defaults\n" "IP information\n" "Add a large community list entry\n" "Specify standard large-community-list\n" "Large Community list name\n") DEFSH (0, show_bgp_ipv4_filter_list_cmd_vtysh, "show bgp ipv4 filter-list WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, clear_bgp_as_in_cmd_vtysh, "clear bgp " "<1-4294967295>" " in", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, show_bgp_ipv4_paths_cmd_vtysh, "show bgp paths", "Show running system information\n" "BGP information\n" "Path information\n") DEFSH (0, show_zebra_fpm_stats_cmd_vtysh, "show zebra fpm stats", "Show running system information\n" "Zebra information\n" "Forwarding Path Manager information\n" "Statistics\n") DEFSH (0, debug_ospf6_route_cmd_vtysh, "debug ospf6 route (table|intra-area|inter-area|memory)", "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" "Debug route memory use\n" ) DEFSH (0, no_bgp_bestpath_aspath_multipath_relax_cmd_vtysh, "no bgp bestpath as-path multipath-relax", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Allow load sharing across routes that have different AS paths (but same length)\n") DEFSH (0, 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 (0, ospf6_distance_ospf6_external_intra_cmd_vtysh, "distance ospf6 external <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "External routes\n" "Distance for external routes\n" "Intra-area routes\n" "Distance for intra-area routes\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_debug_ospf6_lsa_hex_detail_cmd_vtysh, "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)", "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 (0, ospf6_distance_source_access_list_cmd_vtysh, "distance <1-255> X:X::X:X/M WORD", "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") DEFSH (0, 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 (0|0|0|0, 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 (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, log_commands_cmd_vtysh, "log commands", "Logging control\n" "Log all commands (can't be unset without restart)\n") DEFSH (0, no_log_adj_changes_cmd_vtysh, "no log-adjacency-changes", "Stop logging changes in adjacency state\n") DEFSH (0, link_params_admin_grp_cmd_vtysh, "admin-grp BITPATTERN", "Administrative group membership\n" "32-bit Hexadecimal value (e.g. 0xa1)\n") DEFSH (0, 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 (0, service_advanced_vty_cmd_vtysh, "service advanced-vty", "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") DEFSH (0, area_passwd_md5_snpauth_cmd_vtysh, "(area-password|domain-password) md5 WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n" "Authentication type\n" "Level-wide password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n") DEFSH (0, neighbor_ttl_security_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "ttl-security hops <1-254>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify the maximum number of hops to the BGP peer\n") DEFSH (0, ip_irdp_preference_cmd_vtysh, "ip irdp preference <0-2147483647>", "IP information\n" "ICMP Router discovery on this interface\n" "Set default preference level for this interface\n" "Preference level\n") DEFSH (0, 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 (0, 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 (0, show_ip_bgp_damp_flap_prefix_list_cmd_vtysh, "show ip bgp dampening flap-statistics prefix-list WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, 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 (0, 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 (0, 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 (0, no_ospf_max_metric_router_lsa_shutdown_cmd_vtysh, "no max-metric router-lsa on-shutdown", "Negate a command or set its defaults\n" "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Advertise stub-router prior to full shutdown of OSPF\n") DEFSH (0, no_neighbor_advertise_interval_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "advertisement-interval <0-600>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Minimum interval between sending BGP routing updates\n" "time in seconds\n") DEFSH (0, no_ipv6_route_ifname_tag_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, debug_igmp_cmd_vtysh, "debug igmp", "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n") DEFSH (0, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, ip_route_mask_flags_distance_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0|0|0|0, 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 (0, no_psnp_interval_l2_cmd_vtysh, "no isis psnp-interval level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "Specify interval for level-2 PSNPs\n") DEFSH (0, 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 (0, show_ip_rpf_vrf_all_cmd_vtysh, "show ip rpf " "vrf all", "Show running system information\n" "IP information\n" "Display RPF information for multicast source\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, ipv6_route_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 (0, 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 (0, 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 (0, clear_ip_bgp_as_encap_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " encap 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 (0, clear_bgp_ipv6_all_out_cmd_vtysh, "clear bgp ipv6 * out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Resend all outbound updates\n") DEFSH (0, no_ipv6_route_ifname_flags_pref_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_interface_vrf_all_cmd_vtysh, "show interface " "vrf all", "Show running system information\n" "Interface status and configuration\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, no_ipv6_route_ifname_flags_pref_tag_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, clear_ip_bgp_peer_encap_soft_in_cmd_vtysh, "clear ip bgp A.B.C.D encap 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 (0, show_ip_igmp_groups_cmd_vtysh, "show ip igmp groups", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP groups information\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv6_safi_community_list_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\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 (0, ripng_redistribute_type_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel|nhrp)", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, interface_ip_igmp_query_max_response_time_cmd_vtysh, "ip igmp query-max-response-time" " <1-25>", "IP information\n" "Enable IGMP operation\n" "IGMP max query response value (seconds)\n" "Query response value in seconds\n") DEFSH (0, show_ipv6_ospf6_database_type_id_router_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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 (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, 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 (0, 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 (0, ospf6_distance_ospf6_external_cmd_vtysh, "distance ospf6 external <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "External routes\n" "Distance for external routes\n") DEFSH (0, 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 (0, show_ip_ospf_database_type_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" "|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" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "LSAs in MaxAge list\n" "Self-originated link states\n") DEFSH (0, show_bgp_ipv6_safi_lcommunity3_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, 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 (0, bgp_redistribute_ipv6_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" " metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, no_max_lsp_lifetime_cmd_vtysh, "no max-lsp-lifetime", "Negate a command or set its defaults\n" "LSP lifetime in seconds\n") DEFSH (0, show_ip_bgp_lcommunity3_cmd_vtysh, "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the large-communities\n" "largecommunity number\n" "largecommunity number\n" "largecommunity number\n") DEFSH (0, 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 (0, 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 (0, show_bgp_view_ipv4_safi_rsclient_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, 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 (0, debug_isis_upd_cmd_vtysh, "debug isis update-packets", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Update related packets\n") DEFSH (0, 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 (0, vty_login_cmd_vtysh, "login", "Enable password checking\n") DEFSH (0|0|0|0|0, no_match_tag_cmd_vtysh, "no match tag", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match tag of route\n") DEFSH (0, ospf6_timers_throttle_spf_cmd_vtysh, "timers throttle spf <0-600000> <0-600000> <0-600000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF6 SPF timers\n" "Delay (msec) from first change received till SPF calculation\n" "Initial hold time (msec) between consecutive SPF calculations\n" "Maximum hold time (msec)\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_regexp_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) regexp .LINE", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\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 (0, 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 (0, 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 (0, 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 inbound and outbound updates\n") DEFSH (0, show_bgp_ipv4_community4_cmd_vtysh, "show bgp ipv4 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" "IP 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 (0, show_bgp_view_ipv6_rsclient_route_cmd_vtysh, "show bgp view WORD ipv6 rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "BGP view name\n" "IP6_STR" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, show_ip_pim_upstream_join_desired_cmd_vtysh, "show ip pim upstream-join-desired", "Show running system information\n" "IP information\n" "PIM information\n" "PIM upstream join-desired\n") DEFSH (0|0|0|0, 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 (0|0, no_match_ipv6_address_val_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 (0, 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 (0, no_match_probability_cmd_vtysh, "no match probability", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match portion of routes defined by percentage value\n") DEFSH (0, clear_ip_pim_interfaces_cmd_vtysh, "clear ip pim interfaces", "Reset functions\n" "IP information\n" "PIM clear commands\n" "Reset PIM interfaces\n") DEFSH (0, no_ipv6_route_flags_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, test_pim_receive_prune_cmd_vtysh, "test pim receive prune INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM prune reception from neighbor\n" "Interface\n" "Neighbor holdtime\n" "Upstream neighbor unicast destination address\n" "Downstream neighbor unicast source address\n" "Multicast group address\n" "Unicast source address\n") DEFSH (0, show_ipv6_route_vrf_all_cmd_vtysh, "show ipv6 route " "vrf all", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, show_ipv6_nht_cmd_vtysh, "show ipv6 nht", "Show running system information\n" "IP information\n" "IPv6 nexthop tracking table\n") DEFSH (0, csnp_interval_l2_cmd_vtysh, "isis csnp-interval <1-600> level-2", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") DEFSH (0, ipv6_route_ifname_flags_pref_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255> " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 calculation\n" "Show SPF tree\n") DEFSH (0|0|0|0, 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 (0, no_ripng_offset_list_cmd_vtysh, "no offset-list WORD (in|out) <0-16>", "Negate a command or set its defaults\n" "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") DEFSH (0, 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 (0, show_ip_multicast_cmd_vtysh, "show ip multicast", "Show running system information\n" "IP information\n" "Multicast global information\n") DEFSH (0, show_bgp_ipv6_vpn_tags_cmd_vtysh, "show bgp ipv6 vpn tags", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "Display BGP tags for prefixes\n") DEFSH (0, show_debugging_pim_cmd_vtysh, "show debugging pim", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "PIM information\n") DEFSH (0, show_bgp_ipv6_safi_prefix_list_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) prefix-list WORD", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, 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 (0, show_ip_bgp_nexthop_cmd_vtysh, "show ip bgp nexthop", "Show running system information\n" "IP information\n" "BGP information\n" "BGP nexthop table\n") DEFSH (0, 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 (0, 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 (0, undebug_bgp_events_cmd_vtysh, "undebug bgp events", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP events\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, ip_route_flags2_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole)", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, debug_isis_packet_dump_cmd_vtysh, "debug isis packet-dump", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS packet dump\n") DEFSH (0, no_ipv6_nd_mtu_cmd_vtysh, "no ipv6 nd mtu", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n") DEFSH (0, show_ip_nhrp_cmd_vtysh, "show " "(ip|ipv6)" " nhrp (cache|nhs|shortcut|opennhrp|)", "Show running system information\n" "IP information\n" "IPv6 information\n" "NHRP information\n" "Forwarding cache information\n" "Next hop server information\n" "Shortcut information\n" "opennhrpctl style cache dump\n") DEFSH (0, 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 (0, ospf6_distance_ospf6_intra_external_cmd_vtysh, "distance ospf6 intra-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "External routes\n" "Distance for external routes\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, show_ipv6_ospf6_database_type_id_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, show_bgp_instance_neighbors_cmd_vtysh, "show bgp view WORD neighbors", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, 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 (0, set_aggregator_as_cmd_vtysh, "set aggregator as " "<1-4294967295>" " 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 (0, 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 (0, nhrp_nflog_group_cmd_vtysh, "nhrp nflog-group <1-65535>", "Next Hop Resolution Protocol functions\n" "Specify NFLOG group number\n" "NFLOG group number\n") DEFSH (0|0|0|0, 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 (0, no_debug_igmp_trace_cmd_vtysh, "no debug igmp trace", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP internal daemon activity\n") DEFSH (0, clear_ip_bgp_all_in_cmd_vtysh, "clear ip bgp * in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, ospf_timers_min_ls_arrival_cmd_vtysh, "timers lsa arrival <0-1000>", "Adjust routing timers\n" "Throttling link state advertisement delays\n" "OSPF minimum arrival interval delay\n" "Delay (msec) between accepted LSAs\n") DEFSH (0|0|0|0, 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 (0, ipv6_nd_managed_config_flag_cmd_vtysh, "ipv6 nd managed-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Managed address configuration flag\n") DEFSH (0, 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 (0, show_bgp_view_neighbor_damp_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system 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" "Display the dampened routes received from neighbor\n") DEFSH (0, 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 (0, tunnel_source_cmd_vtysh, "tunnel source INTERFACE", "NHRP/GRE integration\n" "Tunnel device binding tracking\n" "Interface name\n") DEFSH (0, area_import_list_cmd_vtysh, "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") DEFSH (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, bgp_redistribute_ipv4_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)" " metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, bgp_damp_set3_cmd_vtysh, "bgp dampening", "BGP Specific commands\n" "Enable route-flap dampening\n") DEFSH (0|0|0|0, 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 (0, no_neighbor_local_as_val3_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>" " no-prepend replace-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" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n" "Do not prepend local-as to updates from ibgp peers\n") DEFSH (0, 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 (0, 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 (0, show_bgp_view_cmd_vtysh, "show bgp view WORD", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n") DEFSH (0, show_ipv6_ospf6_database_cmd_vtysh, "show ipv6 ospf6 database", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" ) DEFSH (0, show_isis_neighbor_detail_cmd_vtysh, "show isis neighbor detail", "Show running system information\n" "ISIS network information\n" "ISIS neighbor adjacencies\n" "show detailed information\n") DEFSH (0, clear_ip_bgp_as_encap_soft_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " encap 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 (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0|0|0|0, 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 (0, 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 (0, show_bgp_ipv4_safi_neighbor_flap_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system information\n" "BGP information\n" "Address Family Modifier\n" "Address Family Modifier\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 flap statistics of the routes learned from neighbor\n") DEFSH (0, ipv6_nd_ra_interval_cmd_vtysh, "ipv6 nd ra-interval <1-1800>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in seconds\n") DEFSH (0, show_bgp_prefix_pathtype_cmd_vtysh, "show bgp X:X::X:X/M (bestpath|multipath)", "Show running system information\n" "BGP information\n" "IPv6 prefix /\n" "Display only the bestpath\n" "Display only multipaths\n") DEFSH (0, 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 (0, no_ip_route_mask_flags_distance2_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255> " "vrf <0-65535>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, 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 (0, no_bgp_redistribute_ipv4_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0|0|0|0, 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 (0, clear_bgp_as_soft_out_cmd_vtysh, "clear bgp " "<1-4294967295>" " soft out", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, show_bgp_ipv6_safi_community4_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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 (0, ip_ospf_cost_u32_inet4_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 (0, show_bgp_ipv4_rsclient_cmd_vtysh, "show bgp ipv4 rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Address Family\n" "Information about Route Server Client\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, clear_ip_bgp_as_soft_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n") DEFSH (0, no_ipv6_address_cmd_vtysh, "no ipv6 address X:X::X:X/M", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Set the IP address of an interface\n" "IPv6 address (e.g. 3ffe:506::1/48)\n") DEFSH (0, 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 (0, 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 (0, show_ipv6_ospf6_database_type_adv_router_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, no_isis_hello_interval_cmd_vtysh, "no isis hello-interval", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n") DEFSH (0, no_ipv6_nd_other_config_flag_cmd_vtysh, "no ipv6 nd other-config-flag", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Other statefull configuration flag\n") DEFSH (0|0|0|0, 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 (0, 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 (0, show_bgp_ipv4_safi_flap_regexp_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics regexp .LINE", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\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 (0, 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 (0, isis_redistribute_cmd_vtysh, "redistribute (ipv4|ipv6) " "(kernel|connected|static|rip|ripng|ospf|ospf6|bgp|pim|babel|nhrp)" " (level-1|level-2) {metric <0-16777215>|route-map WORD}", "Redistribute information from another routing protocol\n" "Redistribute IPv4 routes\n" "Redistribute IPv6 routes\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (OSPFv2)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Redistribute into level-1\n" "Redistribute into level-2\n" "Metric for redistributed routes\n" "ISIS default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 (0, no_isis_mpls_te_inter_as_cmd_vtysh, "no mpls-te inter-as", "Negate a command or set its defaults\n" "Disable the MPLS-TE functionality\n" "Disable MPLS-TE Inter-AS support\n") DEFSH (0, show_database_arg_detail_cmd_vtysh, "show isis database WORD detail", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n" "LSP ID\n" "Detailed information\n") DEFSH (0, show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\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 (0, no_ip_route_mask_distance_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255> " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_ip_route_protocol_cmd_vtysh, "show ip route " "(kernel|connected|static|rip|ospf|isis|bgp|pim|babel|nhrp)", "Show running system information\n" "IP information\n" "IP routing table\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, show_bgp_community_all_cmd_vtysh, "show bgp community", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n") DEFSH (0, no_link_params_delay_cmd_vtysh, "no delay", "Negate a command or set its defaults\n" "Disable Unidirectional Average, Min & Max Link Delay on this interface\n") DEFSH (0, show_ipv6_bgp_lcommunity_cmd_vtysh, "show ipv6 bgp large-community (AA:BB:CC)", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, no_neighbor_enforce_multihop_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "enforce-multihop", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Enforce EBGP neighbors perform multihop\n") DEFSH (0|0|0|0, 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 (0, debug_isis_lupd_cmd_vtysh, "debug isis local-updates", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS local update packets\n") DEFSH (0, area_lsp_mtu_cmd_vtysh, "lsp-mtu <128-4352>", "Configure the maximum size of generated LSPs\n" "Maximum size of generated LSPs\n") DEFSH (0, no_debug_isis_spftrigg_cmd_vtysh, "no debug isis spf-triggers", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS SPF triggering events\n") DEFSH (0, no_ipv6_route_tag_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, show_bgp_ipv4_encap_rd_tags_cmd_vtysh, "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn tags", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "Display BGP tags for prefixes\n") DEFSH (0|0|0|0|0, set_tag_cmd_vtysh, "set tag <1-4294967295>", "Set values in destination routing protocol\n" "Tag value for routing protocol\n" "Tag value\n") DEFSH (0, no_ipv6_ripng_split_horizon_poisoned_reverse_cmd_vtysh, "no ipv6 ripng split-horizon poisoned-reverse", "Negate a command or set its defaults\n" "IPv6 information\n" "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFSH (0, no_ipv6_route_ifname_pref_tag_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_bgp_view_rsclient_prefix_cmd_vtysh, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, 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 (0, show_ip_bgp_lcommunity_list_cmd_vtysh, "show ip bgp large-community-list (<1-500>|WORD)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") DEFSH (0, multicast_cmd_vtysh, "multicast", "Set multicast flag to interface\n") DEFSH (0, clear_bgp_ipv6_as_soft_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " soft", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n") DEFSH (0, test_pim_receive_dump_cmd_vtysh, "test pim receive dump INTERFACE A.B.C.D .LINE", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM packet dump reception from neighbor\n" "Interface\n" "Neighbor address\n" "Packet dump\n") DEFSH (0, 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 (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, show_ip_bgp_ipv4_dampening_parameters_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) dampening parameters", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display detail of configured dampening parameters\n") DEFSH (0, show_ipv6_ospf6_route_longer_detail_cmd_vtysh, "show ipv6 ospf6 route X:X::X:X/M longer 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 longer than the specified route\n" "Detailed information\n" ) DEFSH (0, 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 (0, clear_ip_bgp_peer_encap_soft_cmd_vtysh, "clear ip bgp A.B.C.D encap 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 (0, show_interface_name_vrf_all_cmd_vtysh, "show interface IFNAME " "vrf all", "Show running system information\n" "Interface status and configuration\n" "Interface name\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, show_bgp_ipv6_neighbor_damp_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-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 dampened routes received from neighbor\n") DEFSH (0, 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 (0, no_ipv6_nd_homeagent_config_flag_cmd_vtysh, "no ipv6 nd home-agent-config-flag", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent configuration flag\n") DEFSH (0, 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 (0, 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 (0, show_ip_bgp_damp_flap_prefix_longer_cmd_vtysh, "show ip bgp dampening flap-statistics A.B.C.D/M longer-prefixes", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\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 (0, 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 (0, 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 (0, 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 (0, vrf_netns_cmd_vtysh, "vrf <1-65535> netns NAME", "Enable a VRF\n" "Specify the VRF identifier\n" "Associate with a NETNS\n" "The file name in " "/var/run/netns" ", or a full pathname\n") DEFSH (0, 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 (0, 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" "Resend all outbound updates\n") DEFSH (0, 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 (0, 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" "Resend all outbound updates\n") DEFSH (0|0|0|0|0|0, no_rmap_onmatch_next_cmd_vtysh, "no on-match next", "Negate a command or set its defaults\n" "Exit policy on matches\n" "Next clause\n") DEFSH (0, ospf_neighbor_cmd_vtysh, "neighbor A.B.C.D", "Specify neighbor router\n" "Neighbor IP address\n") DEFSH (0, log_adj_changes_cmd_vtysh, "log-adjacency-changes", "Log changes in adjacency state\n") DEFSH (0, show_bgp_ipv4_vpn_rd_tags_cmd_vtysh, "show bgp ipv4 vpn rd ASN:nn_or_IP-address:nn tags", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n") DEFSH (0, interface_no_ip_igmp_query_max_response_time_dsec_cmd_vtysh, "no" " " "ip igmp query-max-response-time-dsec", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n" "IGMP max query response value (deciseconds)\n") DEFSH (0, 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 (0, 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 (0, 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 (0, show_ip_lcommunity_list_cmd_vtysh, "show ip large-community-list", "Show running system information\n" "IP information\n" "List large-community list\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, show_isis_neighbor_arg_cmd_vtysh, "show isis neighbor WORD", "Show running system information\n" "ISIS network information\n" "ISIS neighbor adjacencies\n" "System id\n") DEFSH (0, 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 (0, no_ip_rip_split_horizon_cmd_vtysh, "no ip rip split-horizon", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Perform split horizon\n") DEFSH (0, ip_mroute_dist_cmd_vtysh, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n") DEFSH (0, clear_isis_neighbor_arg_cmd_vtysh, "clear isis neighbor WORD", "Reset functions\n" "ISIS network information\n" "ISIS neighbor adjacencies\n" "System id\n") DEFSH (0, show_ip_rip_cmd_vtysh, "show ip rip", "Show running system information\n" "IP information\n" "Show RIP routes\n") DEFSH (0, 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 (0, no_bgp_confederation_identifier_arg_cmd_vtysh, "no bgp confederation identifier " "<1-4294967295>", "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 (0, 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 (0, 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 (0, vty_restricted_mode_cmd_vtysh, "anonymous restricted", "Restrict view commands available in anonymous, unauthenticated vty\n") DEFSH (0, 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 (0, if_nhrp_holdtime_cmd_vtysh, "(ip|ipv6)" " nhrp holdtime <1-65000>", "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Specify NBMA address validity time\n" "Time in seconds that NBMA addresses are advertised valid\n") DEFSH (0, show_ip_igmp_groups_retransmissions_cmd_vtysh, "show ip igmp groups retransmissions", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP groups information\n" "IGMP group retransmissions\n") DEFSH (0, 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 (0, no_debug_zebra_nht_cmd_vtysh, "no debug zebra nht", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra next hop tracking\n") DEFSH (0, neighbor_peer_group_cmd_vtysh, "neighbor WORD peer-group", "Specify neighbor router\n" "Neighbor tag\n" "Configure peer-group\n") DEFSH (0, 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" "Community-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") DEFSH (0|0|0|0, 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 (0, ospf6_distance_source_cmd_vtysh, "distance <1-255> X:X::X:X/M", "Administrative distance\n" "Distance value\n" "IP source prefix\n") DEFSH (0, show_ipv6_ospf6_database_type_id_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, show_bgp_ipv4_safi_rsclient_route_cmd_vtysh, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, show_ipv6_ospf6_database_type_id_self_originated_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, 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 (0, 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 (0, 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 extended community\n" "VPN extended community\n") DEFSH (0, debug_isis_csum_cmd_vtysh, "debug isis checksum-errors", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS LSP checksum errors\n") DEFSH (0, 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 (0, 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" "View name\n") DEFSH (0, 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 (0, 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 (0|0|0|0|0, 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 (0, 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 (0, no_match_local_pref_cmd_vtysh, "no match local-preference", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match local preference of route\n") DEFSH (0, 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 (0, clear_ip_bgp_as_vpnv4_soft_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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 inbound and outbound updates\n") DEFSH (0, 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 (0, 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 (0, debug_mroute_cmd_vtysh, "debug mroute", "Debugging functions (see also 'undebug')\n" "PIM interaction with kernel MFC cache\n") DEFSH (0, show_interface_name_cmd_vtysh, "show interface IFNAME", "Show running system information\n" "Interface status and configuration\n" "Interface name\n") DEFSH (0, show_bgp_ipv6_safi_rd_prefix_cmd_vtysh, "show bgp ipv6 (encap|vpn) rd ASN:nn_or_IP-address:nn X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display information for a route distinguisher\n" "ENCAP Route Distinguisher\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_bgp_ipv6_encap_neighbor_routes_cmd_vtysh, "show bgp ipv6 encap neighbors A.B.C.D routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0|0|0|0|0|0, rmap_show_name_cmd_vtysh, "show route-map [WORD]", "Show running system information\n" "route-map information\n" "route-map name\n") DEFSH (0, 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 (0, ip_lcommunity_list_name_standard2_cmd_vtysh, "ip large-community-list standard WORD (deny|permit)", "IP information\n" "Add a large community list entry\n" "Specify standard large-community-list\n" "Large Community list name\n" "Specify large community to reject\n" "Specify large community to accept\n") DEFSH (0, ip_ospf_dead_interval_minimal_cmd_vtysh, "ip ospf dead-interval minimal hello-multiplier <1-10>", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Minimal 1s dead-interval with fast sub-second hellos\n" "Hello multiplier factor\n" "Number of Hellos to send each second\n") DEFSH (0|0|0|0, 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 (0|0|0|0, 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 (0, neighbor_local_as_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>", "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 (0, 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 (0, 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 (0, show_ip_route_tag_cmd_vtysh, "show ip route tag <1-4294967295>", "Show running system information\n" "IP information\n" "IP routing table\n" "Show only routes with tag\n" "Tag value\n") DEFSH (0, show_bgp_instance_ipv6_safi_rsclient_summary_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) rsclient summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0|0|0, ospf6_routemap_no_match_address_prefixlist_cmd_vtysh, "no match ipv6 address prefix-list WORD", "Negate a command or set its defaults\n" "Match values\n" "IPv6 information\n" "Match address of route\n" "Match entries of prefix-lists\n" "IPv6 prefix-list name\n") DEFSH (0, 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") DEFSH (0, undebug_igmp_events_cmd_vtysh, "undebug igmp events", "Disable debugging functions (see also 'debug')\n" "IGMP protocol activity\n" "IGMP protocol events\n") DEFSH (0, ospf6_redistribute_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|isis|bgp|babel|nhrp)" " route-map WORD", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Route map name\n" ) DEFSH (0, 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 (0, 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 (0, show_ipv6_ospf6_database_detail_cmd_vtysh, "show ipv6 ospf6 database (detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, show_isis_summary_cmd_vtysh, "show isis summary", "Show running system information\n" "IS-IS information\n" "IS-IS summary\n") DEFSH (0, show_ip_bgp_ipv4_neighbor_prefix_counts_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", "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 detailed prefix count information\n") DEFSH (0, show_interface_name_vrf_cmd_vtysh, "show interface IFNAME " "vrf <0-65535>", "Show running system information\n" "Interface status and configuration\n" "Interface name\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_auto_summary_cmd_vtysh, "no auto-summary", "Negate a command or set its defaults\n" "Enable automatic network number summarization\n") DEFSH (0, show_database_detail_arg_cmd_vtysh, "show isis database detail WORD", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n" "Detailed information\n" "LSP ID\n") DEFSH (0, show_bgp_ipv4_safi_damp_flap_cidr_only_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics cidr-only", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Address Family Modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") DEFSH (0, 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 occurrences of AS number\n") DEFSH (0, show_bgp_view_ipv6_neighbor_routes_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\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 (0|0|0|0, 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 (0, no_debug_bgp_zebra_cmd_vtysh, "no debug bgp zebra", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP Zebra messages\n") DEFSH (0, ospf_cost_u32_inet4_cmd_vtysh, "ospf cost <1-65535> A.B.C.D", "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFSH (0, 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 (0, 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 (0, 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 (0, 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 (0, show_bgp_ipv4_safi_community3_exact_cmd_vtysh, "show 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" "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 (0, show_ipv6_route_summary_prefix_vrf_cmd_vtysh, "show ipv6 route summary prefix " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Prefix routes\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, ip_route_flags_tag_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") DEFSH (0, no_ipv6_route_ifname_pref_tag_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") DEFSH (0, 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 (0, debug_isis_lsp_sched_cmd_vtysh, "debug isis lsp-sched", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS scheduling of LSP generation\n") DEFSH (0, 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 (0, config_table_cmd_vtysh, "table TABLENO", "Configure target kernel routing table\n" "TABLE integer\n") DEFSH (0, max_lsp_lifetime_l2_cmd_vtysh, "max-lsp-lifetime level-2 <350-65535>", "Maximum LSP lifetime for Level 2 only\n" "LSP lifetime for Level 2 only in seconds\n") DEFSH (0, 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 (0, no_isis_hello_multiplier_l2_arg_cmd_vtysh, "no isis hello-multiplier <2-100> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") DEFSH (0, bgp_enforce_first_as_cmd_vtysh, "bgp enforce-first-as", "BGP information\n" "Enforce the first AS for EBGP routes\n") DEFSH (0, 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 (0, show_bgp_ipv4_community4_exact_cmd_vtysh, "show bgp ipv4 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" "IP 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 (0, show_bgp_ipv6_safi_community_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\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 (0|0|0|0, 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 (0, ip_multicast_routing_cmd_vtysh, "ip multicast-routing", "IP information\n" "Enable IP multicast forwarding\n") DEFSH (0, show_bgp_ipv6_encap_neighbor_advertised_routes_cmd_vtysh, "show bgp ipv6 encap neighbors A.B.C.D advertised-routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\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 (0, 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 (0, 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 (0, ospf_priority_cmd_vtysh, "ospf priority <0-255>", "OSPF interface commands\n" "Router priority\n" "Priority\n") DEFSH (0, 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 (0, isis_metric_cmd_vtysh, "isis metric <0-16777215>", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") DEFSH (0, no_ipv6_ripng_split_horizon_cmd_vtysh, "no ipv6 ripng split-horizon", "Negate a command or set its defaults\n" "IPv6 information\n" "Routing Information Protocol\n" "Perform split horizon\n") DEFSH (0, ospf6_redistribute_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|isis|bgp|babel|nhrp)", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" ) DEFSH (0|0|0|0|0|0, no_rmap_call_cmd_vtysh, "no call", "Negate a command or set its defaults\n" "Jump to another Route-Map after match+set\n") DEFSH (0, no_isis_hello_interval_l2_cmd_vtysh, "no isis hello-interval level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Specify hello-interval for level-2 IIHs\n") DEFSH (0, 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 (0, show_ipv6_ospf6_database_id_router_cmd_vtysh, "show ipv6 ospf6 database * 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 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" ) DEFSH (0, 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 (0, 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 (0, no_ospf_network_cmd_vtysh, "no ospf network", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Network type\n") DEFSH (0|0|0|0, 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 (0, ipv6_bgp_distance_source_cmd_vtysh, "distance <1-255> X:X::X:X/M", "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n") DEFSH (0, if_no_nhrp_map_cmd_vtysh, "no " "(ip|ipv6)" " nhrp map (A.B.C.D|X:X::X:X)", "Negate a command or set its defaults\n" "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Nexthop Server configuration\n" "IPv4 protocol address\n" "IPv6 protocol address\n") DEFSH (0, 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 (0, show_ipv6_mbgp_lcommunity2_cmd_vtysh, "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n") DEFSH (0, 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 (0, 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 (0, 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 (0, no_isis_metric_l1_cmd_vtysh, "no isis metric level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Specify metric for level-1 routing\n") DEFSH (0, no_ip_lcommunity_list_name_expanded_cmd_vtysh, "no ip large-community-list expanded WORD (deny|permit) .LINE", "Negate a command or set its defaults\n" "IP information\n" "Add a large community list entry\n" "Specify expanded large-community-list\n" "Large community list name\n" "Specify large community to reject\n" "Specify large community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_prefix_list_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) prefix-list WORD", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd_vtysh, "show bgp ipv4 vpn neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\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 (0, show_ipv6_route_prefix_longer_vrf_cmd_vtysh, "show ipv6 route X:X::X:X/M longer-prefixes " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0|0|0|0|0|0, rmap_continue_cmd_vtysh, "continue", "Continue on a different entry within the route-map\n") DEFSH (0, no_lsp_refresh_interval_l1_arg_cmd_vtysh, "no lsp-refresh-interval level-1 <1-65235>", "Negate a command or set its defaults\n" "LSP refresh interval for Level 1 only\n" "LSP refresh interval for Level 1 only in seconds\n") DEFSH (0, 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 (0, show_ip_extcommunity_list_cmd_vtysh, "show ip extcommunity-list", "Show running system information\n" "IP information\n" "List extended-community list\n") DEFSH (0, no_ipv6_nd_ra_interval_val_cmd_vtysh, "no ipv6 nd ra-interval <1-1800>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n") DEFSH (0, router_id_vrf_cmd_vtysh, "router-id A.B.C.D " "vrf <0-65535>", "Manually set the router-id\n" "IP address to use for router-id\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_set_lcommunity_delete_val_cmd_vtysh, "no set large-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 large community list (for deletion)\n" "Large Community-list number (standard)\n" "Large Communitly-list number (expanded)\n" "Large Community-list name\n" "Delete matching large communities\n") DEFSH (0, show_bgp_statistics_view_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", "Show running system information\n" "BGP information\n" "BGP view\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFSH (0, debug_bgp_filter_cmd_vtysh, "debug bgp filters", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP filters\n") DEFSH (0, ripng_aggregate_address_cmd_vtysh, "aggregate-address X:X::X:X/M", "Set aggregate RIPng route announcement\n" "Aggregate network\n") DEFSH (0, no_ospf_max_metric_router_lsa_startup_cmd_vtysh, "no max-metric router-lsa on-startup", "Negate a command or set its defaults\n" "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Automatically advertise stub Router-LSA on startup of OSPF\n") DEFSH (0, 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 (0, ospf6_distance_ospf6_inter_external_cmd_vtysh, "distance ospf6 inter-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "External routes\n" "Distance for external routes\n") DEFSH (0, show_bgp_view_rsclient_cmd_vtysh, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, clear_bgp_as_soft_cmd_vtysh, "clear bgp " "<1-4294967295>" " soft", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound and outbound updates\n") DEFSH (0|0|0|0, 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 (0, show_ipv6_ospf6_database_type_router_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, no_debug_ospf6_route_cmd_vtysh, "no debug ospf6 route (table|intra-area|inter-area|memory)", "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" "Debug route memory use\n") DEFSH (0, ip_irdp_minadvertinterval_cmd_vtysh, "ip irdp minadvertinterval <3-1800>", "IP information\n" "ICMP Router discovery on this interface\n" "Set minimum time between advertisement\n" "Minimum advertisement interval in seconds\n") DEFSH (0, 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 (0, psnp_interval_l2_cmd_vtysh, "isis psnp-interval <1-120> level-2", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-2 PSNPs\n") DEFSH (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") DEFSH (0, undebug_pim_zebra_cmd_vtysh, "undebug pim zebra", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "ZEBRA protocol activity\n") DEFSH (0, ip_route_flags_distance2_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole) <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, 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 (0|0|0|0, clear_ipv6_prefix_list_cmd_vtysh, "clear ipv6 prefix-list", "Reset functions\n" "IPv6 information\n" "Build a prefix list\n") DEFSH (0, show_ip_ssmpingd_cmd_vtysh, "show ip ssmpingd", "Show running system information\n" "IP information\n" "ssmpingd operation\n") DEFSH (0, show_bgp_view_afi_safi_community_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\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 (0, show_bgp_ipv6_safi_community2_exact_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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 (0|0|0|0|0|0, no_rmap_description_cmd_vtysh, "no description", "Negate a command or set its defaults\n" "Route-map comment\n") DEFSH (0, 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 (0, neighbor_advertise_interval_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "advertisement-interval <0-600>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Minimum interval between sending BGP routing updates\n" "time in seconds\n") DEFSH (0, no_set_ipv6_nexthop_peer_cmd_vtysh, "no set ipv6 next-hop peer-address", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "IPv6 information\n" "IPv6 next-hop address\n" ) DEFSH (0, show_bgp_statistics_cmd_vtysh, "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics", "Show running system information\n" "BGP information\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFSH (0, 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 (0, 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 (0, 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" "Display Intra-Area routes\n" "Display Inter-Area routes\n" "Display Type-1 External routes\n" "Display Type-2 External routes\n" ) DEFSH (0, show_ip_protocol_cmd_vtysh, "show ip protocol", "Show running system information\n" "IP information\n" "IP protocol filtering status\n") DEFSH (0, ospf6_distance_ospf6_inter_external_intra_cmd_vtysh, "distance ospf6 inter-area <1-255> external <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF6 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 (0, 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 (0, show_bgp_ipv6_safi_regexp_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) regexp .LINE", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\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 (0, show_ip_pim_assert_internal_cmd_vtysh, "show ip pim assert-internal", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface internal assert state\n") DEFSH (0, 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 (0, show_bgp_ipv6_safi_damp_dampened_paths_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) dampening dampened-paths", "Show running system information\n" "BGP information\n" "IPv6 information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display paths suppressed due to dampening\n") DEFSH (0, no_debug_nhrp_cmd_vtysh, "no debug nhrp " "(all|common|event|interface|kernel|route|vici)", "Negate a command or set its defaults\n" "Disable debug messages for specific or all parts.\n" "NHRP information\n" "All messages\n" "Common messages (default)\n" "Event manager messages\n" "Interface messages\n" "Kernel messages\n" "Route messages\n" "VICI messages\n") DEFSH (0, isis_metric_l1_cmd_vtysh, "isis metric <0-16777215> level-1", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-1 routing\n") DEFSH (0, no_ospf_cost_u32_inet4_cmd_vtysh, "no ospf cost <1-65535> A.B.C.D", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFSH (0, ospf_timers_throttle_spf_cmd_vtysh, "timers throttle spf <0-600000> <0-600000> <0-600000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF SPF timers\n" "Delay (msec) from first change received till SPF calculation\n" "Initial hold time (msec) between consecutive SPF calculations\n" "Maximum hold time (msec)\n") DEFSH (0, debug_pim_packets_filter_cmd_vtysh, "debug pim packets (hello|joins)", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol packets\n" "PIM Hello protocol packets\n" "PIM Join/Prune protocol packets\n") DEFSH (0, 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 (0, is_type_cmd_vtysh, "is-type (level-1|level-1-2|level-2-only)", "IS Level for this routing process (OSI only)\n" "Act as a station router only\n" "Act as both a station router and an area router\n" "Act as an area router only\n") DEFSH (0, ipv6_nd_prefix_noval_rtaddr_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Set Router Address flag\n") DEFSH (0, 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 (0, 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 (0, show_ip_route_summary_vrf_cmd_vtysh, "show ip route summary " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "Summary of all routes\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, no_debug_isis_err_cmd_vtysh, "no debug isis protocol-errors", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS LSP protocol errors\n") DEFSH (0, show_ip_pim_lan_prune_delay_cmd_vtysh, "show ip pim lan-prune-delay", "Show running system information\n" "IP information\n" "PIM information\n" "PIM neighbors LAN prune delay parameters\n") DEFSH (0, 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 (0, 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 (0, no_ipv6_route_ifname_pref_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255> " "vrf <0-65535>", "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" "Specify the VRF\nThe VRF ID\n") DEFSH (0, ipv6_nd_prefix_val_offlink_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n") DEFSH (0, no_link_params_ava_bw_cmd_vtysh, "no ava-bw", "Negate a command or set its defaults\n" "Disable Unidirectional Available Bandwidth on this interface\n") DEFSH (0, pce_domain_cmd_vtysh, "pce domain as <0-65535>", "PCE Router Information specific commands\n" "Configure PCE domain AS number\n" "AS number where the PCE as visibilities for path computation\n" "AS number in decimal <0-65535>\n") DEFSH (0, 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 (0, no_ip_ospf_cost_u32_cmd_vtysh, "no ip ospf cost <1-65535>", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost") DEFSH (0, no_neighbor_ttl_security_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ttl-security hops <1-254>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify the maximum number of hops to the BGP peer\n") DEFSH (0, show_isis_interface_detail_cmd_vtysh, "show isis interface detail", "Show running system information\n" "ISIS network information\n" "ISIS interface\n" "show detailed information\n") DEFSH (0|0|0|0, 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 (0, no_bgp_redistribute_ipv6_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)" " metric <0-4294967295>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, area_passwd_clear_snpauth_cmd_vtysh, "(area-password|domain-password) clear WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n" "Authentication type\n" "Area password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n") DEFSH (0, no_debug_ospf6_brouter_router_cmd_vtysh, "no debug ospf6 border-routers router-id", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" "Debug specific border router\n" ) DEFSH (0, debug_isis_spfstats_cmd_vtysh, "debug isis spf-statistics ", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS SPF Timing and Statistic Data\n") DEFSH (0, show_ip_bgp_lcommunity_info_cmd_vtysh, "show ip bgp large-community-info", "Show running system information\n" "IP information\n" "BGP information\n" "List all bgp large-community information\n") DEFSH (0, no_neighbor_timers_connect_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "timers connect <1-65535>", "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" "BGP connect timer\n" "Connect timer\n") DEFSH (0, 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 (0, 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 (0, show_ip_pim_upstream_cmd_vtysh, "show ip pim upstream", "Show running system information\n" "IP information\n" "PIM information\n" "PIM upstream information\n") DEFSH (0, show_bgp_ipv6_safi_lcommunity_list_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) large-community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n") DEFSH (0, 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 (0, 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 (0|0|0|0, 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 (0, show_bgp_ipv4_safi_damp_flap_statistics_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n") DEFSH (0, 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 (0, bgp_confederation_identifier_cmd_vtysh, "bgp confederation identifier " "<1-4294967295>", "BGP specific commands\n" "AS confederation parameters\n" "AS number\n" "Set routing domain confederation AS\n") DEFSH (0, show_ipv6_mbgp_lcommunity4_cmd_vtysh, "show ipv6 mbgp laarge-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, no_ip_route_flags_distance_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, neighbor_password_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "password LINE", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Set a password\n" "The password\n") DEFSH (0, 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 (0, 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 (0, no_set_lcommunity_val_cmd_vtysh, "no set large-community .AA:BB:CC", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP large community attribute\n" "Large community in .AA:BB:CC format or additive\n") DEFSH (0, no_ip_route_mask_flags_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, ip_route_flags_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, clear_ip_bgp_instance_all_rsclient_cmd_vtysh, "clear ip bgp view WORD * rsclient", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, 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 (0, 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 (0, 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 (0, show_database_detail_cmd_vtysh, "show isis database detail", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n") DEFSH (0, show_bgp_ipv6_vpn_rd_neighbor_routes_cmd_vtysh, "show bgp ipv6 vpn rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "Address Family\n" "Address Family modifier\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 (0, 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 (0, psnp_interval_cmd_vtysh, "isis psnp-interval <1-120>", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n") DEFSH (0, undebug_bgp_as4_segment_cmd_vtysh, "undebug bgp as4 segment", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") DEFSH (0, no_ip_mroute_cmd_vtysh, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", "Negate a command or set its defaults\n" "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, show_ipv6_route_summary_vrf_cmd_vtysh, "show ipv6 route summary " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0|0, ip_route_flags2_tag_vrf_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_neighbor_timers_connect_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "timers connect", "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" "BGP connect timer\n") DEFSH (0, no_ip_mroute_dist_cmd_vtysh, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n") DEFSH (0, no_match_local_pref_val_cmd_vtysh, "no match local-preference <0-4294967295>", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match local preference of route\n" "Local preference value\n") DEFSH (0, show_ip_pim_neighbor_cmd_vtysh, "show ip pim neighbor", "Show running system information\n" "IP information\n" "PIM information\n" "PIM neighbor information\n") DEFSH (0, show_ip_bgp_instance_rsclient_summary_cmd_vtysh, "show ip bgp view WORD rsclient summary", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, clear_ip_ospf_interface_cmd_vtysh, "clear ip ospf interface [IFNAME]", "Reset functions\n" "IP information\n" "OSPF information\n" "Interface information\n" "Interface name\n") DEFSH (0, show_bgp_view_ipv6_safi_rsclient_route_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, show_dmvpn_cmd_vtysh, "show dmvpn", "Show running system information\n" "DMVPN information\n") DEFSH (0, 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 (0, show_ip_bgp_ipv4_lcommunity_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)", "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 large-communities\n" "large-community number\n") DEFSH (0, ip_irdp_holdtime_cmd_vtysh, "ip irdp holdtime <0-9000>", "IP information\n" "ICMP Router discovery on this interface\n" "Set holdtime value\n" "Holdtime value in seconds. Default is 1800 seconds\n") DEFSH (0, clear_bgp_ipv6_instance_all_rsclient_cmd_vtysh, "clear bgp ipv6 view WORD * rsclient", "Reset functions\n" "BGP information\n" "Address family\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, no_ospf_abr_type_cmd_vtysh, "no ospf abr-type (cisco|ibm|shortcut|standard)", "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 (0, no_max_lsp_lifetime_l2_cmd_vtysh, "no max-lsp-lifetime level-2", "Negate a command or set its defaults\n" "LSP lifetime for Level 2 only in seconds\n") DEFSH (0, show_bgp_ipv6_safi_neighbor_received_routes_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\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 (0, no_ipv6_route_flags_pref_tag_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, undebug_pim_packetdump_recv_cmd_vtysh, "undebug pim packet-dump receive", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump received packets\n") DEFSH (0, 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 (0, no_debug_igmp_cmd_vtysh, "no debug igmp", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n") DEFSH (0, show_ip_rpf_vrf_cmd_vtysh, "show ip rpf " "vrf <0-65535>", "Show running system information\n" "IP information\n" "Display RPF information for multicast source\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_router_bgp_cmd_vtysh, "no router bgp " "<1-4294967295>", "Negate a command or set its defaults\n" "Enable a routing process\n" "BGP information\n" "AS number\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0|0, 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 (0, show_ipv6_ospf6_database_type_id_self_originated_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, clear_bgp_ipv6_peer_rsclient_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, no_ripng_timers_cmd_vtysh, "no timers basic", "Negate a command or set its defaults\n" "RIPng timers setup\n" "Basic timer\n") DEFSH (0, no_neighbor_nexthop_local_unchanged_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "nexthop-local unchanged", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Configure treatment of outgoing link-local-nexthop attribute\n" "Leave link-local nexthop unchanged for this peer\n") DEFSH (0, clear_bgp_external_cmd_vtysh, "clear bgp external", "Reset functions\n" "BGP information\n" "Clear all external peers\n") DEFSH (0, show_bgp_ipv4_prefix_cmd_vtysh, "show bgp ipv4 A.B.C.D/M", "Show running system information\n" "BGP information\n" "IP information\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, 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 (0, bgp_bestpath_aspath_confed_cmd_vtysh, "bgp bestpath as-path confed", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Compare path lengths including confederation sets & sequences in selecting a route\n") DEFSH (0, show_ip_bgp_view_rsclient_route_cmd_vtysh, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, set_ipv6_nexthop_peer_cmd_vtysh, "set ipv6 next-hop peer-address", "Set values in destination routing protocol\n" "IPv6 information\n" "Next hop address\n" "Use peer address (for BGP only)\n") DEFSH (0, ospf_default_information_originate_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 (0, 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 (0, show_ip_bgp_damp_flap_filter_list_cmd_vtysh, "show ip bgp dampening flap-statistics filter-list WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, 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 (0, no_vty_ipv6_access_class_cmd_vtysh, "no ipv6 access-class [WORD]", "Negate a command or set its defaults\n" "IPv6 information\n" "Filter connections based on an IP access list\n" "IPv6 access list\n") DEFSH (0, 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 (0, 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 (0, show_bgp_ipv4_safi_community_list_exact_cmd_vtysh, "show bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", "Show running system 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 (0, 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 (0, show_bgp_ipv6_lcommunity4_cmd_vtysh, "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, ip_route_mask_tag_vrf_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, show_bgp_ipv6_flap_address_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) flap-statistics A.B.C.D", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") DEFSH (0, show_ip_rpf_addr_vrf_all_cmd_vtysh, "show ip rpf A.B.C.D " "vrf all", "Show running system information\n" "IP information\n" "Display RPF information for multicast source\n" "IP multicast source address (e.g. 10.0.0.0)\n" "Specify the VRF\nAll VRFs\n") DEFSH (0, 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 (0, no_router_bgp_view_cmd_vtysh, "no router bgp " "<1-4294967295>" " 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 (0, no_set_attached_bit_cmd_vtysh, "no set-attached-bit", "Reset attached bit\n") DEFSH (0, 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 (0, 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 (0, interface_no_ip_pim_drprio_cmd_vtysh, "no ip pim drpriority {<1-4294967295>}", "IP information\n" "PIM information\n" "Revert the Designated Router Priority to default\n" "Old Value of the Priority\n") DEFSH (0|0, 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 (0, 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 (0, show_ipv6_ospf6_database_type_self_originated_detail_cmd_vtysh, "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 running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, show_ip_access_list_cmd_vtysh, "show ip access-list", "Show running system information\n" "IP information\n" "List IP access lists\n") DEFSH (0, no_match_peer_val_cmd_vtysh, "no match peer (A.B.C.D|X:X::X:X)", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match peer address\n" "IP address of peer\n" "IPv6 address of peer\n") DEFSH (0, 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 (0, show_ip_rip_status_cmd_vtysh, "show ip rip status", "Show running system information\n" "IP information\n" "Show RIP routes\n" "IP routing protocol process parameters and statistics\n") DEFSH (0, show_bgp_ipv6_encap_tags_cmd_vtysh, "show bgp ipv6 encap tags", "Show running system information\n" "BGP information\n" "Address Family\n" "Display ENCAP NLRI specific information\n" "Display BGP tags for prefixes\n") DEFSH (0, 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 (0, 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 (0, show_database_cmd_vtysh, "show isis database", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n") DEFSH (0, neighbor_remote_as_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "remote-as " "<1-4294967295>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a BGP neighbor\n" "AS number\n") DEFSH (0, ipv6_nd_suppress_ra_cmd_vtysh, "ipv6 nd suppress-ra", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Suppress Router Advertisement\n") DEFSH (0, 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 (0, show_isis_mpls_te_router_cmd_vtysh, "show isis mpls-te router", "Show running system information\n" "IS-IS information\n" "MPLS-TE specific commands\n" "Router information\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_flap_filter_list_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) flap-statistics filter-list WORD", "Show running system information\n" "BGP information\n" "IP information\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0|0|0|0, 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 (0, ipv6_route_ifname_flags_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, 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 (0, no_neighbor_send_community_type_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|all|extended|standard|large)", "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, Large and Extended Community attributes\n" "Send Standard, Large and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n" "Send Large Community attributes\n") DEFSH (0, ip_route_flags_vrf_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) " "vrf <0-65535>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0|0|0|0, 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 (0, ip_route_mask_flags_tag_distance_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, show_bgp_statistics_view_vpnv4_cmd_vtysh, "show bgp view WORD (ipv4) (vpnv4) statistics", "Show running system information\n" "BGP information\n" "BGP view\n" "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFSH (0, 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 (0, lsp_gen_interval_l2_cmd_vtysh, "lsp-gen-interval level-2 <1-120>", "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n" "Minimum interval in seconds\n") DEFSH (0, 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 (0, 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 (0, no_router_id_cmd_vtysh, "no router-id", "Negate a command or set its defaults\n" "Remove the manually configured router-id\n") DEFSH (0, no_ipv6_route_flags_tag_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") DEFSH (0, no_ospf_max_metric_router_lsa_admin_cmd_vtysh, "no max-metric router-lsa administrative", "Negate a command or set its defaults\n" "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") DEFSH (0, set_ip_nexthop_peer_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 (0, show_bgp_ipv4_vpn_summary_cmd_vtysh, "show bgp ipv4 vpn summary", "Show running system information\n" "BGP information\n" "IPv4\n" "Display VPN NLRI specific information\n" "Summary of BGP neighbor status\n") DEFSH (0, 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 (0, show_ipv6_forwarding_cmd_vtysh, "show ipv6 forwarding", "Show running system information\n" "IPv6 information\n" "Forwarding status\n") DEFSH (0|0|0|0|0, no_set_tag_val_cmd_vtysh, "no set tag <1-4294967295>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Tag value for routing protocol\n" "Tag value\n") DEFSH (0, 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 (0|0, 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 metric\n") DEFSH (0, interface_ip_igmp_cmd_vtysh, "ip igmp", "IP information\n" "Enable IGMP operation\n") DEFSH (0, interface_ip_mroute_cmd_vtysh, "ip mroute INTERFACE A.B.C.D", "IP information\n" "Add multicast route\n" "Outgoing interface name\n" "Group address\n") DEFSH (0, debug_pim_events_cmd_vtysh, "debug pim events", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol events\n") DEFSH (0, no_isis_metric_l2_cmd_vtysh, "no isis metric level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Specify metric for level-2 routing\n") DEFSH (0, 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 (0, debug_ospf6_brouter_area_cmd_vtysh, "debug ospf6 border-routers area-id A.B.C.D", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" "Debug border routers in specific Area\n" "Specify Area-ID\n" ) DEFSH (0, no_neighbor_passive_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "passive", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Don't send open messages to this neighbor\n") DEFSH (0, no_ospf_passive_interface_default_cmd_vtysh, "no passive-interface default", "Negate a command or set its defaults\n" "Allow routing updates on an interface\n" "Allow routing updates on interfaces by default\n") DEFSH (0, show_ip_route_supernets_vrf_all_cmd_vtysh, "show ip route supernets-only " "vrf all", "Show running system information\n" "IP information\n" "IP routing table\n" "Show supernet entries only\n" "Specify the VRF\nAll VRFs\n") DEFSH (0|0|0|0, 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 (0|0|0|0|0|0, set_metric_cmd_vtysh, "set metric <0-4294967295>", "Set value\n" "Metric value for destination routing protocol\n" "Metric value\n") DEFSH (0, 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 (0, show_bgp_ipv4_vpn_tags_cmd_vtysh, "show bgp ipv4 vpn tags", "Show running system information\n" "BGP information\n" "Address Family\n" "Display VPN NLRI specific information\n" "Display BGP tags for prefixes\n") DEFSH (0, show_bgp_ipv6_safi_community3_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) 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" "Address family modifier\n" "Address family modifier\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 (0, 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 (0, show_ip_igmp_parameters_cmd_vtysh, "show ip igmp parameters", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP parameters information\n") DEFSH (0, show_bgp_ipv4_safi_damp_flap_prefix_cmd_vtysh, "show bgp ipv4 (encap|multicast|unicast|vpn) dampening flap-statistics A.B.C.D/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Address Family modifier\n" "Display detailed information about dampening\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_rip_redistribute_type_routemap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel|nhrp)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, 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 (0, 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" "Resend all outbound updates\n") DEFSH (0, show_bgp_ipv4_safi_neighbor_routes_cmd_vtysh, "show bgp ipv4 (multicast|unicast) neighbors (A.B.C.D|X:X::X:X) routes", "Show running system 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 (0, 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 (0, 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 (0, show_ip_route_cmd_vtysh, "show ip route", "Show running system information\n" "IP information\n" "IP routing table\n") DEFSH (0, 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 (0, 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 (0, 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 (0, no_spf_interval_l2_arg_cmd_vtysh, "no spf-interval level-2 <1-120>", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, 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 (0, ip_lcommunity_list_name_standard_cmd_vtysh, "ip large-community-list standard WORD (deny|permit) .AA:BB.CC", "IP information\n" "Add a large community list entry\n" "Specify standard large-community-list\n" "Large Community list name\n" "Specify large community to reject\n" "Specify large community to accept\n" "large community in 'aa:bb:cc' format\n") DEFSH (0, 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 (0, if_nhrp_network_id_cmd_vtysh, "(ip|ipv6)" " nhrp network-id <1-4294967295>", "IP information\n" "IPv6 information\n" "Next Hop Resolution Protocol functions\n" "Enable NHRP and specify network-id\n" "System local ID to specify interface group\n") DEFSH (0, ipv6_route_flags_pref_tag_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") DEFSH (0, no_isis_hello_multiplier_arg_cmd_vtysh, "no isis hello-multiplier <2-100>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") DEFSH (0|0|0|0, 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 (0, 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 (0, no_isis_metric_l1_arg_cmd_vtysh, "no isis metric <0-16777215> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-1 routing\n") DEFSH (0, 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 (0, lsp_gen_interval_cmd_vtysh, "lsp-gen-interval <1-120>", "Minimum interval between regenerating same LSP\n" "Minimum interval in seconds\n") DEFSH (0, no_ipv6_nd_adv_interval_config_option_cmd_vtysh, "no ipv6 nd adv-interval-option", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertisement Interval Option\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, show_ipv6_route_protocol_vrf_cmd_vtysh, "show ipv6 route " "(kernel|connected|static|ripng|ospf6|isis|bgp|babel|nhrp)" " " "vrf <0-65535>", "Show running system information\n" "IP information\n" "IP routing table\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_lsp_gen_interval_arg_cmd_vtysh, "no lsp-gen-interval <1-120>", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Minimum interval in seconds\n") DEFSH (0, 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 (0, show_bgp_ipv4_safi_rsclient_prefix_cmd_vtysh, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, debug_isis_snp_cmd_vtysh, "debug isis snp-packets", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS CSNP/PSNP packets\n") DEFSH (0, 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 (0, 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 (0, no_pce_neighbor_cmd_vtysh, "no pce neighbor as <0-65535>", "Negate a command or set its defaults\n" "PCE Router Information specific commands\n" "Disable PCE neighbor AS number\n" "AS number of PCE neighbor\n" "AS number in decimal <0-65535>\n") DEFSH (0, csnp_interval_l1_cmd_vtysh, "isis csnp-interval <1-600> level-1", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") DEFSH (0, show_ipv6_ripng_cmd_vtysh, "show ipv6 ripng", "Show running system information\n" "IPv6 information\n" "Show RIPng routes\n") DEFSH (0, show_bgp_ipv6_encap_prefix_cmd_vtysh, "show bgp ipv6 encap X:X::X:X/M", "Show running system information\n" "BGP information\n" "IP information\n" "Display ENCAP NLRI specific information\n" "Display information about ENCAP NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_ipv6_ospf6_database_type_router_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) * A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "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" ) DEFSH (0, show_ipv6_bgp_lcommunity_list_cmd_vtysh, "show ipv6 bgp large-community-list WORD", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the large-community-list\n" "large-community-list name\n") DEFSH (0, 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 (0, ospf6_distance_ospf6_external_inter_intra_cmd_vtysh, "distance ospf6 external <1-255> inter-area <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF6 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 (0, 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 (0, show_bgp_view_afi_safi_community2_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) 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" "BGP view\n" "View name\n" "Address family\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 (0, ipv6_ripng_split_horizon_poisoned_reverse_cmd_vtysh, "ipv6 ripng split-horizon poisoned-reverse", "IPv6 information\n" "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFSH (0, show_bgp_view_afi_safi_lcommunity_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, 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 (0, 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 (0, no_ospf_mpls_te_cmd_vtysh, "no mpls-te", "Negate a command or set its defaults\n" "Disable the MPLS-TE functionality\n") DEFSH (0, 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 (0, ospf6_distance_ospf6_intra_inter_cmd_vtysh, "distance ospf6 intra-area <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF6 Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "Inter-area routes\n" "Distance for inter-area routes\n") DEFSH (0, show_bgp_ipv6_lcommunity_cmd_vtysh, "show bgp ipv6 large-community (AA:BB:CC)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the large-communities\n" "large-community number\n") DEFSH (0, 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 (0, 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 (0, ospf_distribute_list_out_cmd_vtysh, "distribute-list WORD out " "(kernel|connected|static|rip|isis|bgp|pim|babel|nhrp)", "Filter networks in routing updates\n" "Access-list name\n" "Filter outgoing routing updates\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, 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 (0, 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 (0, 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 (0, ip_route_flags_tag_distance2_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n") DEFSH (0, 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 inbound and outbound updates\n") DEFSH (0, show_ip_bgp_ipv4_lcommunity4_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)", "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 large-communities\n" "large-community number\n" "large-community number\n" "large-community number\n" "large-community number\n") DEFSH (0, bgp_always_compare_med_cmd_vtysh, "bgp always-compare-med", "BGP specific commands\n" "Allow comparing MED from different neighbors\n") DEFSH (0, show_bgp_summary_cmd_vtysh, "show bgp summary", "Show running system information\n" "BGP information\n" "Summary of BGP neighbor status\n") DEFSH (0, show_ip_bgp_dampening_params_cmd_vtysh, "show ip bgp dampening parameters", "Show running system information\n" "IP information\n" "BGP information\n" "Display detailed information about dampening\n" "Display detail of configured dampening parameters\n") DEFSH (0|0|0|0, 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 (0, 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 inbound and outbound updates\n") DEFSH (0, 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 (0, 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\n") DEFSH (0, 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 (0, ipv6_route_pref_tag_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") DEFSH (0, no_isis_metric_cmd_vtysh, "no isis metric", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n") DEFSH (0, no_ip_route_flags2_tag_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>", "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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n") DEFSH (0, debug_ospf_ism_cmd_vtysh, "debug ospf ism", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Interface State Machine\n") DEFSH (0, no_ipv6_route_tag_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>", "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" "Set tag for this route\n" "Tag value\n") DEFSH (0, 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 (0, 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 (0, ip_irdp_debug_misc_cmd_vtysh, "ip irdp debug misc", "IP information\n" "ICMP Router discovery debug Averts. and Solicits (short)\n") DEFSH (0, no_bgp_redistribute_ipv6_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel|nhrp)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, 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 (0, ipv6_route_pref_tag_vrf_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, csnp_interval_cmd_vtysh, "isis csnp-interval <1-600>", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") DEFSH (0, show_bgp_view_afi_safi_community_all_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") DEFSH (0|0|0|0, 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 (0, debug_ospf_event_cmd_vtysh, "debug ospf event", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF event information\n") DEFSH (0, 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 (0, no_metric_style_cmd_vtysh, "no metric-style", "Negate a command or set its defaults\n" "Use old-style (ISO 10589) or new-style packet formats\n") DEFSH (0, no_bgp_graceful_restart_restart_time_val_cmd_vtysh, "no bgp graceful-restart restart-time <1-3600>", "Negate a command or set its defaults\n" "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") DEFSH (0, 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 (0, no_debug_pim_packetdump_recv_cmd_vtysh, "no debug pim packet-dump receive", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump received packets\n") DEFSH (0, 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 (0, bgp_redistribute_ipv4_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel|nhrp)", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Next Hop Resolution Protocol (NHRP)\n") DEFSH (0, no_ip_route_mask_flags2_tag_vrf_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>" "vrf <0-65535>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, no_ipv6_route_pref_tag_vrf_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <1-255>" "vrf <0-65535>", "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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" "Specify the VRF\nThe VRF ID\n") DEFSH (0, interface_no_ip_mroute_source_cmd_vtysh, "no ip mroute INTERFACE A.B.C.D A.B.C.D", "Negate a command or set its defaults\n" "IP information\n" "Add multicast route\n" "Outgoing interface name\n" "Group Address\n" "Source Address\n") DEFSH (0, 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\n") DEFSH (0, ospf_area_nssa_cmd_vtysh, "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") DEFSH (0, no_neighbor_remote_as_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "remote-as " "<1-4294967295>", "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 (0, no_set_pathlimit_ttl_val_cmd_vtysh, "no set pathlimit ttl <1-255>", "Negate a command or set its defaults\n" "Match values from routing table\n" "BGP AS-Pathlimit attribute\n" "Set AS-Path Hop-count TTL\n") DEFSH (0, 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" "Send route-refresh unless using 'soft-reconfiguration inbound'\n" "Push out the existing ORF prefix-list\n") DEFSH (0, 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 (0, 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 (0, 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 (0, show_bgp_ipv6_safi_community_exact_cmd_vtysh, "show bgp ipv6 (encap|multicast|unicast|vpn) community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Address family\n" "Address family modifier\n" "Address family modifier\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 (0, 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 (0, 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 (0, clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " 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 inbound and outbound updates\n" "Send route-refresh unless using 'soft-reconfiguration inbound'\n") DEFSH (0, no_debug_zebra_rib_cmd_vtysh, "no debug zebra rib", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug zebra RIB\n") DEFSH (0, 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" "Resend all outbound updates\n") DEFSH (0, ip_ospf_area_cmd_vtysh, "ip ospf area (A.B.C.D|<0-4294967295>) [A.B.C.D]", "IP Information\n" "OSPF interface commands\n" "Enable OSPF on this interface\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Address of interface\n") DEFSH (0, link_params_delay_mm_cmd_vtysh, "delay <0-16777215> min <0-16777215> max <0-16777215>", "Unidirectional Average Link Delay (optionally Minimum and Maximum delays)\n" "Average delay in micro-second as decimal (0...16777215)\n" "Minimum delay\n" "Minimum delay in micro-second as decimal (0...16777215)\n" "Maximum delay\n" "Maximum delay in micro-second as decimal (0...16777215)\n") DEFSH (0, ipv6_nd_other_config_flag_cmd_vtysh, "ipv6 nd other-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Other statefull configuration flag\n") DEFSH (0, debug_pim_packetdump_recv_cmd_vtysh, "debug pim packet-dump receive", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump received packets\n") DEFSH (0, no_ipv6_route_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 (0, 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 inbound and outbound updates\n" "Resend all outbound updates\n") void test_init_cmd (void) { install_element (CONFIG_NODE, &ip_route_mask_tag_vrf_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_message_sendrecv_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_vrf_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_in_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_tags_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_lcommunity3_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_filter_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_remark_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_nsm_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_regexp_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_pim_drprio_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh); install_element (ISIS_NODE, &no_net_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &no_terminal_monitor_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_cmd_vtysh); install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community2_cmd_vtysh); install_element (BGP_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rpf_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_exact_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh); install_element (RMAP_NODE, &set_atomic_aggregate_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_router_detail_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_brouter_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (ISIS_NODE, &metric_style_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (RMAP_NODE, &no_match_interface_cmd_vtysh); install_element (RMAP_NODE, &no_set_weight_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd_vtysh); install_element (RMAP_NODE, &rmap_continue_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_out_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community_exact_cmd_vtysh); install_element (INTERFACE_NODE, &if_no_nhrp_network_id_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_tag_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd_vtysh); install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_enable_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ripng_events_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_interface_cmd_vtysh); install_element (BGP_NODE, &bgp_graceful_restart_restart_time_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_flap_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rd_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_set_weight_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_timers_throttle_spf_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_distance_ospf6_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_route_source_cmd_vtysh); install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_maxpaths_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_rip_packet_cmd_vtysh); install_element (OSPF_NODE, &pce_domain_cmd_vtysh); install_element (CONFIG_NODE, &ip_multicast_routing_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_regexp_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd_vtysh); install_element (RMAP_NODE, &no_set_src_cmd_vtysh); install_element (CONFIG_NODE, &debug_igmp_trace_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags2_tag_vrf_cmd_vtysh); install_element (RMAP_NODE, &set_local_pref_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd_vtysh); install_element (ENABLE_NODE, &debug_rip_packet_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_bgp_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_summary_cmd_vtysh); install_element (INTERFACE_NODE, &no_tunnel_source_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_pref_vrf_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (VIEW_NODE, &show_database_detail_arg_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_rib_q_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community2_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_router_id_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_lcommunity_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_lcommunity4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &no_router_id_vrf_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_zebra_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_pathtype_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_cmd_vtysh); install_element (RMAP_NODE, &no_set_metric_type_cmd_vtysh); install_element (CONFIG_NODE, &no_key_chain_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh); install_element (RIPNG_NODE, &ripng_redistribute_type_metric_routemap_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_shutdown_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd_vtysh); install_element (VIEW_NODE, &show_isis_neighbor_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_lcommunity3_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_multicast_mode_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_any_host_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_interval_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_inter_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (INTERFACE_NODE, &if_nhrp_reg_flags_cmd_vtysh); install_element (CONFIG_NODE, &no_bgp_config_type_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_intra_external_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_regexp_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_allow_martians_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_admin_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd_vtysh); install_element (ENABLE_NODE, &rmap_show_name_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_interface_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_tag_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_router_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity4_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (RMAP_NODE, &no_set_ip_nexthop_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_timers_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh); install_element (RMAP_NODE, &no_set_local_pref_cmd_vtysh); install_element (VTY_NODE, &vty_ipv6_access_class_cmd_vtysh); install_element (VIEW_NODE, &show_isis_neighbor_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ripng_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_rib_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &nhrp_nflog_group_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_priority_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_statistics_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_routes_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd_vtysh); install_element (BGP_NODE, &neighbor_filter_list_cmd_vtysh); install_element (BGP_NODE, &no_bgp_distance_source_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_tag_vrf_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity3_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (VIEW_NODE, &show_database_cmd_vtysh); install_element (OSPF_NODE, &pce_neighbor_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_dampened_paths_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_spfstats_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_zebra_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_all_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (RMAP_NODE, &set_lcommunity_delete_cmd_vtysh); install_element (VIEW_NODE, &show_isis_interface_arg_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_param1_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_community_list_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_igmp_events_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_network_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_querier_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_vrf_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_mroute_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_exact_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community4_exact_cmd_vtysh); install_element (RMAP_NODE, &no_match_lcommunity_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (RIP_NODE, &no_rip_neighbor_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_cost_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_addr_cmd_vtysh); install_element (RIPNG_NODE, &ripng_aggregate_address_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (CONFIG_NODE, &default_linkdetect_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (RMAP_NODE, &no_set_originator_id_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community4_exact_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_packet_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_addr_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd_vtysh); install_element (RMAP_NODE, &set_lcommunity_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rip_status_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_routes_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_pim_hello_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_fsm_cmd_vtysh); install_element (VIEW_NODE, &show_ip_multicast_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community4_exact_cmd_vtysh); install_element (BGP_NODE, &no_bgp_graceful_restart_restart_time_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (BGP_NODE, &neighbor_passive_cmd_vtysh); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (CONFIG_NODE, &no_router_rip_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd_vtysh); install_element (INTERFACE_NODE, &isis_circuit_type_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_poll_interval_priority_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_use_bw_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_router_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_lcommunity_cmd_vtysh); install_element (CONFIG_NODE, &access_list_standard_any_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_prefix_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_priority_poll_interval_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_interface_area_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_memory_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_route_map_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_rsclient_cmd_vtysh); install_element (BGP_NODE, &bgp_log_neighbor_changes_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_vrf_all_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd_vtysh); install_element (BGP_NODE, &no_bgp_maxpaths_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_timers_cmd_vtysh); install_element (ENABLE_NODE, &debug_ripng_packet_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_param4_cmd_vtysh); install_element (RMAP_NODE, &set_src_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_backdoor_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd_vtysh); install_element (RMAP_NODE, &set_aggregator_as_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd_vtysh); install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity3_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_lsp_sched_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_vrf_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_abr_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_regexp_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_authentication_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_route_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_message_sendrecv_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_summary_only_cmd_vtysh); install_element (INTERFACE_NODE, &no_multicast_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_unset2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_tags_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_stub_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_dead_interval_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd_vtysh); install_element (ISIS_NODE, &isis_default_originate_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_mroute_source_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_standard_all_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_NODE, &neighbor_timers_connect_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_route_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_NODE, &bgp_network_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_lcommunity2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_mtu_ignore_addr_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_any_any_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_delay_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (ISIS_NODE, &no_set_attached_bit_cmd_vtysh); install_element (RMAP_NODE, &set_origin_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (CONFIG_NODE, &dump_bgp_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd_vtysh); install_element (OSPF_NODE, &ospf_timers_throttle_spf_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd_vtysh); install_element (INTERFACE_NODE, &shutdown_if_cmd_vtysh); install_element (RIP_NODE, &rip_distance_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_in_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_passwd_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_offset_list_ifname_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_adv_router_detail_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_longer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_lcommunity_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_tags_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh); install_element (RMAP_NODE, &match_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_lsp_sched_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_err_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_igmp_events_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd_vtysh); install_element (ISIS_NODE, &set_attached_bit_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_maxpaths_cmd_vtysh); install_element (BGP_NODE, &no_bgp_graceful_restart_restart_time_val_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_te_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_out_cmd_vtysh); install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd_vtysh); install_element (OSPF_NODE, &no_capability_opaque_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_l1_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_interface_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd_vtysh); install_element (BGP_NODE, &no_synchronization_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd_vtysh); install_element (CONFIG_NODE, &access_list_standard_nomask_cmd_vtysh); install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community2_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance2_cmd_vtysh); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_admin_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_router_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh); install_element (VIEW_NODE, &show_ip_forwarding_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh); install_element (CONFIG_NODE, &bgp_multiple_instance_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_val_cmd_vtysh); install_element (ISIS_NODE, &no_isis_mpls_te_on_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_detail_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_dampened_paths_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_damp_set2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rib_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_views_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_tag_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_access_list_cmd_vtysh); install_element (RMAP_NODE, &no_set_tag_val_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_cmd_vtysh); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &undebug_igmp_packets_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_nssa_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_import_check_cmd_vtysh); install_element (VIEW_NODE, &show_isis_mpls_te_interface_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd_vtysh); install_element (ISIS_NODE, &lsp_refresh_interval_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd_vtysh); install_element (ENABLE_NODE, &clear_ipv6_ospf6_interface_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_packets_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_trace_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_cmd_vtysh); install_element (RMAP_NODE, &no_set_metric_addsub_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_damp_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_cmd_vtysh); install_element (RIPNG_NODE, &if_ipv6_rmap_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &ip_mroute_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_access_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_vrf_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity4_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_NODE, &no_bgp_cluster_id_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_zebra_cmd_vtysh); install_element (ISIS_NODE, &no_isis_default_originate_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd_vtysh); install_element (VIEW_NODE, &show_isis_neighbor_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_router_detail_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_igmp_trace_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_tag_distance_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_cost_u32_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_routes_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_external_intra_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_prefix_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_pathtype_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd_vtysh); install_element (BGP_NODE, &no_bgp_log_neighbor_changes_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_med2_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_route_map_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_addr_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_neighbor_advertised_routes_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_vrf_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_cmd_vtysh); install_element (INTERFACE_NODE, &tunnel_protection_cmd_vtysh); install_element (BGP_NODE, &bgp_fast_external_failover_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_message_cmd_vtysh); install_element (OSPF_NODE, &router_info_area_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_cmd_vtysh); install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_events_cmd_vtysh); install_element (RMAP_NODE, &no_set_lcommunity_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_route_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_admin_grp_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_all_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd_vtysh); install_element (VIEW_NODE, &show_isis_interface_detail_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_all_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_upcall_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_kernel_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_lcommunity_all_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_unset_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd_vtysh); install_element (KEYCHAIN_NODE, &no_key_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community4_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_address_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_update_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_match_ipv6_address_cmd_vtysh); install_element (VIEW_NODE, &show_zebra_cmd_vtysh); install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_authentication_mode_authlen_cmd_vtysh); install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_csum_cmd_vtysh); install_element (RIP_NODE, &no_rip_default_information_originate_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_rip_packet_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_export_list_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_tag_vrf_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh); install_element (OSPF_NODE, &no_pce_domain_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd_vtysh); install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd_vtysh); install_element (RMAP_NODE, &set_metric_rtt_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (RIP_NODE, &no_rip_route_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_interface_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_nhrp_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_passive_interface_addr_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_mpls_te_router_cmd_vtysh); install_element (RMAP_NODE, &no_match_ipv6_address_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community4_cmd_vtysh); install_element (OSPF_NODE, &no_router_info_cmd_vtysh); install_element (RMAP_NODE, &no_match_interface_val_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_route_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_dampened_paths_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_cmd_vtysh); install_element (BGP_NODE, &no_bgp_confederation_peers_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_received_routes_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd_vtysh); install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_vrf_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (BGP_NODE, &neighbor_ttl_security_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_adv_router_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_lsa_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd_vtysh); install_element (VIEW_NODE, &show_interface_vrf_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_igmp_packets_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_events_cmd_vtysh); install_element (ISIS_NODE, &spf_interval_l1_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_cmd_vtysh); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_startup_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_param3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_interface_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd_vtysh); install_element (INTERFACE_NODE, &csnp_interval_l2_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_distance_vrf_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_activate_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (CONFIG_NODE, &config_table_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_description_val_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd_vtysh); install_element (OSPF6_NODE, &area_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_cmd_vtysh); install_element (OSPF_NODE, &ospf_distance_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_mtu_ignore_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_paths_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_vrf_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_rtevents_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh); install_element (VIEW_NODE, &show_interface_vrf_all_cmd_vtysh); install_element (RMAP_NODE, &no_set_aspath_exclude_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_memory_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_stub_no_summary_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_advertise_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_as4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &ip_address_label_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_distance_cmd_vtysh); install_element (VIEW_NODE, &show_isis_topology_l1_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_preference_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_delay_var_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_cmd_vtysh); install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rd_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd_vtysh); install_element (RIP_NODE, &no_rip_default_metric_val_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_flooding_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_route_map_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_next_hop_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd_vtysh); install_element (RMAP_NODE, &match_ipv6_next_hop_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd_vtysh); install_element (CONFIG_NODE, &ip_mroute_dist_vrf_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd_vtysh); install_element (OSPF_NODE, &ospf_passive_interface_addr_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_standard2_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_refresh_timer_cmd_vtysh); install_element (RMAP_NODE, &match_lcommunity_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_source_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_tag_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_cost_u32_inet4_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbors_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_tags_cmd_vtysh); install_element (RMAP_NODE, &match_ip_next_hop_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (RMAP_NODE, &no_match_origin_val_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (RMAP_NODE, &no_set_tag_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_asbr_cmd_vtysh); install_element (INTERFACE_NODE, &isis_priority_l2_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_lupd_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_summary_cmd_vtysh); install_element (VIEW_NODE, &show_database_arg_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_longer_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_adv_router_linkstate_id_cmd_vtysh); install_element (ENABLE_NODE, &show_dmvpn_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd_vtysh); install_element (BGP_NODE, &neighbor_strict_capability_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_source_access_list_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_distance_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_packets_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_args_addr_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_packets_filter_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (BGP_NODE, &neighbor_interface_cmd_vtysh); install_element (ENABLE_NODE, &undebug_igmp_cmd_vtysh); install_element (CONFIG_NODE, &debug_ripng_events_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_seconds_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd_vtysh); install_element (CONFIG_NODE, &access_list_standard_cmd_vtysh); install_element (RMAP_NODE, &set_community_none_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_longer_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity2_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_lan_prune_delay_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_statistics_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_lupd_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_packets_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_redistribute_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_dmvpn_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_trace_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd_vtysh); install_element (CONFIG_NODE, &debug_rip_zebra_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_route_map_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_out_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_routes_cmd_vtysh); install_element (BGP_NODE, &neighbor_local_as_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_poisoned_reverse_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_NODE, &bgp_router_id_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (VTY_NODE, &exec_timeout_min_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_neighbor_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_ibgp_arg_cmd_vtysh); install_element (VTY_NODE, &exec_timeout_sec_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_debug_packet_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_none_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd_vtysh); install_element (VTY_NODE, &no_vty_login_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (VTY_NODE, &vty_no_restricted_mode_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_pref_vrf_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_tag_vrf_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_cmd_vtysh); install_element (RMAP_NODE, &set_ip_nexthop_cmd_vtysh); install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_join_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd_vtysh); install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_rpf_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_tag_distance_vrf_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_linkstate_id_cmd_vtysh); install_element (RMAP_NODE, &match_metric_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_tag_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd_vtysh); install_element (CONFIG_NODE, &log_commands_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_groups_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_startup_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_exact_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd_vtysh); install_element (ISIS_NODE, &no_set_overload_bit_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (RMAP_NODE, &match_interface_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_passive_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd_vtysh); install_element (CONFIG_NODE, &undebug_ssmpingd_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_prefix_vrf_all_cmd_vtysh); install_element (OSPF_NODE, &ospf_log_adjacency_changes_detail_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_upd_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_packets_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rd_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_out_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_detail_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_split_horizon_poisoned_reverse_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_shutdown_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_te_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_l2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_set_lcommunity_delete_val_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_delay_var_cmd_vtysh); install_element (CONFIG_NODE, &no_nhrp_nflog_group_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_out_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity2_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community2_exact_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_zebra_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_delete_val_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_ism_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_router_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_distance_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_authkey_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &debug_nhrp_cmd_vtysh); install_element (RIP_NODE, &no_if_rmap_cmd_vtysh); install_element (CONFIG_NODE, &no_service_advanced_vty_cmd_vtysh); install_element (RIPNG_NODE, &ripng_network_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_rip_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community3_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_ospf_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_nhrp_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_arg_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_damp_dampened_paths_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_nht_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_spfevents_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_description_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd_vtysh); install_element (VIEW_NODE, &show_database_arg_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_route_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (OSPF_NODE, &ospf_timers_min_ls_arrival_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_enable_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community3_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_addr_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_passive_interface_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh); install_element (VTY_NODE, &vty_access_class_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd_vtysh); install_element (RIP_NODE, &no_rip_timers_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_route_cmd_vtysh); install_element (BGP_NODE, &neighbor_timers_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_events_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd_vtysh); install_element (BGP_NODE, &bgp_rr_allow_outbound_policy_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community2_exact_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_pref_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_tag_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_stub_no_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_intra_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community2_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_export_list_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_authentication_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community4_exact_cmd_vtysh); install_element (BGP_NODE, &neighbor_password_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_detail_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_vrf_all_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_shortcut_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_out_cmd_vtysh); install_element (CONFIG_NODE, &debug_mroute_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_router_detail_cmd_vtysh); install_element (INTERFACE_NODE, &isis_metric_l2_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ssmpingd_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_access_list_cmd_vtysh); install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd_vtysh); install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ripng_events_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &debug_ripng_events_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_res_bw_cmd_vtysh); install_element (INTERFACE_NODE, &bandwidth_if_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_authentication_key_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh); install_element (OSPF6_NODE, &no_area_range_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_flooding_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh); install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_neighbor_routes_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_packet_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_csum_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_advertise_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_not_advertise_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community3_exact_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &undebug_igmp_trace_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_forwarding_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd_vtysh); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_shutdown_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_nssa_cmd_vtysh); install_element (RMAP_NODE, &no_match_probability_val_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (CONFIG_NODE, &access_list_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_as4_segment_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd_vtysh); install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_inter_as_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_neighbor_advertised_routes_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_igmp_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_vrf_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd_vtysh); install_element (CONFIG_NODE, &ip_ssmpingd_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &csnp_interval_l1_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_packetdump_recv_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_encap_summary_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd_vtysh); install_element (VIEW_NODE, &show_hostname_cmd_vtysh); install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_in_cmd_vtysh); install_element (CONFIG_NODE, &no_route_map_cmd_vtysh); install_element (OSPF_NODE, &router_info_as_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags2_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_vrf_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags2_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_distance_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_normal_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_cmd_vtysh); install_element (RMAP_NODE, &no_match_community_cmd_vtysh); install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_name_standard_all_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_pref_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_pathtype_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_distance_vrf_cmd_vtysh); install_element (RMAP_NODE, &no_match_tag_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_pathtype_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd_vtysh); install_element (OSPF_NODE, &ospf_auto_cost_reference_bandwidth_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_all_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_external_cmd_vtysh); install_element (RMAP_NODE, &rmap_continue_index_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_damp_set_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_regexp_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_timers_connect_cmd_vtysh); install_element (INTERFACE_NODE, &linkdetect_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd_vtysh); install_element (INTERFACE_NODE, &if_no_nhrp_flags_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_network_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd_vtysh); install_element (BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd_vtysh); install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_assert_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_zebra_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_route_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_cmd_vtysh); install_element (RMAP_NODE, &no_match_aspath_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ripng_zebra_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_brouter_router_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh); install_element (RMAP_NODE, &no_match_metric_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_vrf_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ssmpingd_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_standard_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (ENABLE_NODE, &show_zebra_client_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community_exact_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (ISIS_NODE, &max_lsp_lifetime_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_snp_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_spfstats_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_authkey_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_tag_vrf_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_authlen_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_maxpaths_ibgp_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_send_community_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_encap_summary_cmd_vtysh); install_element (RMAP_NODE, &no_match_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_distance_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_dampened_paths_cmd_vtysh); install_element (BGP_NODE, &neighbor_activate_cmd_vtysh); install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_lsa_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_mroute_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community3_exact_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_neighbor_cmd_vtysh); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh); install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_vrf_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (RMAP_NODE, &no_match_local_pref_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_longer_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd_vtysh); install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community4_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_admin_grp_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_address_cmd_vtysh); install_element (RMAP_NODE, &no_match_peer_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_prefix_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_spftrigg_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community3_cmd_vtysh); install_element (BGP_NODE, &neighbor_description_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_vrf_cmd_vtysh); install_element (CONFIG_NODE, &access_list_any_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_res_bw_cmd_vtysh); install_element (RIP_NODE, &if_rmap_cmd_vtysh); install_element (BGP_NODE, &neighbor_remote_as_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_nexthop_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_adv_router_linkstate_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_isis_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_fpm_cmd_vtysh); install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_upd_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_vrf_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_zebra_sendrecv_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_send_community_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_prefix_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_inter_as_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_ifmtu_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_route_map_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_expanded_all_cmd_vtysh); install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_neighbor_cmd_vtysh); install_element (CONFIG_NODE, &undebug_igmp_packets_cmd_vtysh); install_element (OSPF_NODE, &ospf_mpls_te_inter_as_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community3_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_cost_inet4_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_update_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_vrf_cmd_vtysh); install_element (BGP_NODE, &neighbor_default_originate_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd_vtysh); install_element (BGP_NODE, &neighbor_enforce_multihop_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_debug_messages_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_tags_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd_vtysh); install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd_vtysh); install_element (CONFIG_NODE, &no_router_ospf6_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (OSPF_NODE, &pce_cap_flag_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_prefix_longer_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rpf_addr_vrf_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_zebra_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd_vtysh); install_element (VIEW_NODE, &show_interface_name_vrf_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_distance2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_cost_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_interface_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd_vtysh); install_element (BGP_NODE, &bgp_confederation_identifier_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd_vtysh); install_element (BGP_NODE, &no_bgp_router_id_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_forwarding_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_events_cmd_vtysh); install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd_vtysh); install_element (VIEW_NODE, &clear_isis_neighbor_arg_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_filter_list_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_mpls_te_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags2_vrf_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_weight_val_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_tags_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_allow_martians_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (OSPF6_NODE, &area_export_list_cmd_vtysh); install_element (CONFIG_NODE, &router_id_vrf_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_brouter_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_expanded_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_nhrp_cmd_vtysh); install_element (RMAP_NODE, &no_set_aggregator_as_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_arg_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity4_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_err_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_as4_segment_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_NODE, &neighbor_capability_dynamic_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_flooding_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (ISIS_NODE, &area_lsp_mtu_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_prefix_pathtype_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (CONFIG_NODE, &access_list_exact_cmd_vtysh); install_element (RIP_NODE, &rip_redistribute_type_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (INTERFACE_NODE, &isis_passive_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_nssa_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_exact_cmd_vtysh); install_element (ISIS_NODE, &no_is_type_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_normal_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_cidr_only_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_route_map_cmd_vtysh); install_element (RIP_NODE, &rip_distance_source_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_router_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_rip_events_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd_vtysh); install_element (OSPF_NODE, &ospf_mpls_te_router_addr_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_tag_distance_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_offset_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_trace_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd_vtysh); install_element (RIP_NODE, &no_rip_allow_ecmp_cmd_vtysh); install_element (CONFIG_NODE, &ip_protocol_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (BGP_NODE, &no_bgp_timers_arg_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_aspath_confed_cmd_vtysh); install_element (VTY_NODE, &vty_login_cmd_vtysh); install_element (RIPNG_NODE, &ripng_redistribute_type_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_network_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_spfevents_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_router_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_vrf_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_zebra_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_address_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_distance2_vrf_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_safi_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_afi_safi_view_cmd_vtysh); install_element (RIP_NODE, &rip_allow_ecmp_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_router_isis_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_statistics_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd_vtysh); install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_aspath_multipath_relax_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_interface_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd_vtysh); install_element (ISIS_NODE, &no_area_lsp_mtu_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd_vtysh); install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (RMAP_NODE, &no_set_lcommunity_val_cmd_vtysh); install_element (INTERFACE_NODE, &isis_priority_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (RIP_NODE, &no_rip_network_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_zebra_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_address_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_encap_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_list_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_pathtype_cmd_vtysh); install_element (RIPNG_NODE, &ripng_offset_list_ifname_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_router_info_pce_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd_vtysh); install_element (OSPF_NODE, &ospf_router_id_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_upd_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_abr_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd_vtysh); install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rd_route_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_route_map_cmd_vtysh); install_element (RMAP_NODE, &set_ecommunity_rt_cmd_vtysh); install_element (ISIS_NODE, &no_area_passwd_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_flap_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_statistics_cmd_vtysh); install_element (CONFIG_NODE, &vrf_netns_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_prefix_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_all_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community2_exact_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_mpls_te_link_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_vrf_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_irdp_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_mroute_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_debug_misc_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd_vtysh); install_element (RIP_NODE, &rip_default_information_originate_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd_vtysh); install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd_vtysh); install_element (INTERFACE_NODE, &no_bandwidth_if_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_host_host_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_as4_segment_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd_vtysh); install_element (RIP_NODE, &rip_timers_cmd_vtysh); install_element (VIEW_NODE, &show_ip_protocol_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd_vtysh); install_element (RMAP_NODE, &no_match_metric_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_vrf_all_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_pathtype_cmd_vtysh); install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_jp_override_interval_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_as4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_tag_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_password_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_aspath_confed_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_address_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_router_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh); install_element (ENABLE_NODE, &debug_rip_events_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_mpls_te_inter_as_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv4_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_set_local_pref_val_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_protocol_cmd_vtysh); install_element (RMAP_NODE, &set_metric_addsub_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_cmd_vtysh); install_element (VIEW_NODE, &show_ip_mroute_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_description_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (RIP_NODE, &rip_distance_source_access_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_route_map_all_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_as_path_all_cmd_vtysh); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd_vtysh); install_element (RMAP_NODE, &no_set_aspath_prepend_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh); install_element (ISIS_NODE, &no_isis_mpls_te_inter_as_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_static_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_summary_vrf_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (ISIS_NODE, &log_adj_changes_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_authkey_cmd_vtysh); install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_protocol_vrf_all_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_zebra_cmd_vtysh); install_element (ISIS_NODE, &area_passwd_clear_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_pkt_loss_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_args_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (ISIS_NODE, &no_metric_style_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_ava_bw_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh); install_element (CONFIG_NODE, &debug_ripng_packet_cmd_vtysh); install_element (BGP_NODE, &no_bgp_distance_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_packetdump_send_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd_vtysh); install_element (ENABLE_NODE, &test_igmp_receive_report_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mroute_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_linkstate_id_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh); install_element (ISIS_NODE, &spf_interval_l2_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_asbr_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_stub_router_admin_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_events_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd_vtysh); install_element (OSPF_NODE, &ospf_timers_min_ls_interval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_neighbor_advertised_routes_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_distance_vrf_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv4_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_ism_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_distance2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_route_pathtype_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_message_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_any_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_damp_set3_cmd_vtysh); install_element (ISIS_NODE, &no_area_lsp_mtu_arg_cmd_vtysh); install_element (VIEW_NODE, &show_database_detail_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd_vtysh); install_element (ISIS_NODE, &dynamic_hostname_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_pkt_loss_cmd_vtysh); install_element (CONFIG_NODE, &debug_ripng_zebra_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_lcommunity4_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ripng_packet_cmd_vtysh); install_element (RIP_NODE, &rip_route_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community_list_exact_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_metric_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_tag_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_allow_martians_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_event_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd_vtysh); install_element (RIPNG_NODE, &ripng_passive_interface_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_regexp_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd_vtysh); install_element (BGP_NODE, &bgp_timers_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_intra_inter_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_strict_capability_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (OSPF_NODE, &pce_path_scope_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_import_list_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_exact_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_spfevents_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_summary_vrf_all_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_area_cmd_vtysh); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_tag_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_cmd_vtysh); install_element (ENABLE_NODE, &show_zebra_client_summary_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_redistribute_cmd_vtysh); install_element (RMAP_NODE, &set_tag_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_advertised_route_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_standard_any_cmd_vtysh); install_element (CONFIG_NODE, &nhrp_event_socket_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_zebra_cmd_vtysh); install_element (ISIS_NODE, &spf_interval_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rpf_addr_vrf_all_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd_vtysh); install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd_vtysh); install_element (CONFIG_NODE, &undebug_igmp_trace_cmd_vtysh); install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_tag_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_neighbor_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_as4_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_prefix_vrf_cmd_vtysh); install_element (OSPF_NODE, &ospf_abr_type_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_events_cmd_vtysh); install_element (OSPF6_NODE, &no_area_export_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_prefix_longer_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd_vtysh); install_element (INTERFACE_NODE, &if_nhrp_network_id_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd_vtysh); install_element (CONFIG_NODE, &router_id_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_advertised_routes_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_distance_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_arg_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_exact_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_cmd_vtysh); install_element (VIEW_NODE, &show_interface_name_cmd_vtysh); install_element (RIP_NODE, &rip_redistribute_type_metric_routemap_cmd_vtysh); install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_authkey_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_interface_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_damp_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_damp_flap_prefix_longer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd_vtysh); install_element (VIEW_NODE, &show_interface_name_vrf_all_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh); install_element (VTY_NODE, &no_exec_timeout_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_local_as_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_event_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_trace_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_filter_list_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rpf_vrf_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_join_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_routemap_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_router_info_cmd_vtysh); install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd_vtysh); install_element (CONFIG_NODE, &ip_mroute_dist_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd_vtysh); install_element (OSPF_NODE, &ospf_distribute_list_out_cmd_vtysh); install_element (ENABLE_NODE, &clear_nhrp_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_stub_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_spfstats_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity4_cmd_vtysh); install_element (RMAP_NODE, &match_aspath_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_priority_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_as_path_cmd_vtysh); install_element (RIPNG_NODE, &ripng_timers_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_zebra_sendrecv_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_shortcut_cmd_vtysh); install_element (BGP_NODE, &neighbor_override_capability_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd_vtysh); install_element (RMAP_NODE, &match_probability_cmd_vtysh); install_element (OSPF_NODE, &capability_opaque_cmd_vtysh); install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_packet_dump_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd_vtysh); install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_vrf_cmd_vtysh); install_element (RMAP_NODE, &match_ipv6_address_cmd_vtysh); install_element (CONFIG_NODE, &ip_mroute_vrf_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_adj_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd_vtysh); install_element (RMAP_NODE, &set_aspath_prepend_lastas_cmd_vtysh); install_element (CONFIG_NODE, &no_vrf_netns_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_prefix_longer_vrf_all_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd_vtysh); install_element (ENABLE_NODE, &undebug_ssmpingd_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ripng_packet_cmd_vtysh); install_element (OSPF6_NODE, &no_area_import_list_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_distance_source_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_events_cmd_vtysh); install_element (RIP_NODE, &rip_passive_interface_cmd_vtysh); install_element (BGP_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd_vtysh); install_element (RMAP_NODE, &no_match_probability_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_prefix_cmd_vtysh); install_element (RMAP_NODE, &set_aspath_exclude_cmd_vtysh); install_element (BGP_NODE, &neighbor_update_source_cmd_vtysh); install_element (RIP_NODE, &no_rip_version_val_cmd_vtysh); install_element (ENABLE_NODE, &debug_rip_zebra_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh); install_element (OSPF6_NODE, &area_range_advertise_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_inter_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd_vtysh); install_element (RMAP_NODE, &rmap_onmatch_goto_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_lsp_sched_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_route_map_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_cmd_vtysh); install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd_vtysh); install_element (RIPNG_NODE, &ripng_offset_list_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_med3_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_distance_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_vrf_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_vrf_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_pim_hello_hold_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_timers_min_ls_arrival_cmd_vtysh); install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_param4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_inter_intra_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_tags_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_pathtype_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_advertise_cost_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (RIP_NODE, &rip_neighbor_cmd_vtysh); install_element (INTERFACE_NODE, &if_no_nhrp_map_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ripng_packet_direct_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_route_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_summary_vrf_all_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_events_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_nexthop_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_zebra_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (RMAP_NODE, &set_metric_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_distance_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_spftrigg_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_multicast_mode_noarg_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_forwarding_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_packets_filter_cmd_vtysh); install_element (ENABLE_NODE, &debug_ssmpingd_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd_vtysh); install_element (BGP_NODE, &bgp_distance_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_pim_drprio_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_delay_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_cidr_only_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (BGP_NODE, &no_bgp_always_compare_med_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_route_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_tag_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (CONFIG_NODE, &debug_nhrp_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_supernets_vrf_all_cmd_vtysh); install_element (INTERFACE_NODE, &tunnel_source_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_poll_interval_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh); install_element (BGP_NODE, &bgp_graceful_restart_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_update_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_set3_cmd_vtysh); install_element (RIP_NODE, &rip_redistribute_type_metric_cmd_vtysh); install_element (CONFIG_NODE, &ip_multicast_mode_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_in_cmd_vtysh); install_element (RMAP_NODE, &no_match_community_val_cmd_vtysh); install_element (VIEW_NODE, &show_debugging_zebra_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_maxbw_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (RIP_NODE, &no_rip_redistribute_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rd_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (RIPNG_NODE, &ripng_route_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_advertise_cost_cmd_vtysh); install_element (RMAP_NODE, &no_set_lcommunity_none_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_addr_vrf_all_cmd_vtysh); install_element (ISIS_NODE, &area_passwd_md5_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_pim_ssm_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_rd_route_cmd_vtysh); install_element (RMAP_NODE, &match_peer_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_md5_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_delay_mm_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community_exact_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_list_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_mtu_ignore_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mroute_vrf_all_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_packets_filter_cmd_vtysh); install_element (VIEW_NODE, &show_version_ospf6_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_NODE, &no_bgp_maxpaths_arg_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_irdp_address_preference_cmd_vtysh); install_element (CONFIG_NODE, &no_dump_bgp_all_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd_vtysh); install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_zebra_cmd_vtysh); install_element (CONFIG_NODE, &undebug_igmp_events_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (INTERFACE_NODE, &ip_address_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_source_access_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_prefix_pathtype_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_pref_tag_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity4_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_pref_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_exact_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_hello_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_fsm_cmd_vtysh); install_element (CONFIG_NODE, &debug_ssmpingd_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_ttl_security_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_distance_vrf_cmd_vtysh); install_element (RIP_NODE, &no_rip_passive_interface_cmd_vtysh); install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_external_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_upd_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_peer_group_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_igmp_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_vpn_rd_route_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh); install_element (OSPF_NODE, &ospf_passive_interface_default_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_timers_val_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_send_community_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_md5_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (RMAP_NODE, &no_set_metric_cmd_vtysh); install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_detail_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_prefix_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_packets_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community4_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_param1_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_hello_interval_cmd_vtysh); install_element (INTERFACE_NODE, &if_nhrp_mtu_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_cmd_vtysh); install_element (BGP_NODE, &neighbor_shutdown_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_statistics_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_received_routes_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_local_as_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_split_horizon_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_pref_tag_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_bgp_distance_source_access_list_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_redistribute_type_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_nht_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_filter_list_cmd_vtysh); install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd_vtysh); install_element (RMAP_NODE, &match_community_cmd_vtysh); install_element (BGP_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community_exact_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_pim_hello_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_events_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_in_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_flooding_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_pathtype_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_cmd_vtysh); install_element (VIEW_NODE, &show_isis_topology_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_substitute_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_lcommunity_all_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_tag_vrf_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_shutdown_if_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_adv_router_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_distance2_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd_vtysh); install_element (CONFIG_NODE, &debug_rip_events_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_tag_vrf_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd_vtysh); install_element (BGP_NODE, &bgp_maxpaths_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_all_cmd_vtysh); install_element (CONFIG_NODE, &debug_rip_packet_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_disable_connected_check_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_supernets_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_weight_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_static_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd_vtysh); install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_as4_segment_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_regexp_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd_vtysh); install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (CONFIG_NODE, &debug_static_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_lcommunity2_cmd_vtysh); install_element (RMAP_NODE, &set_aspath_prepend_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd_vtysh); install_element (RMAP_NODE, &no_set_origin_val_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_event_cmd_vtysh); install_element (BGP_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_local_as_val3_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rd_route_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_igmp_trace_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_lupd_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd_vtysh); install_element (RMAP_NODE, &match_origin_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (INTERFACE_NODE, &if_nhrp_nhs_cmd_vtysh); install_element (INTERFACE_NODE, &isis_network_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd_vtysh); install_element (RMAP_NODE, &no_match_peer_val_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_summary_prefix_vrf_cmd_vtysh); install_element (CONFIG_NODE, &ip_lcommunity_list_standard2_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_call_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_fpm_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_route_map_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_route_pathtype_cmd_vtysh); install_element (CONFIG_NODE, &debug_igmp_events_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_cost_inet4_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_assert_cmd_vtysh); install_element (INTERFACE_NODE, &multicast_cmd_vtysh); install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_all_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd_vtysh); install_element (BGP_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community4_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd_vtysh); install_element (OSPF6_NODE, &area_range_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_mroute_dist_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd_vtysh); install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_views_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ripng_zebra_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd_vtysh); install_element (RMAP_NODE, &match_ip_address_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_table_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_intra_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community2_cmd_vtysh); install_element (INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (INTERFACE_NODE, &isis_metric_l1_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_external_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_prefix_vrf_all_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (ENABLE_NODE, &undebug_igmp_events_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_self_originated_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_vrf_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_encap_network_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_md5_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_exact_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community2_exact_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authkey_cmd_vtysh); install_element (OSPF_NODE, &ospf_default_metric_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_forwarding_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_as4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_paths_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_log_adjacency_changes_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (BGP_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_tag_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_events_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_lsp_gen_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags2_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_prefix_cmd_vtysh); install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd_vtysh); install_element (BGP_NODE, &no_bgp_rr_allow_outbound_policy_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_remote_as_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_tags_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_vrf_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_nht_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_detail_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_packets_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_ospf_interface_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_cmd_vtysh); install_element (BGP_NODE, &neighbor_advertise_interval_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_zebra_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_mroute_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh); install_element (RIP_NODE, &rip_offset_list_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_secondary_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd_vtysh); install_element (BGP_NODE, &neighbor_route_map_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_route_cmd_vtysh); install_element (ENABLE_NODE, &debug_ripng_zebra_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_csum_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_nssa_no_summary_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity4_cmd_vtysh); install_element (INTERFACE_NODE, &isis_priority_l1_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_area_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community4_cmd_vtysh); install_element (CONFIG_NODE, &bgp_config_type_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); install_element (CONFIG_NODE, &no_nhrp_event_socket_cmd_vtysh); install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_tag_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_network_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (VIEW_NODE, &clear_isis_neighbor_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_nssa_cmd_vtysh); install_element (OSPF_NODE, &ospf_redistribute_source_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_rsclient_route_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (ISIS_NODE, &is_type_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_exact_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_detail_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_pathtype_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_fpm_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_cmd_vtysh); install_element (OSPF_NODE, &ospf_mpls_te_on_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (RMAP_NODE, &match_ip_route_source_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd_vtysh); install_element (RMAP_NODE, &rmap_description_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd_vtysh); install_element (OSPF_NODE, &ospf_network_area_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (LINK_PARAMS_NODE, &link_params_ava_bw_cmd_vtysh); install_element (RMAP_NODE, &rmap_call_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_linkstate_id_detail_cmd_vtysh); install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_received_prefix_filter_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_cost_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_standard_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_cmd_vtysh); install_element (RMAP_NODE, &match_tag_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_lcommunity2_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (RIP_NODE, &no_rip_default_metric_cmd_vtysh); install_element (CONFIG_NODE, &no_router_id_cmd_vtysh); install_element (BGP_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_broadcast_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd_vtysh); install_element (INTERFACE_NODE, &psnp_interval_l2_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_default_metric_cmd_vtysh); install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_param3_cmd_vtysh); install_element (CONFIG_NODE, &fpm_remote_ip_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd_vtysh); install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_route_cmd_vtysh); install_element (CONFIG_NODE, &ip_as_path_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (BGP_NODE, &no_auto_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_self_originated_detail_cmd_vtysh); install_element (ISIS_NODE, &set_overload_bit_cmd_vtysh); install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_list_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_arg_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_prefix_cmd_vtysh); install_element (RMAP_NODE, &match_local_pref_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_spftrigg_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community3_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd_vtysh); install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_events_cmd_vtysh); install_element (OSPF_NODE, &ospf_default_information_originate_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_nhrp_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd_vtysh); install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_route_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_import_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (CONFIG_NODE, &no_fpm_remote_ip_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_addr_vrf_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_NODE, &no_bgp_graceful_restart_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_rtevents_cmd_vtysh); install_element (VIEW_NODE, &show_isis_mpls_te_router_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_linkstate_id_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh); install_element (RMAP_NODE, &set_ecommunity_soo_cmd_vtysh); install_element (VIEW_NODE, &show_debugging_nhrp_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd_vtysh); install_element (BGP_NODE, &bgp_distance_source_access_list_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (RMAP_NODE, &no_match_ecommunity_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_maxpaths_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_md5_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); install_element (BGP_NODE, &bgp_deterministic_med_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_delete_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_cmd_vtysh); install_element (BGP_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (ZEBRA_NODE, &redistribute_ospf6_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_prune_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community2_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_rd_neighbor_advertised_routes_cmd_vtysh); install_element (VTY_NODE, &no_vty_access_class_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_vpn_prefix_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_md5_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_rtevents_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_community3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_rsclient_cmd_vtysh); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd_vtysh); install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity2_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (RIP_NODE, &rip_version_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_nht_cmd_vtysh); install_element (RMAP_NODE, &set_originator_id_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_cmd_vtysh); install_element (BGP_NODE, &old_ipv6_bgp_network_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_activate_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_vrf_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_all_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_received_prefix_filter_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_auto_cost_reference_bandwidth_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_access_list_any_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd_vtysh); install_element (BGP_NODE, &bgp_network_route_map_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_le_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_err_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_snp_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_param2_cmd_vtysh); install_element (BGP_VPNV6_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_events_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd_vtysh); install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_detail_cmd_vtysh); install_element (BGP_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh); install_element (RMAP_NODE, &match_ip_route_source_prefix_list_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_zebra_sendrecv_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_events_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_addr_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_nssa_translate_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity_cmd_vtysh); install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_detail_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_neighbors_peer_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_damp_unset2_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd_vtysh); install_element (BGP_ENCAP_NODE, &encap_network_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_lcommunity_cmd_vtysh); install_element (BGP_NODE, &bgp_cluster_id32_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_default_cost_cmd_vtysh); install_element (OSPF_NODE, &ospf_refresh_timer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rpf_addr_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags2_tag_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (RIPNG_NODE, &ripng_default_information_originate_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_vrf_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_brouter_router_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd_vtysh); install_element (BGP_NODE, &neighbor_disable_connected_check_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_rip_events_cmd_vtysh); install_element (RMAP_NODE, &no_match_local_pref_val_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_brouter_area_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_message_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags2_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_prefix_pathtype_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_abr_cmd_vtysh); install_element (BGP_NODE, &bgp_always_compare_med_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_update_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_source_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_routes_cmd_vtysh); install_element (CONFIG_NODE, &access_list_standard_host_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd_vtysh); install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_standard_host_cmd_vtysh); install_element (VIEW_NODE, &show_isis_interface_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd_vtysh); install_element (RMAP_NODE, &set_community_delete_cmd_vtysh); install_element (RMAP_NODE, &no_match_origin_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_tag_distance_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_distance_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_nhrp_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_passwd_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_dr_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_neighbor_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_router_ospf_cmd_vtysh); install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd_vtysh); install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard2_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_cost_u32_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_all_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_update_source_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_nht_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_seconds_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rpf_vrf_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_dump_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (CONFIG_NODE, &service_advanced_vty_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_neighbor_flap_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity2_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd_vtysh); install_element (INTERFACE_NODE, &if_nhrp_holdtime_cmd_vtysh); install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_external_inter_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_list_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_network_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_routes_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_address_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (RMAP_NODE, &set_weight_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_filter_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags2_cmd_vtysh); install_element (RIP_NODE, &rip_default_metric_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_community4_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rip_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_neighbor_priority_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd_vtysh); install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rd_route_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_neighbor_poll_interval_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_detail_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags2_cmd_vtysh); install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_timers_connect_val_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (RMAP_NODE, &set_community_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_activate_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_vrf_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_area_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd_vtysh); install_element (BGP_NODE, &bgp_cluster_id_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_all_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_nht_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_err_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_neighbors_peer_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity3_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_supernets_vrf_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd_vtysh); install_element (INTERFACE_NODE, &if_nhrp_flags_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_irdp_shutdown_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_passive_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_adv_router_linkstate_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_trace_cmd_vtysh); install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_events_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd_vtysh); install_element (ISIS_NODE, &no_isis_redistribute_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_spfstats_cmd_vtysh); install_element (RMAP_NODE, &no_match_ecommunity_val_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_damp_unset_cmd_vtysh); install_element (RMAP_NODE, &no_set_metric_val_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_route_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_vrf_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_normal_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (INTERFACE_NODE, &psnp_interval_l1_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_route_map_cmd_vtysh); install_element (RIP_NODE, &no_rip_distance_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_self_originated_detail_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_lupd_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_join_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (BGP_NODE, &bgp_distance_source_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_as4_segment_cmd_vtysh); install_element (OSPF_NODE, &no_router_ospf_id_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_network_area_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_adj_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_mtu_ignore_addr_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd_vtysh); install_element (ENABLE_NODE, &debug_igmp_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_spftrigg_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_detail_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_source_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity2_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_kernel_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_cidr_only_cmd_vtysh); install_element (BGP_NODE, &bgp_confederation_peers_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_all_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_allow_martians_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_all_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd_vtysh); install_element (CONFIG_NODE, &no_router_isis_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_spfevents_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd_vtysh); install_element (INTERFACE_NODE, &if_no_nhrp_mtu_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_adv_router_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_snp_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_distance_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_address_label_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_self_originated_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_all_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_lcommunity3_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_debug_disable_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_stub_router_admin_cmd_vtysh); install_element (RIP_NODE, &no_rip_version_cmd_vtysh); install_element (RIPNG_NODE, &ripng_default_metric_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_natural_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_med_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_csum_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_access_list_name_cmd_vtysh); install_element (RMAP_NODE, &no_match_aspath_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_neighbor_routes_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_neighbor_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_prefix_vrf_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_set_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd_vtysh); install_element (CONFIG_NODE, &undebug_igmp_cmd_vtysh); install_element (RMAP_NODE, &no_match_pathlimit_as_val_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_message_sendrecv_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd_vtysh); install_element (INTERFACE_NODE, &if_no_nhrp_nhs_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_trace_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_brouter_area_cmd_vtysh); install_element (ISIS_NODE, &lsp_gen_interval_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_te_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_summary_1w_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community3_exact_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_tag_distance_vrf_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_assert_internal_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_list_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_pref_vrf_cmd_vtysh); install_element (OSPF6_NODE, &no_area_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd_vtysh); install_element (RMAP_NODE, &rmap_onmatch_next_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (LINK_PARAMS_NODE, &no_link_params_use_bw_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_adj_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_vpn_rd_route_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_peer_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_lcommunity4_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_vrf_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_encap_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_allow_martians_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_route_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_as_set_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd_vtysh); install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_passive_interface_default_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_zebra_sendrecv_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_pathtype_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_filter_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_events_cmd_vtysh); install_element (INTERFACE_NODE, &isis_passwd_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_dsec_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_in_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_addr_vrf_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_nssa_translate_no_summary_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_route_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ripng_packet_direct_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_cmd_vtysh); install_element (OSPF_NODE, &ospf_mpls_te_inter_as_area_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_area_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_filter_cmd_vtysh); install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_val_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd_vtysh); install_element (OSPF_NODE, &pce_address_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_authentication_message_digest_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_zebra_cmd_vtysh); install_element (VIEW_NODE, &show_ip_mroute_count_cmd_vtysh); install_element (VIEW_NODE, &show_isis_topology_l2_cmd_vtysh); install_element (RMAP_NODE, &set_ipv6_nexthop_peer_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh); install_element (VIEW_NODE, &show_isis_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_dampd_paths_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_tag_vrf_cmd_vtysh); install_element (BGP_NODE, &bgp_enforce_first_as_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_vpn_neighbor_routes_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_cost_u32_cmd_vtysh); install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh); install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd_vtysh); install_element (ISIS_NODE, &isis_mpls_te_inter_as_cmd_vtysh); install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_set2_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (RIP_NODE, &rip_offset_list_ifname_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_priority_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_events_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_abr_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_events_cmd_vtysh); install_element (VIEW_NODE, &show_ip_community_list_arg_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_all_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_events_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity3_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh); install_element (OSPF_NODE, &ospf_opaque_capable_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_cost_u32_inet4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_lcommunity_list_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_send_version_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd_vtysh); install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd_vtysh); install_element (CONFIG_NODE, &no_router_zebra_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_as_set_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_address_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (RIPNG_NODE, &ripng_redistribute_type_routemap_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_join_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_nsm_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_longer_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_dampening_params_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_distance2_vrf_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_priority_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_all_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_snp_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_protocol_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_padding_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_cmd_vtysh); install_element (RMAP_NODE, &no_set_originator_id_val_cmd_vtysh); install_element (RMAP_NODE, &match_ecommunity_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_route_cmd_vtysh); install_element (RMAP_NODE, &set_lcommunity_none_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_interval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_prefix_list_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_message_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (BGP_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_all_rsclient_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_flap_address_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_protocol_vrf_all_cmd_vtysh); install_element (OSPF6_NODE, &auto_cost_reference_bandwidth_cmd_vtysh); install_element (ENABLE_NODE, &debug_mroute_cmd_vtysh); install_element (VIEW_NODE, &show_ip_nht_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_cost_u32_cmd_vtysh); install_element (RIP_NODE, &rip_network_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_in_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd_vtysh); install_element (BGP_NODE, &neighbor_port_cmd_vtysh); install_element (INTERFACE_NODE, &psnp_interval_cmd_vtysh); install_element (BGP_NODE, &no_bgp_deterministic_med_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_distance_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_tag_distance_cmd_vtysh); install_element (INTERFACE_NODE, &no_tunnel_protection_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_message_sendrecv_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_summary_vrf_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_send_community_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_detail_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_nht_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_packetdump_recv_cmd_vtysh); install_element (BGP_NODE, &neighbor_local_as_no_prepend_replace_as_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd_vtysh); install_element (BGP_NODE, &bgp_network_import_check_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (BGP_NODE, &neighbor_send_community_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_events_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_sources_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_inter_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd_vtysh); install_element (ENABLE_NODE, &debug_static_cmd_vtysh); install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_event_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_interface_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_tag_cmd_vtysh); install_element (RMAP_NODE, &no_set_origin_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_peer_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_cidr_only_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags2_tag_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd_vtysh); install_element (CONFIG_NODE, &access_list_remark_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_vrf_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd_vtysh); install_element (BGP_NODE, &no_bgp_default_local_preference_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_tag_cmd_vtysh); install_element (RMAP_NODE, &no_set_pathlimit_ttl_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_route_pathtype_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_rib_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_router_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_addr_vrf_all_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_igmp_packets_cmd_vtysh); install_element (ISIS_NODE, &no_dynamic_hostname_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_neighbors_peer_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_distance2_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_router_ripng_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_mroute_vrf_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_distance_source_access_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd_vtysh); install_element (KEYCHAIN_NODE, &no_key_chain_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community4_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_param2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd_vtysh); install_element (INTERFACE_NODE, &if_no_nhrp_holdtime_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_protocol_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_parameters_cmd_vtysh); install_element (ISIS_NODE, &isis_mpls_te_on_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_out_cmd_vtysh); install_element (VTY_NODE, &vty_restricted_mode_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_damp_flap_prefix_list_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_abr_type_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_refresh_timer_val_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_log_adjacency_changes_detail_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd_vtysh); install_element (RMAP_NODE, &no_match_peer_local_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_port_val_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh); install_element (ISIS_NODE, &isis_mpls_te_router_addr_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (INTERFACE_NODE, &no_linkdetect_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_mtu_ignore_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_substitute_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd_vtysh); install_element (CONFIG_NODE, &debug_igmp_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd_vtysh); install_element (INTERFACE_NODE, &if_nhrp_map_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_local_membership_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_cidr_only_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community4_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_rsclient_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd_vtysh); install_element (VIEW_NODE, &show_debugging_ripng_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd_vtysh); install_element (BGP_NODE, &no_bgp_router_id_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_route_pathtype_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_address_val_cmd_vtysh); install_element (BGP_NODE, &bgp_network_backdoor_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd_vtysh); install_element (BGP_NODE, &neighbor_weight_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_flap_cmd_vtysh); install_element (ISIS_NODE, &net_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_default_cost_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_rsclient_prefix_cmd_vtysh); install_element (RIP_NODE, &no_rip_timers_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mroute_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd_vtysh); install_element (CONFIG_NODE, &no_router_bgp_view_cmd_vtysh); install_element (BGP_NODE, &no_bgp_distance2_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_redistribute_type_routemap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_join_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_vrf_cmd_vtysh); install_element (BGP_NODE, &neighbor_peer_group_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (BGP_NODE, &bgp_default_local_preference_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags2_vrf_cmd_vtysh); install_element (OSPF_NODE, &ospf_passive_interface_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_network_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_cost_u32_inet4_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_detail_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_enforce_multihop_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (INTERFACE_NODE, &isis_metric_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_rib_q_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_description_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_cmd_vtysh); install_element (INTERFACE_NODE, &ip_router_isis_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_zebra_cmd_vtysh); install_element (RMAP_NODE, &no_match_tag_val_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd_vtysh); install_element (OSPF_NODE, &router_ospf_id_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_distance_vrf_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd_vtysh); install_element (RIP_NODE, &no_rip_offset_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh); install_element (RMAP_NODE, &match_peer_local_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh); install_element (ISIS_NODE, &no_log_adj_changes_cmd_vtysh); install_element (BGP_VPNV6_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_flap_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_cost_u32_inet4_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_te_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_neighbor_advertised_route_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_med_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (CONFIG_NODE, &debug_igmp_packets_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd_vtysh); install_element (CONFIG_NODE, &debug_ripng_packet_direct_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_in_cmd_vtysh); install_element (VIEW_NODE, &show_debugging_pim_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_mroute_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_vrf_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_multicast_routing_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_view_prefix_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_override_capability_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_route_map_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd_vtysh); install_element (ENABLE_NODE, &debug_igmp_trace_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity3_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (BGP_NODE, &no_bgp_timers_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd_vtysh); install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_rtevents_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_damp_flap_statistics_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd_vtysh); install_element (ENABLE_NODE, &debug_igmp_packets_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_default_metric_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &debug_igmp_events_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_mroute_dist_vrf_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_mroute_source_cmd_vtysh); install_element (RMAP_NODE, &no_set_aspath_exclude_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_filter_list_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_hello_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_mroute_cmd_vtysh); install_element (BGP_ENCAP_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &key_string_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_network_cmd_vtysh); install_element (ISIS_NODE, &isis_redistribute_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_protocol_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd_vtysh); install_element (INTERFACE_NODE, &csnp_interval_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_timers_min_ls_interval_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &no_key_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_cmd_vtysh); install_element (CONFIG_NODE, &no_router_bgp_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_vrf_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_distance_ospf6_intra_inter_external_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_packet_dump_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_router_id_cmd_vtysh); install_element (RIPNG_NODE, &ripng_redistribute_type_metric_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_nht_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_assert_metric_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rd_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd_vtysh); install_element (OSPF6_NODE, &area_import_list_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_port_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_peer_rsclient_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_flap_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd_vtysh); install_element (RIPNG_NODE, &no_if_ipv6_rmap_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_asbr_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd_vtysh); install_element (OSPF_NODE, &no_pce_neighbor_cmd_vtysh); install_element (RIP_NODE, &no_rip_distance_source_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_in_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_tag_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_nssa_no_summary_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_as4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_summary_prefix_vrf_all_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_network_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_adj_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_vrf_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd_vtysh); install_element (BGP_ENCAP_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_summary_1w_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_arg_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_upstream_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_asbr_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_lsp_sched_cmd_vtysh); install_element (OSPF_NODE, &ospf_log_adjacency_changes_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_vrf_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_opaque_capable_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_lsp_gen_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_upstream_rpf_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_packets_filter_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_shutdown_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_flap_stats_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_mtu_ignore_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_update_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_vrf_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_cmd_vtysh); install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_vrf_all_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_route_pathtype_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_aspath_multipath_relax_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_continue_cmd_vtysh); install_element (OSPF_NODE, &ospf_distance_ospf_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_host_any_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_filter_list_cmd_vtysh); } quagga-1.2.4/tests/test-commands.c000066400000000000000000000245531325323223500170600ustar00rootroot00000000000000/* * Test code for lib/command.c * * Copyright (C) 2013 by Open Source Routing. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") * * This program reads in a list of commandlines from stdin * and calls all the public functions of lib/command.c for * both the given command lines and fuzzed versions thereof. * * The output is currently not validated but only logged. It can * be diffed to find regressions between versions. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* Example use for testing: * ./testcommands -e 0 < testcommands.in | \ * diff -au - testcommands.refout */ #define REALLY_NEED_PLAIN_GETOPT 1 #include #include #include #include #include "command.h" #include "memory.h" #include "vector.h" #include "prng.h" extern vector cmdvec; extern struct cmd_node vty_node; extern void test_init_cmd(void); /* provided in test-commands-defun.c */ struct thread_master *master; /* dummy for libzebra*/ static vector test_cmds; static char test_buf[32768]; static struct cmd_node bgp_node = { BGP_NODE, "%s(config-router)# ", }; static struct cmd_node rip_node = { RIP_NODE, "%s(config-router)# ", }; static struct cmd_node isis_node = { ISIS_NODE, "%s(config-router)# ", }; static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", }; static struct cmd_node rmap_node = { RMAP_NODE, "%s(config-route-map)# " }; static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# " }; static struct cmd_node bgp_vpnv4_node = { BGP_VPNV4_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_vpnv6_node = { BGP_VPNV6_NODE, "%s(config-router-af-vpnv6)# ", }; static struct cmd_node bgp_ipv4_node = { BGP_IPV4_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv4m_node = { BGP_IPV4M_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv6_node = { BGP_IPV6_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv6m_node = { BGP_IPV6M_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_encap_node = { BGP_ENCAP_NODE, "%s(config-router-af-encap)# ", }; static struct cmd_node bgp_encapv6_node = { BGP_ENCAPV6_NODE, "%s(config-router-af-encapv6)# ", }; static struct cmd_node ospf_node = { OSPF_NODE, "%s(config-router)# " }; static struct cmd_node ripng_node = { RIPNG_NODE, "%s(config-router)# " }; static struct cmd_node ospf6_node = { OSPF6_NODE, "%s(config-ospf6)# " }; static struct cmd_node babel_node = { BABEL_NODE, "%s(config-babel)# " }; static struct cmd_node keychain_node = { KEYCHAIN_NODE, "%s(config-keychain)# " }; static struct cmd_node keychain_key_node = { KEYCHAIN_KEY_NODE, "%s(config-keychain-key)# " }; static struct cmd_node link_params_node = { LINK_PARAMS_NODE, "%s(config-link-params)# ", }; static int test_callback(struct cmd_element *cmd, struct vty *vty, int argc, const char *argv[]) { int offset; int rv; int i; offset = 0; rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string); if (rv < 0) abort(); offset += rv; for (i = 0; i < argc; i++) { rv = snprintf(test_buf + offset, sizeof(test_buf) - offset, "%s'%s'", (i == 0) ? ": " : ", ", argv[i]); if (rv < 0) abort(); offset += rv; } return CMD_SUCCESS; } static void test_load(void) { char line[4096]; test_cmds = vector_init(VECTOR_MIN_SIZE); while (fgets(line, sizeof(line), stdin) != NULL) { if (strlen(line)) line[strlen(line) - 1] = '\0'; if (line[0] == '#') continue; vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line)); } } static void test_init(void) { unsigned int node; unsigned int i; struct cmd_node *cnode; struct cmd_element *cmd; cmd_init(1); 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_vpnv6_node, NULL); install_node (&bgp_ipv4_node, NULL); install_node (&bgp_ipv4m_node, NULL); install_node (&bgp_ipv6_node, NULL); install_node (&bgp_ipv6m_node, NULL); install_node (&bgp_encap_node, NULL); install_node (&bgp_encapv6_node, NULL); install_node (&ospf_node, NULL); install_node (&ripng_node, NULL); install_node (&ospf6_node, NULL); install_node (&babel_node, NULL); install_node (&keychain_node, NULL); install_node (&keychain_key_node, NULL); install_node (&isis_node, NULL); install_node (&vty_node, NULL); install_node (&link_params_node, NULL); //install_node (&zebra_if_defaults_node, NULL); test_init_cmd(); for (node = 0; node < vector_active(cmdvec); node++) if ((cnode = vector_slot(cmdvec, node)) != NULL) for (i = 0; i < vector_active(cnode->cmd_vector); i++) if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL) { cmd->daemon = 0; cmd->func = test_callback; } test_load(); vty_init_vtysh(); } static void test_terminate(void) { unsigned int i; vty_terminate(); for (i = 0; i < vector_active(test_cmds); i++) XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i)); vector_free(test_cmds); cmd_terminate(); } static void test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_dist, unsigned int node_index, int verbose) { const char *test_str; vector vline; int ret; unsigned int i; char **completions; unsigned int j; struct cmd_node *cnode; vector descriptions; int appended_null; int no_match; test_str = prng_fuzz(prng, cmd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist); vline = cmd_make_strvec(test_str); if (vline == NULL) return; appended_null = 0; for (i = 0; i < vector_active(cmdvec); i++) if ((cnode = vector_slot(cmdvec, i)) != NULL) { if (node_index != (unsigned int)-1 && i != node_index) continue; if (appended_null) { vector_unset(vline, vector_active(vline) - 1); appended_null = 0; } vty->node = cnode->node; test_buf[0] = '\0'; ret = cmd_execute_command(vline, vty, NULL, 0); no_match = (ret == CMD_ERR_NO_MATCH); if (verbose || !no_match) printf("execute relaxed '%s'@%d: rv==%d%s%s\n", test_str, cnode->node, ret, (test_buf[0] != '\0') ? ", " : "", test_buf); vty->node = cnode->node; test_buf[0] = '\0'; ret = cmd_execute_command_strict(vline, vty, NULL); if (verbose || !no_match) printf("execute strict '%s'@%d: rv==%d%s%s\n", test_str, cnode->node, ret, (test_buf[0] != '\0') ? ", " : "", test_buf); if (isspace((int) test_str[strlen(test_str) - 1])) { vector_set (vline, NULL); appended_null = 1; } vty->node = cnode->node; completions = cmd_complete_command(vline, vty, &ret); if (verbose || !no_match) printf("complete '%s'@%d: rv==%d\n", test_str, cnode->node, ret); if (completions != NULL) { for (j = 0; completions[j] != NULL; j++) { printf(" '%s'\n", completions[j]); XFREE(MTYPE_TMP, completions[j]); } XFREE(MTYPE_VECTOR_INDEX, completions); } vty->node = cnode->node; descriptions = cmd_describe_command(vline, vty, &ret); if (verbose || !no_match) printf("describe '%s'@%d: rv==%d\n", test_str, cnode->node, ret); if (descriptions != NULL) { for (j = 0; j < vector_active(descriptions); j++) { struct cmd_token *cmd = vector_slot(descriptions, j); printf(" '%s' '%s'\n", cmd->cmd, cmd->desc); } vector_free(descriptions); } } cmd_free_strvec(vline); } int main(int argc, char **argv) { int opt; struct prng *prng; struct vty *vty; unsigned int edit_distance; unsigned int max_edit_distance; unsigned int node_index; int verbose; unsigned int test_cmd; unsigned int iteration; unsigned int num_iterations; max_edit_distance = 3; node_index = -1; verbose = 0; while ((opt = getopt(argc, argv, "e:n:v")) != -1) { switch (opt) { case 'e': max_edit_distance = atoi(optarg); break; case 'n': node_index = atoi(optarg); break; case 'v': verbose++; break; default: fprintf(stderr, "Usage: %s [-e ] [-n ] [-v]\n", argv[0]); exit(1); break; } } test_init(); prng = prng_new(0); vty = vty_new(); vty->type = VTY_TERM; fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds)); for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++) { for (edit_distance = 0; edit_distance <= max_edit_distance; edit_distance++) { num_iterations = 1 << edit_distance; num_iterations *= num_iterations * num_iterations; for (iteration = 0; iteration < num_iterations; iteration++) test_run(prng, vty, vector_slot(test_cmds, test_cmd), edit_distance, node_index, verbose); } fprintf(stderr, "\r%u/%u", test_cmd + 1, vector_active(test_cmds)); } fprintf(stderr, "\nDone.\n"); vty_close(vty); prng_free(prng); test_terminate(); return 0; } quagga-1.2.4/tests/test-memory.c000066400000000000000000000067041325323223500165650ustar00rootroot00000000000000/* * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 torture tests * * Tests below are generic but comments are focused on interaction with * Paul's proposed memory 'quick' cache, which may never be included in * CVS */ struct thread_master *master; #if 0 /* set to 1 to use system alloc directly */ #undef XMALLOC #undef XCALLOC #undef XREALLOC #undef XFREE #define XMALLOC(T,S) malloc((S)) #define XCALLOC(T,S) calloc(1, (S)) #define XREALLOC(T,P,S) realloc((P),(S)) #define XFREE(T,P) free((P)) #endif #define TIMES 10 int main(int argc, char **argv) { void *a[10]; int i; printf ("malloc x, malloc x, free, malloc x, free free\n\n"); /* simple case, test cache */ for (i = 0; i < TIMES; i++) { a[0] = XMALLOC (MTYPE_VTY, 1024); memset (a[0], 1, 1024); a[1] = XMALLOC (MTYPE_VTY, 1024); memset (a[1], 1, 1024); XFREE(MTYPE_VTY, a[0]); /* should go to cache */ a[0] = XMALLOC (MTYPE_VTY, 1024); /* should be satisfied from cache */ XFREE(MTYPE_VTY, a[0]); XFREE(MTYPE_VTY, a[1]); } printf ("malloc x, malloc y, free x, malloc y, free free\n\n"); /* cache should go invalid, valid, invalid, etc.. */ for (i = 0; i < TIMES; i++) { a[0] = XMALLOC (MTYPE_VTY, 512); memset (a[0], 1, 512); a[1] = XMALLOC (MTYPE_VTY, 1024); /* invalidate cache */ memset (a[1], 1, 1024); XFREE(MTYPE_VTY, a[0]); a[0] = XMALLOC (MTYPE_VTY, 1024); XFREE(MTYPE_VTY, a[0]); XFREE(MTYPE_VTY, a[1]); /* cache should become valid again on next request */ } printf ("calloc\n\n"); /* test calloc */ for (i = 0; i < TIMES; i++) { a[0] = XCALLOC (MTYPE_VTY, 1024); memset (a[0], 1, 1024); a[1] = XCALLOC (MTYPE_VTY, 512); /* invalidate cache */ memset (a[1], 1, 512); XFREE(MTYPE_VTY, a[1]); XFREE(MTYPE_VTY, a[0]); /* alloc == 0, cache can become valid again on next request */ } printf ("calloc and realloc\n\n"); /* check calloc + realloc */ for (i = 0; i < TIMES; i++) { printf ("calloc a0 1024\n"); a[0] = XCALLOC (MTYPE_VTY, 1024); memset (a[0], 1, 1024/2); printf ("calloc 1 1024\n"); a[1] = XCALLOC (MTYPE_VTY, 1024); memset (a[1], 1, 1024/2); printf ("realloc 0 1024\n"); a[3] = XREALLOC (MTYPE_VTY, a[0], 2048); /* invalidate cache */ if (a[3] != NULL) a[0] = a[3]; memset (a[0], 1, 1024); printf ("calloc 2 512\n"); a[2] = XCALLOC (MTYPE_VTY, 512); memset (a[2], 1, 512); printf ("free 1 0 2\n"); XFREE(MTYPE_VTY, a[1]); XFREE(MTYPE_VTY, a[0]); XFREE(MTYPE_VTY, a[2]); /* alloc == 0, cache valid next request */ } return 0; } quagga-1.2.4/tests/test-nexthop-iter.c000066400000000000000000000144511325323223500177010ustar00rootroot00000000000000/* * Recursive Nexthop Iterator test. * This tests the ALL_NEXTHOPS_RO macro. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "zebra/rib.h" #include "prng.h" struct thread_master *master; static int verbose; static void str_append(char **buf, const char *repr) { if (*buf) { *buf = realloc(*buf, strlen(*buf) + strlen(repr) + 1); assert(*buf); strncpy((*buf) + strlen(*buf), repr, strlen(repr) + 1); } else { *buf = strdup(repr); assert(*buf); } } static void str_appendf(char **buf, const char *format, ...) { va_list ap; int rv; char *pbuf; va_start(ap, format); rv = vasprintf(&pbuf, format, ap); va_end(ap); assert(rv >= 0); str_append(buf, pbuf); free(pbuf); } /* This structure contains a nexthop chain * and its expected representation */ struct nexthop_chain { /* Head of the chain */ struct nexthop *head; /* Last nexthop in top chain */ struct nexthop *current_top; /* Last nexthop in current recursive chain */ struct nexthop *current_recursive; /* Expected string representation. */ char *repr; }; static struct nexthop_chain* nexthop_chain_new(void) { struct nexthop_chain *rv; rv = calloc(sizeof(*rv), 1); assert(rv); return rv; } static void nexthop_chain_add_top(struct nexthop_chain *nc) { struct nexthop *nh; nh = calloc(sizeof(*nh), 1); assert(nh); if (nc->head) { nc->current_top->next = nh; nh->prev = nc->current_top; nc->current_top = nh; } else { nc->head = nc->current_top = nh; } nc->current_recursive = NULL; str_appendf(&nc->repr, "%p\n", nh); } static void nexthop_chain_add_recursive(struct nexthop_chain *nc) { struct nexthop *nh; nh = calloc(sizeof(*nh), 1); assert(nh); assert(nc->current_top); if (nc->current_recursive) { nc->current_recursive->next = nh; nh->prev = nc->current_recursive; nc->current_recursive = nh; } else { SET_FLAG(nc->current_top->flags, NEXTHOP_FLAG_RECURSIVE); nc->current_top->resolved = nh; nc->current_recursive = nh; } str_appendf(&nc->repr, " %p\n", nh); } static void nexthop_chain_clear(struct nexthop_chain *nc) { struct nexthop *tcur, *tnext; for (tcur = nc->head; tcur; tcur = tnext) { tnext = tcur->next; if (CHECK_FLAG(tcur->flags, NEXTHOP_FLAG_RECURSIVE)) { struct nexthop *rcur, *rnext; for (rcur = tcur->resolved; rcur; rcur = rnext) { rnext = rcur->next; free(rcur); } } free(tcur); } nc->head = nc->current_top = nc->current_recursive = NULL; free(nc->repr); nc->repr = NULL; } static void nexthop_chain_free(struct nexthop_chain *nc) { if (!nc) return; nexthop_chain_clear(nc); free(nc); } /* This function builds a string representation of * the nexthop chain using the ALL_NEXTHOPS_RO macro. * It verifies that the ALL_NEXTHOPS_RO macro iterated * correctly over the nexthop chain by comparing the * generated representation with the expected representation. */ static void nexthop_chain_verify_iter(struct nexthop_chain *nc) { struct nexthop *nh, *tnh; int recursing; char *repr = NULL; for (ALL_NEXTHOPS_RO(nc->head, nh, tnh, recursing)) { if (recursing) str_appendf(&repr, " %p\n", nh); else str_appendf(&repr, "%p\n", nh); } if (repr && verbose) printf("===\n%s", repr); assert((!repr && !nc->repr) || (repr && nc->repr && !strcmp(repr, nc->repr))); free(repr); } /* This test run builds a simple nexthop chain * with some recursive nexthops and verifies that * the iterator works correctly in each stage along * the way. */ static void test_run_first(void) { struct nexthop_chain *nc; nc = nexthop_chain_new(); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_free(nc); } /* This test run builds numerous random * nexthop chain configurations and verifies * that the iterator correctly progresses * through each. */ static void test_run_prng(void) { struct nexthop_chain *nc; struct prng *prng; int i; nc = nexthop_chain_new(); prng = prng_new(0); for (i = 0; i < 1000000; i++) { switch (prng_rand(prng) % 10) { case 0: nexthop_chain_clear(nc); break; case 1: case 2: case 3: case 4: case 5: nexthop_chain_add_top(nc); break; case 6: case 7: case 8: case 9: if (nc->current_top) nexthop_chain_add_recursive(nc); break; } nexthop_chain_verify_iter(nc); } nexthop_chain_free(nc); prng_free(prng); } int main(int argc, char **argv) { if (argc >= 2 && !strcmp("-v", argv[1])) verbose = 1; test_run_first(); printf("Simple test passed.\n"); test_run_prng(); printf("PRNG test passed.\n"); } quagga-1.2.4/tests/test-privs.c000066400000000000000000000065421325323223500164200ustar00rootroot00000000000000/* * $Id: test-privs.c,v 1.1 2005/10/11 03:48:28 paul Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "getopt.h" #include "privs.h" #include "memory.h" zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_DAC_OVERRIDE, }; struct zebra_privs_t test_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #if defined(VTY_GROUP) .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), .cap_num_i = 0 }; struct option longopts[] = { { "help", no_argument, NULL, 'h'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { 0 } }; /* 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 does 'slow' things.\n\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } struct thread_master *master; /* main routine. */ int main (int argc, char **argv) { char *p; char *progname; struct zprivs_ids_t ids; /* Set umask before anything for security */ umask (0027); /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); while (1) { int opt; opt = getopt_long (argc, argv, "hu:g:", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'u': test_privs.user = optarg; break; case 'g': test_privs.group = optarg; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Library inits. */ memory_init (); zprivs_init (&test_privs); #define PRIV_STATE() \ ((test_privs.current_state() == ZPRIVS_RAISED) ? "Raised" : "Lowered") printf ("%s\n", PRIV_STATE()); test_privs.change(ZPRIVS_RAISE); printf ("%s\n", PRIV_STATE()); test_privs.change(ZPRIVS_LOWER); printf ("%s\n", PRIV_STATE()); zprivs_get_ids (&ids); /* terminate privileges */ zprivs_terminate(&test_privs); /* but these should continue to work... */ printf ("%s\n", PRIV_STATE()); test_privs.change(ZPRIVS_RAISE); printf ("%s\n", PRIV_STATE()); test_privs.change(ZPRIVS_LOWER); printf ("%s\n", PRIV_STATE()); zprivs_get_ids (&ids); printf ("terminating\n"); return 0; } quagga-1.2.4/tests/test-segv.c000066400000000000000000000031671325323223500162210ustar00rootroot00000000000000/* * SEGV / backtrace handling test. * * copied from test-sig.c * * Copyright (C) 2013 by David Lamparter, Open Source Routing. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "lib/log.h" #include "lib/memory.h" struct quagga_signal_t sigs[] = { }; struct thread_master *master; static int threadfunc (struct thread *thread) { int *null = NULL; *null += 1; return 0; } int main (void) { master = thread_master_create (); signal_init (master, array_size(sigs), sigs); zlog_default = openzlog("testsegv", ZLOG_NONE, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG); zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); thread_execute (master, threadfunc, 0, 0); exit (0); } quagga-1.2.4/tests/test-sig.c000066400000000000000000000032431325323223500160320ustar00rootroot00000000000000/* * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "lib/log.h" #include "lib/memory.h" static void sighup (void) { printf ("processed hup\n"); } static void sigusr1 (void) { printf ("processed usr1\n"); } static void sigusr2 (void) { printf ("processed usr2\n"); } struct quagga_signal_t sigs[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGUSR2, .handler = &sigusr2, } }; struct thread_master *master; int main (void) { master = thread_master_create (); signal_init (master, array_size(sigs), sigs); zlog_default = openzlog("testsig", ZLOG_NONE, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG); zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); thread_main (master); exit (0); } quagga-1.2.4/tests/test-stream.c000066400000000000000000000035151325323223500165450ustar00rootroot00000000000000/* Simple stream test. * * Copyright (C) 2006 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 static unsigned long long ham = 0xdeadbeefdeadbeef; struct thread_master *master; static void print_stream (struct stream *s) { size_t getp = stream_get_getp (s); printf ("endp: %zu, readable: %zu, writeable: %zu\n", stream_get_endp (s), STREAM_READABLE (s), STREAM_WRITEABLE (s)); while (STREAM_READABLE (s)) { printf ("0x%x ", *stream_pnt (s)); stream_forward_getp (s, 1); } printf ("\n"); /* put getp back to where it was */ stream_set_getp (s, getp); } int main (void) { struct stream *s; s = stream_new (1024); stream_putc (s, ham); stream_putw (s, ham); stream_putl (s, ham); stream_putq (s, ham); print_stream (s); stream_resize (s, stream_get_endp (s)); print_stream (s); printf ("c: 0x%hhx\n", stream_getc (s)); printf ("w: 0x%hx\n", stream_getw (s)); printf ("l: 0x%x\n", stream_getl (s)); printf ("q: 0x%" PRIu64 "\n", stream_getq (s)); return 0; } quagga-1.2.4/tests/test-timer-correctness.c000066400000000000000000000116411325323223500207210ustar00rootroot00000000000000/* * Test program to verify that scheduled timers are executed in the * correct order. * * Copyright (C) 2013 by Open Source Routing. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "memory.h" #include "pqueue.h" #include "prng.h" #include "thread.h" #define SCHEDULE_TIMERS 800 #define REMOVE_TIMERS 200 #define TIMESTR_LEN strlen("4294967296.999999") struct thread_master *master; static size_t log_buf_len; static size_t log_buf_pos; static char *log_buf; static size_t expected_buf_len; static size_t expected_buf_pos; static char *expected_buf; static struct prng *prng; static struct thread **timers; static int timers_pending; static void terminate_test(void) { int exit_code; if (strcmp(log_buf, expected_buf)) { fprintf(stderr, "Expected output and received output differ.\n"); fprintf(stderr, "---Expected output: ---\n%s", expected_buf); fprintf(stderr, "---Actual output: ---\n%s", log_buf); exit_code = 1; } else { printf("Expected output and actual output match.\n"); exit_code = 0; } thread_master_free(master); XFREE(MTYPE_TMP, log_buf); XFREE(MTYPE_TMP, expected_buf); prng_free(prng); XFREE(MTYPE_TMP, timers); exit(exit_code); } static int timer_func(struct thread *thread) { int rv; rv = snprintf(log_buf + log_buf_pos, log_buf_len - log_buf_pos, "%s\n", (char*)thread->arg); assert(rv >= 0); log_buf_pos += rv; assert(log_buf_pos < log_buf_len); XFREE(MTYPE_TMP, thread->arg); timers_pending--; if (!timers_pending) terminate_test(); return 0; } static int cmp_timeval(const void* a, const void *b) { const struct timeval *ta = *(struct timeval * const *)a; const struct timeval *tb = *(struct timeval * const *)b; if (timercmp(ta, tb, <)) return -1; if (timercmp(ta, tb, >)) return 1; return 0; } int main(int argc, char **argv) { int i, j; struct timeval **alarms; master = thread_master_create(); log_buf_len = SCHEDULE_TIMERS * (TIMESTR_LEN + 1) + 1; log_buf_pos = 0; log_buf = XMALLOC(MTYPE_TMP, log_buf_len); expected_buf_len = SCHEDULE_TIMERS * (TIMESTR_LEN + 1) + 1; expected_buf_pos = 0; expected_buf = XMALLOC(MTYPE_TMP, expected_buf_len); prng = prng_new(0); timers = XMALLOC(MTYPE_TMP, SCHEDULE_TIMERS * sizeof(*timers)); for (i = 0; i < SCHEDULE_TIMERS; i++) { long interval_msec; int ret; char *arg; /* Schedule timers to expire in 0..5 seconds */ interval_msec = prng_rand(prng) % 5000; arg = XMALLOC(MTYPE_TMP, TIMESTR_LEN + 1); timers[i] = thread_add_timer_msec(master, timer_func, arg, interval_msec); ret = snprintf(arg, TIMESTR_LEN + 1, "%lld.%06lld", (long long)timers[i]->u.sands.tv_sec, (long long)timers[i]->u.sands.tv_usec); assert(ret > 0); assert((size_t)ret < TIMESTR_LEN + 1); timers_pending++; } for (i = 0; i < REMOVE_TIMERS; i++) { int index; index = prng_rand(prng) % SCHEDULE_TIMERS; if (!timers[index]) continue; XFREE(MTYPE_TMP, timers[index]->arg); thread_cancel(timers[index]); timers[index] = NULL; timers_pending--; } /* We create an array of pointers to the alarm times and sort * that array. That sorted array is used to generate a string * representing the expected "output" of the timers when they * are run. */ j = 0; alarms = XMALLOC(MTYPE_TMP, timers_pending * sizeof(*alarms)); for (i = 0; i < SCHEDULE_TIMERS; i++) { if (!timers[i]) continue; alarms[j++] = &timers[i]->u.sands; } qsort(alarms, j, sizeof(*alarms), cmp_timeval); for (i = 0; i < j; i++) { int ret; ret = snprintf(expected_buf + expected_buf_pos, expected_buf_len - expected_buf_pos, "%lld.%06lld\n", (long long)alarms[i]->tv_sec, (long long)alarms[i]->tv_usec); assert(ret > 0); expected_buf_pos += ret; assert(expected_buf_pos < expected_buf_len); } XFREE(MTYPE_TMP, alarms); thread_main (master); return 0; } quagga-1.2.4/tests/test-timer-performance.c000066400000000000000000000056531325323223500206760ustar00rootroot00000000000000/* * Test program which measures the time it takes to schedule and * remove timers. * * Copyright (C) 2013 by Open Source Routing. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "thread.h" #include "pqueue.h" #include "prng.h" #define SCHEDULE_TIMERS 1000000 #define REMOVE_TIMERS 500000 struct thread_master *master; static int dummy_func(struct thread *thread) { return 0; } int main(int argc, char **argv) { struct prng *prng; int i; struct thread **timers; struct timeval tv_start, tv_lap, tv_stop; unsigned long t_schedule, t_remove; master = thread_master_create(); prng = prng_new(0); timers = calloc(SCHEDULE_TIMERS, sizeof(*timers)); /* create thread structures so they won't be allocated during the * time measurement */ for (i = 0; i < SCHEDULE_TIMERS; i++) timers[i] = thread_add_timer_msec(master, dummy_func, NULL, 0); for (i = 0; i < SCHEDULE_TIMERS; i++) thread_cancel(timers[i]); quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_start); for (i = 0; i < SCHEDULE_TIMERS; i++) { long interval_msec; interval_msec = prng_rand(prng) % (100 * SCHEDULE_TIMERS); timers[i] = thread_add_timer_msec(master, dummy_func, NULL, interval_msec); } quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_lap); for (i = 0; i < REMOVE_TIMERS; i++) { int index; index = prng_rand(prng) % SCHEDULE_TIMERS; if (timers[index]) thread_cancel(timers[index]); timers[index] = NULL; } quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_stop); t_schedule = 1000 * (tv_lap.tv_sec - tv_start.tv_sec); t_schedule += (tv_lap.tv_usec - tv_start.tv_usec) / 1000; t_remove = 1000 * (tv_stop.tv_sec - tv_lap.tv_sec); t_remove += (tv_stop.tv_usec - tv_lap.tv_usec) / 1000; printf("Scheduling %d random timers took %ld.%03ld seconds.\n", SCHEDULE_TIMERS, t_schedule/1000, t_schedule%1000); printf("Removing %d random timers took %ld.%03ld seconds.\n", REMOVE_TIMERS, t_remove/1000, t_remove%1000); fflush(stdout); free(timers); thread_master_free(master); prng_free(prng); return 0; } quagga-1.2.4/tests/testcli.in000066400000000000000000000023211325323223500161220ustar00rootroot00000000000000echo this is a test message echo foo bla ? baz echo arg ipv4 1.2.3.4 arg ipv4 1.2.?3.4 arg ipv4 1.2.3 arg ipv4 1.2.3.4.5 arg ipv4 1.a.3.4 arg ipv4 blah arg ipv4m 1.2.3.0/24 arg ipv4m 1.2.?3.0/24 arg ipv4m 1.2.3/9 arg ipv4m 1.2.3.4.5/6 arg ipv4m 1.a.3.4 arg ipv4m blah arg ipv4m 1.2.3.0/999 arg ipv4m 1.2.3.0/a9 arg ipv4m 1.2.3.0/9a arg ipv6 de4d:b33f::cafe arg ipv6 de4d:b3?3f::caf?e arg ipv6 de4d:b3 3f::caf?e arg ipv6 de4d:b33f:z::cafe arg ipv6 de4d:b33f:cafe: arg ipv6 :: arg ipv6 ::/ arg ipv6 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 arg ipv6 12::34::56 arg ipv6m dead:beef:cafe::/64 arg ipv6m dead:be?ef:cafe:?:/64 arg range 4 arg range 5 arg range 9? arg range 15 arg range 16 arg range -1 arg range 99999999999999999999999999999999999999999 arg ? pa pat pat a pat a a pat a ?b pat a c? pat a a x pat b pat b ?a pat b x pat b x y pat c a pat c a 1.2.3.4 pat c b 2.3.4 pat c c ?x pat d pat d pat d foo 1.2.3.4 pat d foo pat d noooo pat d bar 1::2 pat d bar 1::2 foo 3.4.5.6 pat d ba?z pat d foo 3.4.5.6 baz pat e pat e f pat e f g pat e 1.2.3.4 pat f pat f foo pat f key alt a a?b alt a 1 .2?.3.4 alt a 1 :2? ::?3 conf t do pat d baz exit show run conf t hostname foohost do show run quagga-1.2.4/tests/testcli.refout000066400000000000000000000134261325323223500170300ustar00rootroot00000000000000test# echo this is a test message this is a test message test# echo foo bla MESSAGE The message to echo test# echo foo bla baz foo bla baz test# echo % Command incomplete. test# test# arg ipv4 1.2.3.4 cmd0 with 1 args. [00]: 1.2.3.4 test# arg ipv4 1.2. A.B.C.D 02 test# arg ipv4 1.2.3.4 cmd0 with 1 args. [00]: 1.2.3.4 test# arg ipv4 1.2.3 cmd0 with 1 args. [00]: 1.2.3 test# arg ipv4 1.2.3.4.5 % [NONE] Unknown command: arg ipv4 1.2.3.4.5 test# arg ipv4 1.a.3.4 % [NONE] Unknown command: arg ipv4 1.a.3.4 test# arg ipv4 blah % [NONE] Unknown command: arg ipv4 blah test# test# arg ipv4m 1.2.3.0/24 cmd1 with 1 args. [00]: 1.2.3.0/24 test# arg ipv4m 1.2. A.B.C.D/M 02 test# arg ipv4m 1.2.3.0/24 cmd1 with 1 args. [00]: 1.2.3.0/24 test# arg ipv4m 1.2.3/9 % [NONE] Unknown command: arg ipv4m 1.2.3/9 test# arg ipv4m 1.2.3.4.5/6 % [NONE] Unknown command: arg ipv4m 1.2.3.4.5/6 test# arg ipv4m 1.a.3.4 % [NONE] Unknown command: arg ipv4m 1.a.3.4 test# arg ipv4m blah % [NONE] Unknown command: arg ipv4m blah test# arg ipv4m 1.2.3.0/999 % [NONE] Unknown command: arg ipv4m 1.2.3.0/999 test# arg ipv4m 1.2.3.0/a9 % [NONE] Unknown command: arg ipv4m 1.2.3.0/a9 test# arg ipv4m 1.2.3.0/9a % [NONE] Unknown command: arg ipv4m 1.2.3.0/9a test# test# arg ipv6 de4d:b33f::cafe cmd2 with 1 args. [00]: de4d:b33f::cafe test# arg ipv6 de4d:b3 % There is no matched command. test# arg ipv6 de4d:b33f::caf X:X::X:X 02 test# arg ipv6 de4d:b33f::cafe cmd2 with 1 args. [00]: de4d:b33f::cafe test# arg ipv6 de4d:b3 test# arg ipv6 de4d:b33f::caf X:X::X:X 02 test# arg ipv6 de4d:b33f::cafe cmd2 with 1 args. [00]: de4d:b33f::cafe test# arg ipv6 de4d:b33f:z::cafe % [NONE] Unknown command: arg ipv6 de4d:b33f:z::cafe test# arg ipv6 de4d:b33f:cafe: % [NONE] Unknown command: arg ipv6 de4d:b33f:cafe: test# arg ipv6 :: cmd2 with 1 args. [00]: :: test# arg ipv6 ::/ % [NONE] Unknown command: arg ipv6 ::/ test# arg ipv6 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 % [NONE] Unknown command: arg ipv6 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 test# arg ipv6 12::34::56 % [NONE] Unknown command: arg ipv6 12::34::56 test# arg ipv6m dead:beef:cafe::/64 cmd3 with 1 args. [00]: dead:beef:cafe::/64 test# arg ipv6m dead:be X:X::X:X/M 02 test# arg ipv6m dead:beef:cafe: X:X::X:X/M 02 test# arg ipv6m dead:beef:cafe::/64 cmd3 with 1 args. [00]: dead:beef:cafe::/64 test# test# arg range 4 % [NONE] Unknown command: arg range 4 test# arg range 5 cmd4 with 1 args. [00]: 5 test# arg range 9 <5-15> 02 test# arg range 9 cmd4 with 1 args. [00]: 9 test# arg range 15 cmd4 with 1 args. [00]: 15 test# arg range 16 % [NONE] Unknown command: arg range 16 test# arg range -1 % [NONE] Unknown command: arg range -1 test# arg range 99999999999999999999999999999999999999999 % [NONE] Unknown command: arg range 99999999999999999999999999999999999999999 test# test# arg ipv4 01 ipv4m 01 ipv6 01 ipv6m 01 range 01 test# arg % Command incomplete. test# test# pa test# papat % Command incomplete. test# pat a b c d e f test# pat % Command incomplete. test# test# pat a % Command incomplete. test# pat a a cmd5 with 1 args. [00]: a test# pat a a 02 b 03 test# pat a b cmd5 with 1 args. [00]: b test# pat a c % There is no matched command. test# pat a c % [NONE] Unknown command: pat a c test# pat a a x % [NONE] Unknown command: pat a a x test# test# pat b % Command incomplete. test# pat b a 02 test# pat b a cmd6 with 1 args. [00]: a test# pat b x % [NONE] Unknown command: pat b x test# pat b x y % [NONE] Unknown command: pat b x y test# test# pat c a % Command incomplete. test# pat c a 1.2.3.4 cmd7 with 2 args. [00]: a [01]: 1.2.3.4 test# pat c b 2.3.4 cmd7 with 2 args. [00]: b [01]: 2.3.4 test# pat c c A.B.C.D 05 test# pat c c x % [NONE] Unknown command: pat c c x test# test# pat d cmd8 with 3 args. [00]: (null) [01]: (null) [02]: (null) test# pat d bar baz foo test# pat d cmd8 with 3 args. [00]: (null) [01]: (null) [02]: (null) test# pat d foo 1.2.3.4 cmd8 with 3 args. [00]: 1.2.3.4 [01]: (null) [02]: (null) test# pat d foo % Command incomplete. test# pat d noooo % [NONE] Unknown command: pat d noooo test# pat d bar 1::2 cmd8 with 3 args. [00]: (null) [01]: 1::2 [02]: (null) test# pat d bar 1::2 foo 3.4.5.6 cmd8 with 3 args. [00]: 3.4.5.6 [01]: 1::2 [02]: (null) test# pat d ba bar 04 baz 06 test# pat d baz cmd8 with 3 args. [00]: (null) [01]: (null) [02]: baz test# pat d foo 3.4.5.6 baz cmd8 with 3 args. [00]: 3.4.5.6 [01]: (null) [02]: baz test# test# pat e % Command incomplete. test# pat e f % Command incomplete. test# pat e f g % Command incomplete. test# pat e 1.2.3.4 % Command incomplete. test# test# pat f cmd10 with 0 args. test# pat f foo cmd10 with 1 args. [00]: foo test# pat f key cmd10 with 1 args. [00]: key test# test# alt a test# alt a a WORD 02 test# alt a ab cmd11 with 1 args. [00]: ab test# alt a 1 test# alt a 1.2 A.B.C.D 02 WORD 02 test# alt a 1.2.3.4 cmd12 with 1 args. [00]: 1.2.3.4 test# alt a 1 test# alt a 1:2 WORD 02 test# alt a 1:2 test# alt a 1:2:: WORD 02 X:X::X:X 02 test# alt a 1:2::3 cmd13 with 1 args. [00]: 1:2::3 test# test# conf t test(config)# do pat d baz cmd8 with 3 args. [00]: (null) [01]: (null) [02]: baz test(config)# exit test# test# show run Current configuration: ! hostname test ! line vty ! end test# conf t test(config)# hostname foohost foohost(config)# do show run Current configuration: ! hostname foohost ! line vty ! end foohost(config)# end. quagga-1.2.4/tests/testcommands.in000066400000000000000000000316611325323223500171650ustar00rootroot00000000000000# # # Some randomly chosen valid commands # # area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1 area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1 area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1 area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1 clear bgp 1 out clear bgp ipv6 2001:db8::1 out clear bgp view VARIABLE * soft clear ip bgp 1.2.3.4 ipv4 multicast out ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1 network 1.0.0.0/8 area 0 no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval no bgp graceful-restart no ipv6 nd mtu 1 no neighbor 1.2.3.4 distribute-list 1 in no neighbor 2001:db8::1 send-community both no neighbor VARIABLE maximum-prefix redistribute isis route-map VARIABLE metric 0 metric-type 2 redistribute rip metric 0 route-map VARIABLE metric-type 1 show bgp community VARIABLE local-AS no-export VARIABLE exact-match show bgp ipv6 community no-advertise no-export no-export no-export show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match show bgp view VARIABLE show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS show ip bgp community no-advertise local-AS no-advertise VARIABLE show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match show ipv6 bgp community no-export no-export VARIABLE VARIABLE show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match show ipv6 mbgp community local-AS local-AS no-export no-export exact-match show ipv6 mbgp community no-export no-export local-AS no-export exact-match show ipv6 ospf6 database as-external dump show ipv6 ospf6 database inter-prefix 1.2.3.4 detail show ipv6 ospf6 database intra-prefix 1.2.3.4 internal # # # Slightly Fuzzed commands # # a8ra 0 range 1.0.0.0/8 adverOise accept-lifetime VARIABE 1 VA6IABLE 19I3 VARIABLE 1 VARIABLE 1993 arAea 1.2.M.4 virtual-link 1.2.3.4 dead-interval 1 dead-interval 1 dead-inter6val 1 transmit-delay 1 area 0 virtu0al-link 1.2.3.i hello-interval 1 ello-interval 1 transmit-delay 1 retransmit-interval 1 area 0 virtual-lin 1.2.3.4 retransmit-interval 1 tranwmit-delay 1 retransmit-interval 1 retransmit-interval 1 area 0 virtual-link 1.2.3.4 retransmit-interal 1 trasmit-dely 1 area 1.2.3.4 virtual-link 1.2.3.4 deadCinterval 1 dead-intervalK 1 retransmit-interval 1 dead-interval 1 area 1.2.3.4 virtual-link 1.2.3.4 dead-intervalo I1 dead-interval 1 retransmit-interval1 dead-interval 1 area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1 area 1.2.3.4 virtuyl-link 1.2.3.4 dead-interval 1 dead-inervalI 1 retransmit-interval 1 dead-interval 1 area 1.2.3.4 virual-link 1.2.34 retransmit-interval 1 dead-interval 1 dead-interva 1 area1.2.83.4 virtual-link 1.2.3.4 retra0smit-interval 1 dead-interval 1 dead-interval 1 clear bgAp 2001g:dbK::1 clear ip bgp 1.2.3.4 pv4 mlticat out cleau bg i2001:db8::1 rsclient de:ug ospf6 messag2 lsreq :recv how ip bgp communiQy no-advertise no-adve:tise no-advertise ip route 1.0Q0.0/8 1.2.3.s4 reGject ipv6 nd prefix 2O01:db8::/32 0 infinEite off-link ipv6 nwd prefix 2001:db8::/32 0 infinite oUUff-link ipv6 route 2001:db8::/32q2001:db8:k: blackhole 1 kshow ip rIute bgp matcch peer .2.30.4 mcogin mhow ipv6 mbgp community o-advertise yocal-AS no-advertise neighbor1.2..4 attribute-unchnged next-hop neihbcr 2001:d b8::1 distribute-list 1 in nko key-tqring no area 0 viertual-link 1.2.3k.4 retransmit-iterval retransmit-interval retransmit-interval hello-interval no area 0 virtual-link 1.2.3.4 dead-intaerval dead-intervIl hello-interval retransmit-interval no area 0 virtual-link 1.2.3.4 retransmit-interval retransmit-intervIl dead-interval tranImit-deqlay no area 0 virtual-link S1.2.3.4 d-ead-interval hello-interval transmit-deay transmit-delay no area 1.2.3.4 virtua -link 1.2.3.4 transmit-delay hello-interval hello-interval retransmt-interval no area 1.2.3.4 virtual-link 1.2.3.4 dea-iterval retransmit-interva- dead-interval hello-interval no area 1.2.3.4 virtual-link 1.2.3.4 hello-interSval dead-interval retransmit-interval transmitdelay no a:rea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interSvalW dead-interval retransmit-interval hello-interval noarea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval trynsmit-delay hello-interval no area 1.2.3.4 virtual-link 1.2.3.4 transmt:delay retransmit-interval retransmit-interval dead-Mnterval no ares 1.2.3.4 virtual-link 1.2.3.4 dead-interval retransmit-interval dead-inesval retransmit-interval no ayrea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval transmi-delay hello-interval no bg2 grace2fuy-restart no debug ospk6 nter2face noimatch ipv6 addrMss VARIABLE nomStch iA next-hop prefix-list no neighbCr 200 :db8::1oroute-map VARIABLE export no neighbor VARIABLE attributeaw8changed next-hop no orea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval ead-interval retransmit-inteSval hello-interval no ospcdead-inkerval no redistribute kernelrote-map VARIABLE metric 0 no redistribute s4taik metric 0 nos Ceighbor 1.2.3.4 route-mapEVARIABLE in o :neighbor VAIABLE attribute-unchanged next-hop ooa router ip redistribute isis meGtric-type2 Q route-map VARIABLE redistribute static metric-type 1 metri 0 rowute-map VARIABLE set-Koveroadbit sh2w ipv6 mbgp comAunity VARIABLE shgw bgp ipv6 community no-export VARIABLE no-xport no-expmrt shiow Wgp neighbors shoAw ip bgpipv4 unicast com6munity no-export no-export no-advertise no-export exact-match sho bgp view gARIABLE nyeighbors 2001:db8::1 received-routes shoow bgp ommunity local-AS no--export show6 bgp community no-advertise local4-AS no-advertise VARIABLE exact-math show8 bgp view VARIABLE ipv4 multicast community ARIABLE VARIABLE local-S show bgp cCommunity VARIABLE VOARIABL no-advertise show bgp cimAunity loal-AS local-AS no-export local-AS show bgp cmmunity n-advertise no-export local-S no-advertise show bgp communi0y no-export no-Cexport no-0xport no-export show bgp communityOlocal-A no-advertise local-WAS show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match show bgp communiy no-export no-adsvertise VARIABLOE local-AS show bgp communiYty no-export VARIABLE VARIABLE locali-AS exact-math show bgp commuUityW no-advertis local-AS no-advertise no-advertise show bgp commuWnity VAIABLE local-AS no-advertise n-export show bgp com:unity no-exportqno-export VARIABLE no-expoIrt exact-match show bgp ipv6 community local-AS no-expor no-xport VARIABCLE show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE show bgp ipv6 community no-advertise no6-export lcal-AS local-AS show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math show bgp ipv6 comm-unity no-advertise no-export local-AS local-kS exact-match show bgp ipv6 community no-export local-AS no-adertise no-adve-tie show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE show bgp naighbors 201:db8::1 rUeceived-routes show bgp viewVAIABLE ipv4 multicast community VARIABLE4no-export no-advertise local-AS show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export show bgp view VARIABLE ipv4 multicast omsunity local-AS VARIABLE no-advertise nUo-export show bgp view VARIABLE ipv4 mutiast community no-export no-export VARIBLE no-export show bgp view VARIABLE ipv4 unicast 0community VARIABqLE local-AS no-export VARIABwE show bgp view VARIABLE ipv4 unicast communeity no-export AcRIABLE no-advertise local-AS show bgp view VARIABLE ipv4 unicasU comunity no-export VARIABL no-advertise show bgp view VARIABLE ipv6 unicast cocmmunity VARIABLE no-advet6ise VARIABLE show bgp view VARIABLE ipvk4 unicast communty no-advertie local-AS local-AS no-export show bgp view VARIALE ipv4 multicast cyommunity no-xport local-AS local-AS show i6 bge community no-export VARIABLE no-advegtise VARIABLE exact-match show iI bgp community no-advertise no-ad2vertsse VARIABLE exact-match show ip6osp6 database dump show ipA6 bgp community local-AS local-AS no-advertse lo:cal-AS show ip bg comunity VARIABLE lcal-AS no-advertise show ip bgp communityno-export2no-export no-advertise locaE-AS Show ip bgp community no-export loqcal-AS no-adverise no-export show ip bgp community no-expor VARIABLEono-export VARIAuBLE show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match show ip bgp cWmmunity no-expoWrt VARIABLE no-advertise VARIABLEexact-match show ip bgp ip4 nicast community no-advertise no-expoIt local-AS local-AS exact-match show ip bgp ipAv4 multicast community no-export no-export no-export no-advertiqe exact-mach show ip bgp ipv4 Aulticast community no-advertise VARIABLE no-advertisKe no-exort show ip bgp ipv4 meuqlticast community VARIABLE VARIABLE no-export n-export show ip bgp ipv4 mlticast coQmmunity localg-AS local-AS no-advertise local-AS show ip bgp ipv4 multicast communiy VARIABLE no-export VARIABLE no-advertise yxact-atch show ip bgp ipv4 unicast commu0nity local-AS no-export no-exrt VARIABLE exact-match show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match showip bgp ipv4 unicast community no-export VARIABLE no-exp-ort VAR6IABLE exact-match show ip bgp ipv4 unicat community no-exportlocal-AS VARIABLE no-export exa0t-match show ip bgp ipv4 unicst community no-advertiseG local-AS no-advertise show ip bgp i:v4 multicast community VARIABLE VARIABLE VARIABLE no-export eMxact-match show ip bgp Mv4 unicast community no-export VARIABLE VARIABLE VAoRIABLE show ipgexecommunity-list 1 show ipkv6 bgp community no-export no-export VARIABL VARIBLE show ipv6 bgp commu2nity local-AS local-AS noEadvertise local-AS show ipv6 bgp communitK VARIABLE lcocal-AS no-advertie no-advertise exact-match show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE show ipv6 bgp comu-ity VARIABLE local-AS no-advertise no-export exact-match show ipv6 bgp comunity no- export local-AS no-advertisge VARIABLE show ipv6 bgp ommunity sno-advcrtise VARIABLE no-export no-advertise exact-match show ipv6 igp community no-advertise no-advertise no-ecxpo0rt no-export show ipv6 mb communyty VARIABLE show ipv6 osp8f6 database nQtwork adv-ruter 1.2.3.4 detail show ipv6 ospf6 dataase type-7 adv-router 1.2.3.4 inernal show ipv6 ospf6 Edatabase intuer8-prefix 1.2.3.4 detail show ipvq6 ospf6 database as-externa detil show ip Wbgp ipv4 unicast community no-advertise no-exprt no-export VARIABLEK exact-match show ip Ybgp attribute-in ufo showMbgp ipv6 community ARIABLE local-AS local-AS no8advertise exact-match show p bgp community no-dvertise no-export no-advertiseIno-export exact-match show uipv6 mbgp coqmmunKty VARIABLE shQw ipv6 mbgp community no-advetise local-AS no-export no-export ex8ct-match shuw ipv6 mbgp community VARIABLyUE no-export no-export no-advertise shw bgp view VARIABLE ipv4 un0icast Gcommunity no-export VARIABLE no-advertise sow ip bgp ipv4 mulicast community no-export no-adertise no-export no-advertise sow ipv6 ospf6 databIase as-external adv-router 1.2.3.4 Whow bgp view VARIAeBLE ipv4 unicast community local-AS no-advrtise no-advertise local-AS Wneighbor 1.2.3.4 dot-capabiliy-negotiate # # # Some teststrings explicitly used for keyword commands # # redistribute bgp redistribute bgp m 10 redistribute bgp metric 10 metric-type 1 redistribute bgp metric 10 metric 10 redistribute bgp route-map RMAP_REDIST_BGP default-information originate metric-type 1 metric 10 default-information originate always metric-type 1 metric 10 default-information originate route-map RMAP_DEFAULT default-information originate route-map RMAP_DEFAULT metric 10 default-information originate always metric-type 2 metric 23 quagga-1.2.4/tests/testcommands.refout000066400000000000000000004217241325323223500200660ustar00rootroot00000000000000execute relaxed 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (authentication|) (message-digest|null) (message-digest-key|) <1-255> md5 KEY': '0', '1.2.3.4', 'authentication', 'null', 'message-digest-key', '1', 'VARIABLE' execute strict 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (authentication|) (message-digest|null) (message-digest-key|) <1-255> md5 KEY': '0', '1.2.3.4', 'authentication', 'null', 'message-digest-key', '1', 'VARIABLE' complete 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==2 describe 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0 'KEY' 'The OSPF password (key)' execute relaxed 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, '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>': '0', '1.2.3.4', 'dead-interval', '1', 'hello-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1' execute strict 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, '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>': '0', '1.2.3.4', 'dead-interval', '1', 'hello-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1' complete 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 describe 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0, '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>': '0', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'dead-interval', '1', 'retransmit-interval', '1' execute strict 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0, '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>': '0', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'dead-interval', '1', 'retransmit-interval', '1' complete 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==2 describe 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0, '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>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'hello-interval', '1', 'dead-interval', '1' execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0, '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>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'hello-interval', '1', 'dead-interval', '1' complete 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==2 describe 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0, '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>': '1.2.3.4', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1', 'dead-interval', '1' execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0, '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>': '1.2.3.4', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1', 'dead-interval', '1' complete 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==2 describe 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'clear bgp 1 out'@4: rv==0, 'clear bgp <1-4294967295> out': '1' execute strict 'clear bgp 1 out'@4: rv==0, 'clear bgp <1-4294967295> out': '1' complete 'clear bgp 1 out'@4: rv==7 'out' describe 'clear bgp 1 out'@4: rv==0 'out' 'Soft reconfig outbound update' execute relaxed 'clear bgp ipv6 2001:db8::1 out'@4: rv==0, 'clear bgp ipv6 (A.B.C.D|X:X::X:X) out': '2001:db8::1' execute strict 'clear bgp ipv6 2001:db8::1 out'@4: rv==0, 'clear bgp ipv6 (A.B.C.D|X:X::X:X) out': '2001:db8::1' complete 'clear bgp ipv6 2001:db8::1 out'@4: rv==7 'out' describe 'clear bgp ipv6 2001:db8::1 out'@4: rv==0 'out' 'Soft reconfig outbound update' execute relaxed 'clear bgp view VARIABLE * soft'@4: rv==0, 'clear bgp view WORD * soft': 'VARIABLE' execute strict 'clear bgp view VARIABLE * soft'@4: rv==0, 'clear bgp view WORD * soft': 'VARIABLE' complete 'clear bgp view VARIABLE * soft'@4: rv==7 'soft' describe 'clear bgp view VARIABLE * soft'@4: rv==0 'soft' 'Soft reconfig' execute relaxed 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0, 'clear ip bgp A.B.C.D ipv4 (unicast|multicast) out': '1.2.3.4', 'multicast' execute strict 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0, 'clear ip bgp A.B.C.D ipv4 (unicast|multicast) out': '1.2.3.4', 'multicast' complete 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==7 'out' describe 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0 'out' 'Soft reconfig outbound update' execute relaxed 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0, 'ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) (<0-4294967295>|infinite) (no-autoconfig|)': '2001:db8::/32', 'infinite', 'infinite', 'no-autoconfig' execute strict 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0, 'ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) (<0-4294967295>|infinite) (no-autoconfig|)': '2001:db8::/32', 'infinite', 'infinite', 'no-autoconfig' complete 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==7 'no-autoconfig' describe 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0 'no-autoconfig' 'Do not use prefix for autoconfiguration' execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0 '<1-255>' 'Distance value for this prefix' execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 execute relaxed 'network 1.0.0.0/8 area 0'@23: rv==0, 'network A.B.C.D/M area (A.B.C.D|<0-4294967295>)': '1.0.0.0/8', '0' execute strict 'network 1.0.0.0/8 area 0'@23: rv==0, 'network A.B.C.D/M area (A.B.C.D|<0-4294967295>)': '1.0.0.0/8', '0' complete 'network 1.0.0.0/8 area 0'@23: rv==2 describe 'network 1.0.0.0/8 area 0'@23: rv==0 '<0-4294967295>' 'OSPF area ID as a decimal value' 'A.B.C.D' 'OSPF area ID in IP address format' execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0, '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)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'hello-interval', 'transmit-delay' execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0, '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)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'hello-interval', 'transmit-delay' complete 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==7 'transmit-delay' describe 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0 'transmit-delay' 'Seconds' execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0, '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)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'retransmit-interval', 'transmit-delay' execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0, '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)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'retransmit-interval', 'transmit-delay' complete 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==7 'transmit-delay' describe 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0 'transmit-delay' 'Seconds' execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0, '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)': '1.2.3.4', '1.2.3.4', 'retransmit-interval', 'dead-interval', 'retransmit-interval', 'hello-interval' execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0, '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)': '1.2.3.4', '1.2.3.4', 'retransmit-interval', 'dead-interval', 'retransmit-interval', 'hello-interval' complete 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==7 'hello-interval' describe 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0 'hello-interval' 'Link state transmit delay' execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0, '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)': '1.2.3.4', '1.2.3.4', 'transmit-delay', 'retransmit-interval', 'retransmit-interval', 'hello-interval' execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0, '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)': '1.2.3.4', '1.2.3.4', 'transmit-delay', 'retransmit-interval', 'retransmit-interval', 'hello-interval' complete 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==7 'hello-interval' describe 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0 'hello-interval' 'Link state transmit delay' execute relaxed 'no bgp graceful-restart'@17: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@17: rv==0, 'no bgp graceful-restart' complete 'no bgp graceful-restart'@17: rv==7 'graceful-restart' describe 'no bgp graceful-restart'@17: rv==0 'graceful-restart' 'Graceful restart capability parameters' execute relaxed 'no bgp graceful-restart'@18: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@18: rv==2 complete 'no bgp graceful-restart'@18: rv==2 describe 'no bgp graceful-restart'@18: rv==2 execute relaxed 'no bgp graceful-restart'@19: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@19: rv==2 complete 'no bgp graceful-restart'@19: rv==2 describe 'no bgp graceful-restart'@19: rv==2 execute relaxed 'no bgp graceful-restart'@20: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@20: rv==2 complete 'no bgp graceful-restart'@20: rv==2 describe 'no bgp graceful-restart'@20: rv==2 execute relaxed 'no bgp graceful-restart'@21: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@21: rv==2 complete 'no bgp graceful-restart'@21: rv==2 describe 'no bgp graceful-restart'@21: rv==2 execute relaxed 'no bgp graceful-restart'@22: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@22: rv==2 complete 'no bgp graceful-restart'@22: rv==2 describe 'no bgp graceful-restart'@22: rv==2 execute relaxed 'no ipv6 nd mtu 1'@11: rv==0, 'no ipv6 nd mtu <1-65535>': '1' execute strict 'no ipv6 nd mtu 1'@11: rv==0, 'no ipv6 nd mtu <1-65535>': '1' complete 'no ipv6 nd mtu 1'@11: rv==2 describe 'no ipv6 nd mtu 1'@11: rv==0 '<1-65535>' 'MTU in bytes' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 2001:db8::1 send-community both'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@17: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@17: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@18: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@18: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@19: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@19: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@20: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@20: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@21: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@21: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@22: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@22: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor VARIABLE maximum-prefix'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@17: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@17: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@18: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@18: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@19: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@19: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@20: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@20: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@21: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@21: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@22: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@22: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'isis', '0', '2', 'VARIABLE' execute strict 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'isis', '0', '2', 'VARIABLE' complete 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==7 '2' describe 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0 '2' 'Set OSPF External Type 2 metrics' execute relaxed 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'rip', '0', '1', 'VARIABLE' execute strict 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'rip', '0', '1', 'VARIABLE' complete 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==7 '1' describe 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0 '1' 'Set OSPF External Type 1 metrics' execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0, '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': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0, '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': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==7 'exact-match' describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0, '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': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0, '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': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==7 'exact-match' describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0, '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': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0, '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': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==7 'exact-match' describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0, '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)': 'no-advertise', 'no-export', 'no-export', 'no-export' execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0, '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)': 'no-advertise', 'no-export', 'no-export', 'no-export' complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==7 'no-export' describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0, '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)': 'no-advertise', 'no-export', 'no-export', 'no-export' execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0, '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)': 'no-advertise', 'no-export', 'no-export', 'no-export' complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==7 'no-export' describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0, '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)': 'no-advertise', 'no-export', 'no-export', 'no-export' execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0, '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)': 'no-advertise', 'no-export', 'no-export', 'no-export' complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==7 'no-export' describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0, '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': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0, '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': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0, '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': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0, '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': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0, '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': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0, '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': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0, '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': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0, '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': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0, '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': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0, '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': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0, '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': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0, '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': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp view VARIABLE'@1: rv==4 execute strict 'show bgp view VARIABLE'@1: rv==4 complete 'show bgp view VARIABLE'@1: rv==2 describe 'show bgp view VARIABLE'@1: rv==0 'WORD' 'View name' execute relaxed 'show bgp view VARIABLE'@2: rv==0, 'show bgp view WORD': 'VARIABLE' execute strict 'show bgp view VARIABLE'@2: rv==0, 'show bgp view WORD': 'VARIABLE' complete 'show bgp view VARIABLE'@2: rv==2 describe 'show bgp view VARIABLE'@2: rv==0 'WORD' 'View name' execute relaxed 'show bgp view VARIABLE'@4: rv==0, 'show bgp view WORD': 'VARIABLE' execute strict 'show bgp view VARIABLE'@4: rv==0, 'show bgp view WORD': 'VARIABLE' complete 'show bgp view VARIABLE'@4: rv==2 describe 'show bgp view VARIABLE'@4: rv==0 'WORD' 'View name' execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==2 describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==2 describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==2 describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==7 'no-advertise' describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0 'AA:NN' 'community number' 'no-advertise' 'Do not advertise to any peer (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==7 'no-advertise' describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0 'AA:NN' 'community number' 'no-advertise' 'Do not advertise to any peer (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==7 'no-advertise' describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0 'AA:NN' 'community number' 'no-advertise' 'Do not advertise to any peer (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==2 describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==2 describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==2 describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0, '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)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0, '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)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==2 describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0, '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)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0, '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)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==2 describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0, '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)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0, '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)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==2 describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0, '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': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0, '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': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0, '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': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0, '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': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0, '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': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0, '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': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0, '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': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0, '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)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' execute strict 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0, '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)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' complete 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==2 describe 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0, '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)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' execute strict 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0, '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)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' complete 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==2 describe 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0, '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': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' execute strict 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0, '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': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' complete 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==7 'exact-match' describe 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0, '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': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' execute strict 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0, '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': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' complete 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==7 'exact-match' describe 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0, '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': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' execute strict 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0, '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': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' complete 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==7 'exact-match' describe 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0, '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': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' execute strict 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0, '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': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' complete 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==7 'exact-match' describe 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0, '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': 'local-AS', 'local-AS', 'no-export', 'no-export' execute strict 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0, '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': 'local-AS', 'local-AS', 'no-export', 'no-export' complete 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==7 'exact-match' describe 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0, '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': 'local-AS', 'local-AS', 'no-export', 'no-export' execute strict 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0, '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': 'local-AS', 'local-AS', 'no-export', 'no-export' complete 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==7 'exact-match' describe 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0, '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': 'no-export', 'no-export', 'local-AS', 'no-export' execute strict 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0, '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': 'no-export', 'no-export', 'local-AS', 'no-export' complete 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==7 'exact-match' describe 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0, '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': 'no-export', 'no-export', 'local-AS', 'no-export' execute strict 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0, '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': 'no-export', 'no-export', 'local-AS', 'no-export' complete 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==7 'exact-match' describe 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 ospf6 database as-external dump'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' execute strict 'show ipv6 ospf6 database as-external dump'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' complete 'show ipv6 ospf6 database as-external dump'@2: rv==7 'dump' describe 'show ipv6 ospf6 database as-external dump'@2: rv==0 'dump' 'Dump LSAs' execute relaxed 'show ipv6 ospf6 database as-external dump'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' execute strict 'show ipv6 ospf6 database as-external dump'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' complete 'show ipv6 ospf6 database as-external dump'@4: rv==7 'dump' describe 'show ipv6 ospf6 database as-external dump'@4: rv==0 'dump' 'Dump LSAs' execute relaxed 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0, '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)': 'inter-prefix', '1.2.3.4', 'detail' execute strict 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0, '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)': 'inter-prefix', '1.2.3.4', 'detail' complete 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==7 'detail' describe 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0 'detail' 'Display details of LSAs' execute relaxed 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0, '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)': 'inter-prefix', '1.2.3.4', 'detail' execute strict 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0, '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)': 'inter-prefix', '1.2.3.4', 'detail' complete 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==7 'detail' describe 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0 'detail' 'Display details of LSAs' execute relaxed 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0, '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)': 'intra-prefix', '1.2.3.4', 'internal' execute strict 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0, '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)': 'intra-prefix', '1.2.3.4', 'internal' complete 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==7 'internal' describe 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0 'internal' 'Display LSA's internal information' execute relaxed 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0, '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)': 'intra-prefix', '1.2.3.4', 'internal' execute strict 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0, '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)': 'intra-prefix', '1.2.3.4', 'internal' complete 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==7 'internal' describe 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0 'internal' 'Display LSA's internal information' execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, '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>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'dead-interva', '1', 'retransmit-interval', '1', 'transmit-delay', '1' execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 complete 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 describe 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0, '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': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0, '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': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==7 'exact-match' describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0, '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': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0, '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': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==7 'exact-match' describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0, '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': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0, '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': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==7 'exact-match' describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0, '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)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0, '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)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==2 describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0, '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)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0, '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)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==2 describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0, '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)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0, '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)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==2 describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0, '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)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0, '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)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==2 describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0, '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)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0, '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)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==2 describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0, '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)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0, '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)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==2 describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0, '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)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0, '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)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==7 'local-AS' describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0, '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)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0, '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)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==7 'local-AS' describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0, '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)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0, '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)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==7 'local-AS' describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0, '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)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0, '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)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==2 describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0, '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)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0, '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)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==2 describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0, '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)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0, '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)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==2 describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0, '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)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0, '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)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==2 describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0, '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)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0, '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)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==2 describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0, '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)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0, '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)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==2 describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0, '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)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0, '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)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==2 describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0, '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)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0, '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)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==2 describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0, '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)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0, '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)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==2 describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==7 'local-AS' describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==7 'local-AS' describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==7 'local-AS' describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==7 'no-export' describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==7 'no-export' describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (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)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==7 'no-export' describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0, '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)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0, '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)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==2 describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0, '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)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0, '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)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==2 describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0, '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)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0, '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)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==2 describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0, '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)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0, '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)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==2 describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0, '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)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0, '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)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==2 describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0, '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)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0, '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)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==2 describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0, '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': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0, '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': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0, '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': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0, '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': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0, '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': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0, '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': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0, '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': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' execute strict 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0, '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': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' complete 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==7 'exact-match' describe 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0, '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': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' execute strict 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0, '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': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' complete 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==7 'exact-match' describe 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0, '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)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' execute strict 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0, '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)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' complete 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==2 describe 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0, '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)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' execute strict 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0, '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)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' complete 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==2 describe 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0, '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': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' execute strict 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0, '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': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' complete 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==7 'exact-match' describe 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0, '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': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' execute strict 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0, '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': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' complete 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==7 'exact-match' describe 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0, '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)': 'wARIBLE', 'VARIABLE', '8ARIABLE' execute strict 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0, '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)': 'wARIBLE', 'VARIABLE', '8ARIABLE' complete 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==2 describe 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0, '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)': 'wARIBLE', 'VARIABLE', '8ARIABLE' execute strict 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0, '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)': 'wARIBLE', 'VARIABLE', '8ARIABLE' complete 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==2 describe 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'redistribute bgp'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel)': 'bgp' execute strict 'redistribute bgp'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel)': 'bgp' complete 'redistribute bgp'@14: rv==7 'bgp' describe 'redistribute bgp'@14: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel)': 'bgp' execute strict 'redistribute bgp'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel)': 'bgp' complete 'redistribute bgp'@15: rv==7 'bgp' describe 'redistribute bgp'@15: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp'@16: rv==0, 'redistribute (kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp)': 'bgp' execute strict 'redistribute bgp'@16: rv==0, 'redistribute (kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp)': 'bgp' complete 'redistribute bgp'@16: rv==7 'bgp' describe 'redistribute bgp'@16: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', '(null)' execute strict 'redistribute bgp'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', '(null)' complete 'redistribute bgp'@23: rv==7 'bgp' describe 'redistribute bgp'@23: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel)': 'bgp' execute strict 'redistribute bgp'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel)': 'bgp' complete 'redistribute bgp'@24: rv==7 'bgp' describe 'redistribute bgp'@24: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp m 10'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) metric <0-16>': 'bgp', '10' execute strict 'redistribute bgp m 10'@14: rv==2 complete 'redistribute bgp m 10'@14: rv==2 describe 'redistribute bgp m 10'@14: rv==0 '<0-16>' 'Metric value' execute relaxed 'redistribute bgp m 10'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) metric <0-16>': 'bgp', '10' execute strict 'redistribute bgp m 10'@15: rv==2 complete 'redistribute bgp m 10'@15: rv==2 describe 'redistribute bgp m 10'@15: rv==0 '<0-16>' 'Metric value' execute relaxed 'redistribute bgp m 10'@23: rv==3 execute strict 'redistribute bgp m 10'@23: rv==2 complete 'redistribute bgp m 10'@23: rv==3 describe 'redistribute bgp m 10'@23: rv==3 execute relaxed 'redistribute bgp metric 10 metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '10', '1', '(null)' execute strict 'redistribute bgp metric 10 metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '10', '1', '(null)' complete 'redistribute bgp metric 10 metric-type 1'@23: rv==7 '1' describe 'redistribute bgp metric 10 metric-type 1'@23: rv==0 '1' 'Set OSPF External Type 1 metrics' execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' complete 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==2 describe 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0 'WORD' 'Pointer to route-map entries' execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' complete 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==2 describe 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0 'WORD' 'Pointer to route-map entries' execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', 'RMAP_REDIST_BGP' execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', 'RMAP_REDIST_BGP' complete 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==2 describe 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0 'WORD' 'Pointer to route-map entries' execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' complete 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==2 describe 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0 'WORD' 'Route map name' execute relaxed 'default-information originate metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '1', '(null)' execute strict 'default-information originate metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '1', '(null)' complete 'default-information originate metric-type 1 metric 10'@23: rv==2 describe 'default-information originate metric-type 1 metric 10'@23: rv==0 '<0-16777214>' 'OSPF metric' execute relaxed 'default-information originate always metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '10', '1', '(null)' execute strict 'default-information originate always metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '10', '1', '(null)' complete 'default-information originate always metric-type 1 metric 10'@23: rv==2 describe 'default-information originate always metric-type 1 metric 10'@23: rv==0 '<0-16777214>' 'OSPF metric' execute relaxed 'default-information originate route-map RMAP_DEFAULT'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '(null)', '(null)', 'RMAP_DEFAULT' execute strict 'default-information originate route-map RMAP_DEFAULT'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '(null)', '(null)', 'RMAP_DEFAULT' complete 'default-information originate route-map RMAP_DEFAULT'@23: rv==2 describe 'default-information originate route-map RMAP_DEFAULT'@23: rv==0 'WORD' 'Pointer to route-map entries' execute relaxed 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '(null)', 'RMAP_DEFAULT' execute strict 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '(null)', 'RMAP_DEFAULT' complete 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==2 describe 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0 '<0-16777214>' 'OSPF metric' execute relaxed 'default-information originate always metric-type 2 metric 23'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '23', '2', '(null)' execute strict 'default-information originate always metric-type 2 metric 23'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '23', '2', '(null)' complete 'default-information originate always metric-type 2 metric 23'@23: rv==2 describe 'default-information originate always metric-type 2 metric 23'@23: rv==0 '<0-16777214>' 'OSPF metric' quagga-1.2.4/tests/tests.h000066400000000000000000000020151325323223500154360ustar00rootroot00000000000000/* * Test wrappers common header file * * Copyright (C) 2015 by David Lamparter, * for Open Source Routing./ NetDEF, Inc. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_TESTS_H #define _QUAGGA_TESTS_H extern void test_init (void); extern void test_init_cmd (void); #endif /* _QUAGGA_TESTS_H */ quagga-1.2.4/tools/000077500000000000000000000000001325323223500141235ustar00rootroot00000000000000quagga-1.2.4/tools/multiple-bgpd.sh000066400000000000000000000242741325323223500172350ustar00rootroot00000000000000#!/bin/bash # Public domain, not copyrighted.. set -u # number of bgpd instances, not more than 255 at this point. At least 3 are # needed to connect in a ring. NUM=7 # The NUM peers can be connected in a ring topology. # # This sets the proportion of other peers that each peer should be # configured to connect to E.g., 20 means each BGP instance will peer with # 20% of the other peers before and after it in the ring. So 10% of the # peers prior to this instance in the ring, and 10% of the following peers. # 100 should lead to a full-mesh, for an odd total number of peers. # # A value of 1 will result in each instance having at least 2 peers in the ring. # # A value of 0 will disable creating a ring, in which case the only peers # configured will be those in the EXPEERS list. PEERPROP=100 # number of routes each BGP instance should advertise ADV=10 # First octet to use for the IPv4 advertisements. The advertisements # will be /32s under this /8. E.g. ADVPREF=10 will mean # 10.x.y.z/32's are advertised. ADVPREF=10 # Base VTY port to allocate Quagga telnet vtys from. VTYBASE+ID will be # the port. VTYBASE=2610 # Base ASN to allocate ASNs to instances. ASBASE=64500 PREFIX=192.168.145. #PREFIX=3ffe:123:456:: ADDRPLEN=32 CONFBASE=/tmp PIDBASE=/var/run/quagga USER=quagga GROUP=quagga # MRAI to specify, where an implementation supports it. MRAI=1 # Connect retry timer CONNECTRETRY=1 # The binary locations for BGP instances. declare -A BGP_BINS=( [quagga]=/usr/sbin/bgpd [bird]=/usr/sbin/bird [birdgit]=/home/paul/code/bird/bird [quaggagit]=/home/paul/code/quagga/bgpd/bgpd [exabgp]=/home/paul/code/exabgp/sbin/exabgp ) # Configuration generation functions for the BGP instances. declare -A BGP_CONFIGGEN=( [quagga]=quagga_config [quaggagit]=quagga_config [bird]=bird_config [birdgit]=bird_config [exabgp]=exabgp_config ) # Launch functions for the BGP instances. declare -A BGP_LAUNCH=( [quagga]=quagga_launch [quaggagit]=quagga_launch [bird]=bird_launch [birdgit]=bird_launch [quaggagit]=quagga_launch [exabgp]=exabgp_launch ) # the instances to run, in the order they should appear in the ring # (repeated over until there are $NUM instances). The value must exist as a # key into the above two arrays. declare -a BGP_INSTANCES=( quagga bird quaggagit exabgp ) # Peers to configure, that are external to this script. One list of IPs, with # corresponding list of their ASes. # # e.g.: #EXPEERS=(192.168.147.{1..10}) #EXPEERASES=($(seq $((ASBASE+11)) $(($ASBASE+20)))) EXPEERS=() EXPEERASES=() ############################################################################ # Can override any of the above from a supplied file with declarations CONFWRITE=Y if [ $# -gt 0 ] ; then echo "multiple-bgpd.sh: sourcing config from $1" [ -f "$1" ] && . "$1" # keep config, if exists [ $# -gt 1 ] && [ "$2" = "k" ] && CONFWRITE=N fi ############################################################################ # Internal variables. # Number of peers for each instance to peer with PEERNUM=$(( ($NUM-1) * $PEERPROP / 100 )) [ "$PEERNUM" -gt $(($NUM-1)) ] && PEERNUM=$(($NUM-1)) # the 'range', i.e. how many of the previous and next peers in the ring to # connect to PEERRANGE=$(( $PEERNUM/2 )) [ "$PEERPROP" -gt 0 -a "$NUM" -ge 3 -a "$PEERRANGE" -le 0 ] && PEERRANGE=1 # and a convenience expansion PEEREXP="" if [ "$PEERRANGE" -gt 0 ]; then PEEREXP=($(seq -${PEERRANGE} ${PEERRANGE})) # dont need 0 unset PEEREXP[PEERRANGE] fi #echo ${PEEREXP[@]} ############################################################################ ## helpers # translate instance ID to its address. id2addr () { local ID=$1 echo ${PREFIX}${ID} } # return the ID of a peer, in terms of an offset on the given instance's ID. # # E.g., given an ID of 1 and an offset of -1, if there are 10 instances overall, # this will return 10. peeridoff () { local ID=$1 local OFF=$2 echo $(( (($ID + $OFF - 1 + $NUM) % $NUM) + 1 )) } # return IPv4 address to advertise, for given instance ID and number. advipaddr () { local ID=$1 local N=$2 echo "$ADVPREF.$(( ($N >> 16) %256 )).$(( ($N >> 8) % 256 )).$(( $N % 256 ))" } ############################################################################ # launch functions # # do not daemonise, so that all launched instances can be killed by killing # the script. # quagga_launch () { local ID=$1 local ASN=$2 local ADDR=$3 local BIN=$4 local CONF=$5 ${BIN} -i "${PIDBASE}"/bgpd${ID}.pid \ -l ${ADDR} \ -f "${CONF}" \ -u $USER -g $GROUP \ -P $((${VTYBASE}+${ID})) } exabgp_launch () { local ID=$1 local ASN=$2 local ADDR=$3 local BIN=$4 local CONF=$5 env exabgp.api.file="${PIDBASE}"/exabgp${ID}.ctl \ exabgp.daemon.pid="${PIDBASE}"/bgpd${ID}.pid \ exabgp.daemon.daemonize=false \ exabgp.tcp.bind=${ADDR} \ exabgp.log.enable=false \ exabgp.daemon.user=quagga \ ${BIN} ${CONF} } bird_launch () { local ID=$1 local ASN=$2 local ADDR=$3 local BIN=$4 local CONF=$5 ${BIN} -P "${PIDBASE}"/bird${ID}.pid \ -c "${CONF}" \ -s "${PIDBASE}"/bird${ID}.ctl \ -f } ####################################################################### # # functions to write the configuration for instances # exabgp_config () { local ID=$1 local ASN=$2 local ADDR=$3 local N local P cat <<- EOF group default { local-address $ADDR; local-as $ASN; router-id $ADDR; capability { asn4 enable; } EOF for N in $(seq 1 $ADV) ; do echo " static {" echo " route `advipaddr $ID $N`/32 {" echo " next-hop $ADDR;" echo " }" echo " }" done for P in ${PEEREXP[@]}; do [ "$P" -eq 0 ] && continue; #local PID=$(( (($ID + $P - 1 + $NUM) % $NUM) + 1 )) local PID=`peeridoff $ID $P` #local PADDR="${PREFIX}${PID}" local PADDR=`id2addr $PID` local PAS=$((${ASBASE} + $PID)) echo " neighbor $PADDR {" #echo " local-address $ADDR;" #echo " local-as $ASN;" #echo " graceful-restart;" #echo " router-id $ADDR;" echo " peer-as $PAS;" echo " }" done for P in ${!EXPEERS[@]}; do echo " neighbor ${EXPEERS[$P]} {" echo " peer-as ${EXPEERASES[$P]};" echo " }" done cat <<- EOF } EOF } quagga_config () { local ID=$1 local ASN=$2 local ADDR=$3 local N local P # Edit config to suit. cat <<- EOF password foo service advanced-vty ! router bgp ${ASN} bgp router-id ${ADDR} !maximum-paths 32 !bgp bestpath as-path multipath-relax EOF for N in $(seq 1 $ADV) ; do echo " network `advipaddr $ID $N`/32" done cat <<- EOF neighbor default peer-group neighbor default update-source ${ADDR} neighbor default capability orf prefix-list both !neighbor default soft-reconfiguration inbound neighbor default advertisement-interval $MRAI neighbor default timers connect $CONNECTRETRY neighbor default route-map test out EOF for P in ${PEEREXP[@]}; do [ "$P" -eq 0 ] && continue; local PID=`peeridoff $ID $P` local PADDR=`id2addr $PID` local PAS=$((${ASBASE} + $PID)) echo " neighbor ${PADDR} remote-as ${PAS}" echo " neighbor ${PADDR} peer-group default" done for P in ${!EXPEERS[@]}; do echo " neighbor ${EXPEERS[$P]} remote-as ${EXPEERASES[$P]}" echo " neighbor ${EXPEERS[$P]} peer-group default" done cat <<- EOF ! address-family ipv6 network 3ffe:${ID}::/48 network 3ffe:${ID}:1::/48 pathlimit 1 network 3ffe:${ID}:2::/48 pathlimit 3 network 3ffe:${ID}:3::/48 pathlimit 3 neighbor default activate neighbor default capability orf prefix-list both neighbor default default-originate neighbor default route-map test out EOF for P in ${PEEREXP[@]}; do [ "$P" -eq 0 ] && continue; local PID=`peeridoff $ID $P` local PADDR=`id2addr $PID` local PAS=$((${ASBASE} + $PID)) echo " neighbor ${PADDR} peer-group default" done cat <<- EOF exit-address-family ! ! bgpd still has problems with extcommunity rt/soo route-map test permit 10 set extcommunity rt ${ASN}:1 set extcommunity soo ${ASN}:2 set community ${ASN}:1 ! line vty exec-timeout 0 0 ! end EOF } bird_config () { local ID=$1 local ASN=$2 local ADDR=$3 cat <<- EOF #log "/var/log/bird.log" all; #debug protocols all; # Override router ID router id ${ADDR}; listen bgp address ${ADDR}; protocol kernel { device routes; import all; } protocol device { import all; } function avoid_martians() prefix set martians; { martians = [ 224.0.0.0/4+, 240.0.0.0/4+ ]; # Avoid RFC1918 and similar networks if net ~ martians then return false; return true; } filter import_filter { if ! (avoid_martians()) then reject; accept; } filter set_comm { bgp_community.add ((${ASN}, 1)); accept; } template bgp peer_conf { local as ${ASN}; source address ${ADDR}; import filter import_filter; export filter set_comm; multihop; } EOF local P; for P in ${PEEREXP[@]}; do [ "$P" -eq 0 ] && continue; local PID=`peeridoff $ID $P` local PADDR=`id2addr $PID` local PAS=$((${ASBASE} + $PID)) echo "protocol bgp from peer_conf {" echo " neighbor ${PADDR} as ${PAS};" echo "}" done for P in ${!EXPEERS[@]}; do echo "protocol bgp from peer_conf {" echo " neighbor ${EXPEERS[$P]} as ${EXPEERASES[$P]};" echo "}" done for N in $(seq 1 $ADV) ; do echo " network `advipaddr $ID $N`/32" done } ####################################################################### for ID in $(seq 1 $NUM); do BGP_INST=${BGP_INSTANCES[${ID} % ${#BGP_INSTANCES[@]}]} BGPBIN=${BGP_BINS[$BGP_INST]} CONF="${CONFBASE}"/${BGP_INST}_bgpd${ID}.conf ASN=$(($ASBASE + ${ID})) ADDR=`id2addr $ID` #if [ ! -e "$CONF" ] ; then if [ ! -e "$CONF" -o "$CONFWRITE" = "Y" ] ; then ${BGP_CONFIGGEN[$BGP_INST]} $ID $ASN $ADDR > "$CONF" chown $USER:$GROUP "$CONF" fi # You may want to automatically add configure a local address # on a loop interface. # # Solaris: ifconfig vni${H} plumb ${ADDR}/${ADDRPLEN} up # Linux: #ip address add ${ADDR}/${ADDRPLEN} dev lo 2> /dev/null ip link add dummy${ID} type dummy 2> /dev/null ip link set dev dummy${ID} up ip address add ${ADDR}/${ADDRPLEN} dev dummy${ID} 2> /dev/null ${BGP_LAUNCH[$BGP_INST]} $ID $ASN $ADDR $BGPBIN $CONF & sleep 0.1 done echo "multiple-bgpd.sh: waiting..." wait quagga-1.2.4/tools/zebra.el000066400000000000000000000062001325323223500155460ustar00rootroot00000000000000;; -*- 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)) quagga-1.2.4/update-autotools000077500000000000000000000012711325323223500162230ustar00rootroot00000000000000#! /bin/sh # # When local system does not have the latest autoconf/automake # -- Kunihiro Ishiguro # rm -f config.cache Makefile.in aclocal.m4 config.h.in configure rm -rf config.guess config.sub ltmain.sh rm -rf autom4te.cache echo "This $0 script is deprecated, and will be removed at some stage." echo "Please use the 'autoreconf' command included with autoconf." echo "TOOLS VERIONS:" for tool in autoheader autoconf libtool libtoolize aclocal automake; do $tool --version | head -1 done echo "ACLOCAL:" aclocal -I m4 echo "AUTOHEADER:" autoheader echo "AUTOCONF:" autoconf echo "LIBTOOLIZE:" libtoolize -c echo "AUTOMAKE" automake --gnu --add-missing --copy quagga-1.2.4/vtysh/000077500000000000000000000000001325323223500141405ustar00rootroot00000000000000quagga-1.2.4/vtysh/Makefile.am000066400000000000000000000027121325323223500161760ustar00rootroot00000000000000## Process this file with Automake to create Makefile.in AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" LIBS = @LIBS@ @CURSES@ @LIBPAM@ AM_CFLAGS = $(WERROR) bin_PROGRAMS = vtysh vtysh_SOURCES = vtysh_main.c vtysh.c vtysh_user.c vtysh_config.c nodist_vtysh_SOURCES = vtysh_cmd.c CLEANFILES = vtysh_cmd.c noinst_HEADERS = vtysh.h vtysh_user.h vtysh_LDADD = ../lib/libzebra.la @LIBCAP@ @LIBREADLINE@ examplesdir = $(exampledir) dist_examples_DATA = vtysh.conf.sample EXTRA_DIST = extract.pl vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ $(top_srcdir)/ospfd/*.c $(top_srcdir)/ospf6d/*.c \ $(top_srcdir)/ripd/*.c $(top_srcdir)/ripngd/*.c \ $(top_srcdir)/pimd/pim_cmd.c \ $(top_srcdir)/nhrpd/nhrp_vty.c \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \ $(top_srcdir)/lib/vrf.c \ $(top_srcdir)/lib/vty.c $(top_srcdir)/zebra/debug.c \ $(top_srcdir)/zebra/interface.c \ $(top_srcdir)/zebra/irdp_interface.c \ $(top_srcdir)/zebra/rtadv.c $(top_srcdir)/zebra/zebra_vty.c \ $(top_srcdir)/zebra/zserv.c $(top_srcdir)/zebra/router-id.c \ $(top_srcdir)/zebra/zebra_routemap.c \ $(top_srcdir)/zebra/zebra_fpm.c vtysh_cmd.c: $(vtysh_cmd_FILES) extract.pl ./extract.pl $(vtysh_cmd_FILES) > vtysh_cmd.c quagga-1.2.4/vtysh/Makefile.in000066400000000000000000000607711325323223500162200ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = vtysh$(EXEEXT) subdir = vtysh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = extract.pl CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(bin_PROGRAMS) am_vtysh_OBJECTS = vtysh_main.$(OBJEXT) vtysh.$(OBJEXT) \ vtysh_user.$(OBJEXT) vtysh_config.$(OBJEXT) nodist_vtysh_OBJECTS = vtysh_cmd.$(OBJEXT) vtysh_OBJECTS = $(am_vtysh_OBJECTS) $(nodist_vtysh_OBJECTS) vtysh_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(vtysh_SOURCES) $(nodist_vtysh_SOURCES) DIST_SOURCES = $(vtysh_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/extract.pl.in \ $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ @CURSES@ @LIBPAM@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) vtysh_SOURCES = vtysh_main.c vtysh.c vtysh_user.c vtysh_config.c nodist_vtysh_SOURCES = vtysh_cmd.c CLEANFILES = vtysh_cmd.c noinst_HEADERS = vtysh.h vtysh_user.h vtysh_LDADD = ../lib/libzebra.la @LIBCAP@ @LIBREADLINE@ examplesdir = $(exampledir) dist_examples_DATA = vtysh.conf.sample EXTRA_DIST = extract.pl vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \ $(top_srcdir)/ospfd/*.c $(top_srcdir)/ospf6d/*.c \ $(top_srcdir)/ripd/*.c $(top_srcdir)/ripngd/*.c \ $(top_srcdir)/pimd/pim_cmd.c \ $(top_srcdir)/nhrpd/nhrp_vty.c \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \ $(top_srcdir)/lib/vrf.c \ $(top_srcdir)/lib/vty.c $(top_srcdir)/zebra/debug.c \ $(top_srcdir)/zebra/interface.c \ $(top_srcdir)/zebra/irdp_interface.c \ $(top_srcdir)/zebra/rtadv.c $(top_srcdir)/zebra/zebra_vty.c \ $(top_srcdir)/zebra/zserv.c $(top_srcdir)/zebra/router-id.c \ $(top_srcdir)/zebra/zebra_routemap.c \ $(top_srcdir)/zebra/zebra_fpm.c all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu vtysh/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu vtysh/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): extract.pl: $(top_builddir)/config.status $(srcdir)/extract.pl.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list vtysh$(EXEEXT): $(vtysh_OBJECTS) $(vtysh_DEPENDENCIES) $(EXTRA_vtysh_DEPENDENCIES) @rm -f vtysh$(EXEEXT) $(AM_V_CCLD)$(LINK) $(vtysh_OBJECTS) $(vtysh_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) 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@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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 clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_examplesDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-dist_examplesDATA .PRECIOUS: Makefile vtysh_cmd.c: $(vtysh_cmd_FILES) extract.pl ./extract.pl $(vtysh_cmd_FILES) > 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: quagga-1.2.4/vtysh/extract.pl000077500000000000000000000166401325323223500161610ustar00rootroot00000000000000#! /usr/bin/perl ## ## vtysh/extract.pl. Generated from extract.pl.in by configure. ## ## 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{'"interface IFNAME " "vrf <0-65535>"'} = "ignore"; $ignore{'"link-params"'} = "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-4294967295>"'} = "ignore"; $ignore{'"router bgp " "<1-4294967295>" " view WORD"'} = "ignore"; $ignore{'"router isis WORD"'} = "ignore"; $ignore{'"router zebra"'} = "ignore"; $ignore{'"address-family ipv4"'} = "ignore"; $ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore"; $ignore{'"address-family ipv6"'} = "ignore"; $ignore{'"address-family ipv6 (unicast|multicast)"'} = "ignore"; $ignore{'"address-family vpnv4"'} = "ignore"; $ignore{'"address-family vpnv4 unicast"'} = "ignore"; $ignore{'"address-family vpnv6"'} = "ignore"; $ignore{'"address-family vpnv6 unicast"'} = "ignore"; $ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; $ignore{'"address-family encap"'} = "ignore"; $ignore{'"address-family encapv4"'} = "ignore"; $ignore{'"address-family encapv6"'} = "ignore"; $ignore{'"exit-address-family"'} = "ignore"; $ignore{'"exit-link-params"'} = "ignore"; $ignore{'"vnc defaults"'} = "ignore"; $ignore{'"vnc nve-group NAME"'} = "ignore"; $ignore{'"exit-vnc"'} = "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"; $ignore{'"line vty"'} = "ignore"; $ignore{'"who"'} = "ignore"; $ignore{'"terminal monitor"'} = "ignore"; $ignore{'"terminal no monitor"'} = "ignore"; $ignore{'"show history"'} = "ignore"; my $cli_stomp = 0; foreach (@ARGV) { $file = $_; open (FH, "gcc -E -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I.. -I./ -I./.. -I../lib -I../lib -I../isisd/topology $file |"); local $/; undef $/; $line = ; close (FH); @defun = ($line =~ /(?:DEFUN|ALIAS)\s*\((.+?)\);?\s?\s?\n/sg); @install = ($line =~ /install_element\s*\(\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\/keychain\.c$/) { $protocol = "VTYSH_RIPD"; } elsif ($file =~ /lib\/routemap\.c$/) { $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; } elsif ($file =~ /lib\/filter\.c$/) { $protocol = "VTYSH_ALL"; } elsif ($file =~ /lib\/vrf\.c$/) { $protocol = "VTYSH_ZEBRA"; } elsif ($file =~ /lib\/plist\.c$/) { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; } else { $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA"; } } elsif ($file =~ /lib\/distribute\.c$/) { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD"; } else { $protocol = "VTYSH_RIPD"; } } elsif ($file =~ /lib\/if_rmap\.c$/) { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD"; } else { $protocol = "VTYSH_RIPD"; } } elsif ($file =~ /lib\/vty\.c$/) { $protocol = "VTYSH_ALL"; } else { ($protocol) = ($file =~ /^.*\/([a-z0-9]+)\/[a-zA-Z0-9_\-]+\.c$/); $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 if (exists($cmd2str{$cmd})) { warn "Duplicate CLI Function: $cmd\n"; warn "\tFrom cli: $cmd2str{$cmd} to New cli: $str\n"; warn "\tOriginal Protocol: $cmd2proto{$cmd} to New Protocol: $protocol\n"; $cli_stomp++; } $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}); } } } my $bad_cli_stomps = 102; # Currently we have $bad_cli_stomps. This was determined by # running this script and counting up the collisions from what # was returned. # # When we have cli commands that map to the same function name, we # can introduce subtle bugs due to code not being called when # we think it is. # # If extract.pl fails with a error message and you've been # modifying the cli, then go back and fix your code to # not have cli command function collisions. # # If you've removed a cli overwrite, you can safely subtract # one from $bad_cli_stomps. If you've added to the problem # please fix your code before submittal if ($cli_stomp != $bad_cli_stomps) { warn "Expected $bad_cli_stomps command line stomps, but got $cli_stomp instead\n"; exit $cli_stomp; } # 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 "command.h" #include "vtysh.h" EOF $ignore{'"interface IFNAME"'} = "ignore"; $ignore{'"interface IFNAME " "vrf <0-65535>"'} = "ignore"; $ignore{'"link-params"'} = "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-4294967295>"'} = "ignore"; $ignore{'"router bgp " "<1-4294967295>" " view WORD"'} = "ignore"; $ignore{'"router isis WORD"'} = "ignore"; $ignore{'"router zebra"'} = "ignore"; $ignore{'"address-family ipv4"'} = "ignore"; $ignore{'"address-family ipv4 (unicast|multicast)"'} = "ignore"; $ignore{'"address-family ipv6"'} = "ignore"; $ignore{'"address-family ipv6 (unicast|multicast)"'} = "ignore"; $ignore{'"address-family vpnv4"'} = "ignore"; $ignore{'"address-family vpnv4 unicast"'} = "ignore"; $ignore{'"address-family vpnv6"'} = "ignore"; $ignore{'"address-family vpnv6 unicast"'} = "ignore"; $ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; $ignore{'"address-family encap"'} = "ignore"; $ignore{'"address-family encapv4"'} = "ignore"; $ignore{'"address-family encapv6"'} = "ignore"; $ignore{'"exit-address-family"'} = "ignore"; $ignore{'"exit-link-params"'} = "ignore"; $ignore{'"vnc defaults"'} = "ignore"; $ignore{'"vnc nve-group NAME"'} = "ignore"; $ignore{'"exit-vnc"'} = "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"; $ignore{'"line vty"'} = "ignore"; $ignore{'"who"'} = "ignore"; $ignore{'"terminal monitor"'} = "ignore"; $ignore{'"terminal no monitor"'} = "ignore"; $ignore{'"show history"'} = "ignore"; my $cli_stomp = 0; foreach (@ARGV) { $file = $_; open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_builddir@/lib -I@top_srcdir@/isisd/topology @CPPFLAGS@ $file |"); local $/; undef $/; $line = ; close (FH); @defun = ($line =~ /(?:DEFUN|ALIAS)\s*\((.+?)\);?\s?\s?\n/sg); @install = ($line =~ /install_element\s*\(\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\/keychain\.c$/) { $protocol = "VTYSH_RIPD"; } elsif ($file =~ /lib\/routemap\.c$/) { $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; } elsif ($file =~ /lib\/filter\.c$/) { $protocol = "VTYSH_ALL"; } elsif ($file =~ /lib\/vrf\.c$/) { $protocol = "VTYSH_ZEBRA"; } elsif ($file =~ /lib\/plist\.c$/) { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; } else { $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA"; } } elsif ($file =~ /lib\/distribute\.c$/) { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD"; } else { $protocol = "VTYSH_RIPD"; } } elsif ($file =~ /lib\/if_rmap\.c$/) { if ($defun_array[1] =~ m/ipv6/) { $protocol = "VTYSH_RIPNGD"; } else { $protocol = "VTYSH_RIPD"; } } elsif ($file =~ /lib\/vty\.c$/) { $protocol = "VTYSH_ALL"; } else { ($protocol) = ($file =~ /^.*\/([a-z0-9]+)\/[a-zA-Z0-9_\-]+\.c$/); $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 if (exists($cmd2str{$cmd})) { warn "Duplicate CLI Function: $cmd\n"; warn "\tFrom cli: $cmd2str{$cmd} to New cli: $str\n"; warn "\tOriginal Protocol: $cmd2proto{$cmd} to New Protocol: $protocol\n"; $cli_stomp++; } $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}); } } } my $bad_cli_stomps = 102; # Currently we have $bad_cli_stomps. This was determined by # running this script and counting up the collisions from what # was returned. # # When we have cli commands that map to the same function name, we # can introduce subtle bugs due to code not being called when # we think it is. # # If extract.pl fails with a error message and you've been # modifying the cli, then go back and fix your code to # not have cli command function collisions. # # If you've removed a cli overwrite, you can safely subtract # one from $bad_cli_stomps. If you've added to the problem # please fix your code before submittal if ($cli_stomp != $bad_cli_stomps) { warn "Expected $bad_cli_stomps command line stomps, but got $cli_stomp instead\n"; exit $cli_stomp; } # 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" #include "log.h" #include "bgpd/bgp_vty.h" #include "vrf.h" /* Struct VTY. */ struct vty *vty; /* VTY shell pager name. */ char *vtysh_pager_name = NULL; /* VTY shell client structure. */ struct vtysh_client { int fd; const char *name; int flag; const char *path; } vtysh_client[] = { { .fd = -1, .name = "zebra", .flag = VTYSH_ZEBRA, .path = ZEBRA_VTYSH_PATH}, { .fd = -1, .name = "ripd", .flag = VTYSH_RIPD, .path = RIP_VTYSH_PATH}, { .fd = -1, .name = "ripngd", .flag = VTYSH_RIPNGD, .path = RIPNG_VTYSH_PATH}, { .fd = -1, .name = "ospfd", .flag = VTYSH_OSPFD, .path = OSPF_VTYSH_PATH}, { .fd = -1, .name = "ospf6d", .flag = VTYSH_OSPF6D, .path = OSPF6_VTYSH_PATH}, { .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH}, { .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH}, { .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .path = PIM_VTYSH_PATH}, { .fd = -1, .name = "nhrpd", .flag = VTYSH_NHRPD, .path = NHRP_VTYSH_PATH}, }; /* We need direct access to ripd to implement vtysh_exit_ripd_only. */ static struct vtysh_client *ripd_client = NULL; /* Using integrated config from Quagga.conf. Default is no. */ int vtysh_writeconfig_integrated = 0; extern char config_default[]; static void vclient_close (struct vtysh_client *vclient) { if (vclient->fd >= 0) { fprintf(stderr, "Warning: closing connection to %s because of an I/O error!\n", vclient->name); close (vclient->fd); vclient->fd = -1; } } /* Return true if str begins with prefix, else return false */ static int begins_with(const char *str, const char *prefix) { if (!str || !prefix) return 0; size_t lenstr = strlen(str); size_t lenprefix = strlen(prefix); if (lenprefix > lenstr) return 0; return strncmp(str, prefix, lenprefix) == 0; } /* Following filled with debug code to trace a problematic condition * under load - it SHOULD handle it. */ #define ERR_WHERE_STRING "vtysh(): vtysh_client_execute(): " static int vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp) { int ret; char *buf; size_t bufsz; char *pbuf; size_t left; char *eoln; int nbytes; int i; int readln; int numnulls = 0; 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 * getpagesize() + 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"); XFREE(MTYPE_TMP, buf); 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; } /* If we have already seen 3 nulls, then current byte is ret code */ if ((numnulls == 3) && (nbytes == 1)) { ret = pbuf[0]; break; } pbuf[nbytes] = '\0'; /* If the config needs to be written in file or stdout */ if (fp) { fputs(pbuf, fp); fflush (fp); } /* At max look last four bytes */ if (nbytes >= 4) { i = nbytes - 4; numnulls = 0; } else i = 0; /* Count the numnulls */ while (i < nbytes && numnulls <3) { if (pbuf[i++] == '\0') numnulls++; else numnulls = 0; } /* We might have seen 3 consecutive nulls so store the ret code before updating pbuf*/ ret = pbuf[nbytes-1]; pbuf += nbytes; /* See if a line exists in buffer, if so parse and consume it, and * reset read position. If 3 nulls has been encountered consume the buffer before * next read. */ if (((eoln = strrchr(buf, '\n')) == NULL) && (numnulls<3)) continue; if (eoln >= ((buf + bufsz) - 1)) { fprintf (stderr, ERR_WHERE_STRING \ "warning - eoln beyond buffer end.\n"); } /* If the config needs parsing, consume it */ if(!fp) vtysh_config_parse(buf); eoln++; left = (size_t)(buf + bufsz - eoln); /* * This check is required since when a config line split between two consecutive reads, * then buf will have first half of config line and current read will bring rest of the * line. So in this case eoln will be 1 here, hence calculation of left will be wrong. * In this case we don't need to do memmove, because we have already seen 3 nulls. */ if(left < bufsz) memmove(buf, eoln, left); buf[bufsz-1] = '\0'; pbuf = buf + strlen(buf); /* got 3 or more trailing NULs? */ if ((numnulls >=3) && (i < nbytes)) { break; } } if(!fp) vtysh_config_parse (buf); XFREE(MTYPE_TMP, buf); return ret; } void vtysh_pager_init (void) { char *pager_defined; pager_defined = getenv ("VTYSH_PAGER"); if (pager_defined) vtysh_pager_name = strdup (pager_defined); else vtysh_pager_name = strdup ("more"); } /* Command execution over the vty interface. */ static int vtysh_execute_func (const char *line, int pager) { int ret, cmd_stat; u_int i; vector vline; struct cmd_element *cmd; FILE *fp = NULL; int closepager = 0; int tried = 0; int saved_ret, saved_node; /* Split readline string up into the vector. */ vline = cmd_make_strvec (line); if (vline == NULL) return CMD_SUCCESS; saved_ret = ret = cmd_execute_command (vline, vty, &cmd, 1); saved_node = vty->node; /* If command doesn't succeeded in current node, try to walk up in node tree. * Changing vty->node is enough to try it just out without actual walkup in * the vtysh. */ while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON && ret != CMD_WARNING && vty->node > CONFIG_NODE) { vty->node = node_parent(vty->node); ret = cmd_execute_command (vline, vty, &cmd, 1); tried++; } vty->node = saved_node; /* If command succeeded in any other node than current (tried > 0) we have * to move into node in the vtysh where it succeeded. */ if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING) { if ((saved_node == BGP_VPNV4_NODE || saved_node == BGP_VPNV6_NODE || saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE || saved_node == BGP_IPV4_NODE || saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE || saved_node == BGP_IPV6M_NODE) && (tried == 1)) { vtysh_execute("exit-address-family"); } else if ((saved_node == KEYCHAIN_KEY_NODE) && (tried == 1)) { vtysh_execute("exit"); } else if (tried) { vtysh_execute ("end"); vtysh_execute ("configure terminal"); } } /* If command didn't succeed in any node, continue with return value from * first try. */ else if (tried) { ret = saved_ret; } cmd_free_strvec (vline); cmd_stat = ret; switch (ret) { case CMD_WARNING: if (vty->type == VTY_FILE) fprintf (stdout,"Warning...\n"); break; case CMD_ERR_AMBIGUOUS: fprintf (stdout,"%% Ambiguous command.\n"); break; case CMD_ERR_NO_MATCH: fprintf (stdout,"%% Unknown command.\n"); break; case CMD_ERR_INCOMPLETE: fprintf (stdout,"%% Command incomplete.\n"); break; case CMD_SUCCESS_DAEMON: { /* FIXME: Don't open pager for exit commands. popen() causes problems * if exited from vtysh at all. This hack shouldn't cause any problem * but is really ugly. */ if (pager && vtysh_pager_name && (strncmp(line, "exit", 4) != 0)) { fp = popen (vtysh_pager_name, "w"); if (fp == NULL) { perror ("popen failed for pager"); fp = stdout; } else closepager=1; } else fp = stdout; if (! strcmp(cmd->string,"configure terminal")) { for (i = 0; i < array_size(vtysh_client); i++) { cmd_stat = vtysh_client_execute(&vtysh_client[i], line, fp); if (cmd_stat == CMD_WARNING) break; } if (cmd_stat) { line = "end"; vline = cmd_make_strvec (line); if (vline == NULL) { if (pager && vtysh_pager_name && fp && closepager) { if (pclose (fp) == -1) { perror ("pclose failed for pager"); } fp = NULL; } return CMD_SUCCESS; } ret = cmd_execute_command (vline, vty, &cmd, 1); cmd_free_strvec (vline); if (ret != CMD_SUCCESS_DAEMON) break; } else if (cmd->func) { (*cmd->func) (cmd, vty, 0, NULL); break; } } cmd_stat = CMD_SUCCESS; for (i = 0; i < array_size(vtysh_client); i++) { if (cmd->daemon & vtysh_client[i].flag) { cmd_stat = vtysh_client_execute(&vtysh_client[i], line, fp); if (cmd_stat != CMD_SUCCESS) break; } } if (cmd_stat != CMD_SUCCESS) break; if (cmd->func) (*cmd->func) (cmd, vty, 0, NULL); } } if (pager && vtysh_pager_name && fp && closepager) { if (pclose (fp) == -1) { perror ("pclose failed for pager"); } fp = NULL; } return cmd_stat; } int vtysh_execute_no_pager (const char *line) { return vtysh_execute_func (line, 0); } int vtysh_execute (const char *line) { return vtysh_execute_func (line, 1); } /* Configration make from file. */ int vtysh_config_from_file (struct vty *vty, FILE *fp) { int ret; struct cmd_element *cmd; while (fgets (vty->buf, vty->max, fp)) { ret = command_config_read_one_line (vty, &cmd, 1); switch (ret) { case CMD_WARNING: if (vty->type == VTY_FILE) fprintf (stdout,"Warning...\n"); break; case CMD_ERR_AMBIGUOUS: fprintf (stdout,"%% Ambiguous command.\n"); break; case CMD_ERR_NO_MATCH: fprintf (stdout,"%% Unknown command: %s", vty->buf); break; case CMD_ERR_INCOMPLETE: fprintf (stdout,"%% Command incomplete.\n"); break; case CMD_SUCCESS_DAEMON: { u_int i; int cmd_stat = CMD_SUCCESS; for (i = 0; i < array_size(vtysh_client); i++) { if (cmd->daemon & vtysh_client[i].flag) { cmd_stat = vtysh_client_execute (&vtysh_client[i], vty->buf, stdout); if (cmd_stat != CMD_SUCCESS) break; } } if (cmd_stat != 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. */ static int vtysh_rl_describe (void) { int ret; unsigned int i; vector vline; vector describe; int width; struct cmd_token *token; vline = cmd_make_strvec (rl_line_buffer); /* In case of '> ?'. */ if (vline == NULL) { vline = vector_init (1); vector_set (vline, NULL); } else if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) vector_set (vline, NULL); describe = cmd_describe_command (vline, vty, &ret); fprintf (stdout,"\n"); /* Ambiguous and no match error. */ switch (ret) { case CMD_ERR_AMBIGUOUS: cmd_free_strvec (vline); fprintf (stdout,"%% Ambiguous command.\n"); rl_on_new_line (); return 0; break; case CMD_ERR_NO_MATCH: cmd_free_strvec (vline); fprintf (stdout,"%% 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_active (describe); i++) if ((token = vector_slot (describe, i)) != NULL) { int len; if (token->cmd[0] == '\0') continue; len = strlen (token->cmd); if (token->cmd[0] == '.') len--; if (width < len) width = len; } for (i = 0; i < vector_active (describe); i++) if ((token = vector_slot (describe, i)) != NULL) { if (token->cmd[0] == '\0') continue; if (! token->desc) fprintf (stdout," %-s\n", token->cmd[0] == '.' ? token->cmd + 1 : token->cmd); else fprintf (stdout," %-*s %s\n", width, token->cmd[0] == '.' ? token->cmd + 1 : token->cmd, token->desc); } 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; static char * command_generator (const 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, NULL); matched = cmd_complete_command (vline, vty, &complete_status); } if (matched && matched[index]) return matched[index++]; return NULL; } static char ** new_completion (char *text, int start, int end) { char **matches; matches = rl_completion_matches (text, command_generator); if (matches) { rl_point = rl_end; if (complete_status != CMD_COMPLETE_FULL_MATCH) /* only append a space on full match */ rl_completion_append_character = '\0'; } return matches; } #if 0 /* This function is not actually being used. */ static 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; } #endif /* Vty node structures. */ static struct cmd_node bgp_node = { BGP_NODE, "%s(config-router)# ", }; static struct cmd_node rip_node = { RIP_NODE, "%s(config-router)# ", }; static struct cmd_node isis_node = { ISIS_NODE, "%s(config-router)# ", }; static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", }; static struct cmd_node rmap_node = { RMAP_NODE, "%s(config-route-map)# " }; static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# " }; static struct cmd_node bgp_vpnv4_node = { BGP_VPNV4_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_vpnv6_node = { BGP_VPNV6_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_encap_node = { BGP_ENCAP_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_encapv6_node = { BGP_ENCAPV6_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv4_node = { BGP_IPV4_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv4m_node = { BGP_IPV4M_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv6_node = { BGP_IPV6_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv6m_node = { BGP_IPV6M_NODE, "%s(config-router-af)# " }; static struct cmd_node ospf_node = { OSPF_NODE, "%s(config-router)# " }; static struct cmd_node ripng_node = { RIPNG_NODE, "%s(config-router)# " }; static struct cmd_node ospf6_node = { OSPF6_NODE, "%s(config-ospf6)# " }; static struct cmd_node babel_node = { BABEL_NODE, "%s(config-babel)# " }; static struct cmd_node keychain_node = { KEYCHAIN_NODE, "%s(config-keychain)# " }; static struct cmd_node keychain_key_node = { KEYCHAIN_KEY_NODE, "%s(config-keychain-key)# " }; struct cmd_node link_params_node = { LINK_PARAMS_NODE, "%s(config-link-params)# ", }; /* Defined in lib/vty.c */ extern struct cmd_node vty_node; /* When '^Z' is received from vty, move down to the enable mode. */ static int vtysh_end (void) { 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 change to enable mode\n") { return vtysh_end (); } DEFUNSH (VTYSH_BGPD, router_bgp, router_bgp_cmd, "router bgp " CMD_AS_RANGE, ROUTER_STR BGP_STR AS_STR) { vty->node = BGP_NODE; return CMD_SUCCESS; } ALIAS_SH (VTYSH_BGPD, router_bgp, router_bgp_view_cmd, "router bgp " CMD_AS_RANGE " view WORD", ROUTER_STR BGP_STR AS_STR "BGP view\n" "view name\n") 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_vpnv6, address_family_vpnv6_cmd, "address-family vpnv6", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } DEFUNSH (VTYSH_BGPD, address_family_vpnv6_unicast, address_family_vpnv6_unicast_cmd, "address-family vpnv6 unicast", "Enter Address Family command mode\n" "Address family\n" "Address Family Modifier\n") { vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } DEFUNSH (VTYSH_BGPD, address_family_encap, address_family_encap_cmd, "address-family encap", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_ENCAP_NODE; return CMD_SUCCESS; } DEFUNSH (VTYSH_BGPD, address_family_encapv4, address_family_encapv4_cmd, "address-family encapv4", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_ENCAP_NODE; return CMD_SUCCESS; } DEFUNSH (VTYSH_BGPD, address_family_encapv6, address_family_encapv6_cmd, "address-family encapv6", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_ENCAPV6_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_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_BGPD, address_family_ipv6_multicast, address_family_ipv6_multicast_cmd, "address-family ipv6 multicast", "Enter Address Family command mode\n" "Address family\n" "Address Family Modifier\n") { vty->node = BGP_IPV6M_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_ISISD, router_isis, router_isis_cmd, "router isis WORD", ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag") { vty->node = ISIS_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; } DEFUNSH (VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty", "Configure a terminal line\n" "Virtual terminal\n") { vty->node = VTY_NODE; return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_enable, vtysh_enable_cmd, "enable", "Turn on privileged mode command\n") { vty->node = ENABLE_NODE; return CMD_SUCCESS; } 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; } 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; } static 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 BABEL_NODE: case ISIS_NODE: case MASC_NODE: case RMAP_NODE: case VTY_NODE: case KEYCHAIN_NODE: vtysh_execute("end"); vtysh_execute("configure terminal"); vty->node = CONFIG_NODE; break; case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: case BGP_ENCAP_NODE: case BGP_ENCAPV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: vty->node = BGP_NODE; break; case KEYCHAIN_KEY_NODE: vty->node = KEYCHAIN_NODE; break; case LINK_PARAMS_NODE: vty->node = INTERFACE_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_VPNV6_NODE || vty->node == BGP_ENCAP_NODE || vty->node == BGP_ENCAPV6_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_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_ISISD, vtysh_exit_isisd, vtysh_exit_isisd_cmd, "exit", "Exit current mode and down to previous mode\n") { return vtysh_exit (vty); } ALIAS (vtysh_exit_isisd, vtysh_quit_isisd_cmd, "quit", "Exit current mode and down to previous mode\n") DEFUNSH (VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit", "Exit current mode and down to previous mode\n") { return vtysh_exit (vty); } ALIAS (vtysh_exit_line_vty, vtysh_quit_line_vty_cmd, "quit", "Exit current mode and down to previous mode\n") DEFUNSH (VTYSH_INTERFACE, vtysh_interface, vtysh_interface_cmd, "interface IFNAME", "Select an interface to configure\n" "Interface's name\n") { vty->node = INTERFACE_NODE; return CMD_SUCCESS; } ALIAS_SH (VTYSH_ZEBRA, vtysh_interface, vtysh_interface_vrf_cmd, "interface IFNAME " VRF_CMD_STR, "Select an interface to configure\n" "Interface's name\n" VRF_CMD_HELP_STR) DEFSH (VTYSH_INTERFACE, vtysh_no_interface_cmd, "no interface IFNAME", NO_STR "Delete a pseudo interface's configuration\n" "Interface's name\n") DEFSH (VTYSH_ZEBRA, vtysh_no_interface_vrf_cmd, "no interface IFNAME " VRF_CMD_STR, NO_STR "Delete a pseudo interface's configuration\n" "Interface's name\n" VRF_CMD_HELP_STR) /* TODO Implement interface description commands in ripngd, ospf6d * and isisd. */ DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD, interface_desc_cmd, "description .LINE", "Interface specific description\n" "Characters describing this interface\n") DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_OSPFD, no_interface_desc_cmd, "no description", NO_STR "Interface specific description\n") DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, 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") DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, 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") DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, 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") DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, 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") DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, 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") DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, 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") DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, 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") DEFSH (VTYSH_RIPD|VTYSH_RIPNGD, 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") DEFSH (VTYSH_RIPNGD, ipv6_distribute_list_all_cmd, "ipv6 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_RIPNGD, no_ipv6_distribute_list_all_cmd, "no ipv6 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") DEFSH (VTYSH_RIPNGD, ipv6_distribute_list_cmd, "ipv6 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_ipv6_distribute_list_cmd, "no ipv6 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") DEFSH (VTYSH_RIPNGD, ipv6_distribute_list_prefix_all_cmd, "ipv6 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, no_ipv6_distribute_list_prefix_all_cmd, "no ipv6 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") DEFSH (VTYSH_RIPNGD, ipv6_distribute_list_prefix_cmd, "ipv6 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_RIPNGD, no_ipv6_distribute_list_prefix_cmd, "no ipv6 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") DEFUNSH (VTYSH_INTERFACE, 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_show_thread, vtysh_show_thread_cmd, "show thread cpu [FILTER]", SHOW_STR "Thread information\n" "Thread CPU usage\n" "Display filter (rwtexb)\n") { unsigned int i; int ret = CMD_SUCCESS; char line[100]; sprintf(line, "show thread cpu %s\n", (argc == 1) ? argv[0] : ""); for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) { fprintf (stdout, "Thread statistics for %s:\n", vtysh_client[i].name); ret = vtysh_client_execute (&vtysh_client[i], line, stdout); fprintf (stdout,"\n"); } return ret; } DEFUN (vtysh_show_work_queues, vtysh_show_work_queues_cmd, "show work-queues", SHOW_STR "Work Queue information\n") { unsigned int i; int ret = CMD_SUCCESS; char line[] = "show work-queues\n"; for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) { fprintf (stdout, "Work queue statistics for %s:\n", vtysh_client[i].name); ret = vtysh_client_execute (&vtysh_client[i], line, stdout); fprintf (stdout,"\n"); } return ret; } DEFUN (vtysh_show_work_queues_daemon, vtysh_show_work_queues_daemon_cmd, "show work-queues (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd)", SHOW_STR "Work Queue information\n" "For the zebra daemon\n" "For the rip daemon\n" "For the ripng daemon\n" "For the ospf daemon\n" "For the ospfv6 daemon\n" "For the bgp daemon\n" "For the isis daemon\n") { unsigned int i; int ret = CMD_SUCCESS; for (i = 0; i < array_size(vtysh_client); i++) { if (begins_with(vtysh_client[i].name, argv[0])) break; } ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n", stdout); return ret; } DEFUNSH (VTYSH_ZEBRA, vtysh_link_params, vtysh_link_params_cmd, "link-params", LINK_PARAMS_STR ) { vty->node = LINK_PARAMS_NODE; return CMD_SUCCESS; } DEFUNSH (VTYSH_ZEBRA, exit_link_params, exit_link_params_cmd, "exit-link-params", "Exit from Link Params configuration node\n") { if (vty->node == LINK_PARAMS_NODE) vty->node = INTERFACE_NODE; return CMD_SUCCESS; } /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, "show memory", SHOW_STR "Memory statistics\n") { unsigned int i; int ret = CMD_SUCCESS; char line[] = "show memory\n"; for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) { fprintf (stdout, "Memory statistics for %s:\n", vtysh_client[i].name); ret = vtysh_client_execute (&vtysh_client[i], line, stdout); fprintf (stdout,"\n"); } return ret; } /* Logging commands. */ DEFUN (vtysh_show_logging, vtysh_show_logging_cmd, "show logging", SHOW_STR "Show current logging configuration\n") { unsigned int i; int ret = CMD_SUCCESS; char line[] = "show logging\n"; for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) { fprintf (stdout,"Logging configuration for %s:\n", vtysh_client[i].name); ret = vtysh_client_execute (&vtysh_client[i], line, stdout); fprintf (stdout,"\n"); } return ret; } DEFUNSH (VTYSH_ALL, vtysh_log_stdout, vtysh_log_stdout_cmd, "log stdout", "Logging control\n" "Set stdout logging level\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_log_stdout_level, vtysh_log_stdout_level_cmd, "log stdout "LOG_LEVELS, "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC) { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, no_vtysh_log_stdout, no_vtysh_log_stdout_cmd, "no log stdout [LEVEL]", NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\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, vtysh_log_file_level, vtysh_log_file_level_cmd, "log file FILENAME "LOG_LEVELS, "Logging control\n" "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC) { 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; } ALIAS_SH (VTYSH_ALL, no_vtysh_log_file, no_vtysh_log_file_level_cmd, "no log file FILENAME LEVEL", NO_STR "Logging control\n" "Cancel logging to file\n" "Logging file name\n" "Logging level\n") DEFUNSH (VTYSH_ALL, vtysh_log_monitor, vtysh_log_monitor_cmd, "log monitor", "Logging control\n" "Set terminal line (monitor) logging level\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_log_monitor_level, vtysh_log_monitor_level_cmd, "log monitor "LOG_LEVELS, "Logging control\n" "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC) { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, no_vtysh_log_monitor, no_vtysh_log_monitor_cmd, "no log monitor [LEVEL]", NO_STR "Logging control\n" "Disable terminal line (monitor) logging\n" "Logging level\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_log_syslog, vtysh_log_syslog_cmd, "log syslog", "Logging control\n" "Set syslog logging level\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_log_syslog_level, vtysh_log_syslog_level_cmd, "log syslog "LOG_LEVELS, "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC) { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, no_vtysh_log_syslog, no_vtysh_log_syslog_cmd, "no log syslog [LEVEL]", NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_log_facility, vtysh_log_facility_cmd, "log facility "LOG_FACILITIES, "Logging control\n" "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd, "no log facility [FACILITY]", NO_STR "Logging control\n" "Reset syslog facility to default (daemon)\n" "Syslog facility\n") { return CMD_SUCCESS; } DEFUNSH_DEPRECATED (VTYSH_ALL, vtysh_log_trap, vtysh_log_trap_cmd, "log trap "LOG_LEVELS, "Logging control\n" "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC) { return CMD_SUCCESS; } DEFUNSH_DEPRECATED (VTYSH_ALL, no_vtysh_log_trap, no_vtysh_log_trap_cmd, "no log trap [LEVEL]", NO_STR "Logging control\n" "Permit all logging information\n" "Logging level\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; } DEFUNSH (VTYSH_ALL, vtysh_log_timestamp_precision, vtysh_log_timestamp_precision_cmd, "log timestamp precision <0-6>", "Logging control\n" "Timestamp configuration\n" "Set the timestamp precision\n" "Number of subsecond digits\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, no_vtysh_log_timestamp_precision, no_vtysh_log_timestamp_precision_cmd, "no log timestamp precision", NO_STR "Logging control\n" "Timestamp configuration\n" "Reset the timestamp precision to the default value of 0\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_service_password_encrypt, vtysh_service_password_encrypt_cmd, "service password-encryption", "Set up miscellaneous service\n" "Enable encrypted passwords\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, no_vtysh_service_password_encrypt, no_vtysh_service_password_encrypt_cmd, "no service password-encryption", NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_config_password, vtysh_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") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_password_text, vtysh_password_text_cmd, "password LINE", "Assign the terminal connection password\n" "The UNENCRYPTED (cleartext) line password\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_config_enable_password, vtysh_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") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_enable_password_text, vtysh_enable_password_text_cmd, "enable password LINE", "Modify enable password parameters\n" "Assign the privileged level password\n" "The UNENCRYPTED (cleartext) 'enable' password\n") { return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, no_vtysh_config_enable_password, no_vtysh_enable_password_cmd, "no enable password", NO_STR "Modify enable password parameters\n" "Assign the privileged level password\n") { return CMD_SUCCESS; } DEFUN (vtysh_write_terminal, vtysh_write_terminal_cmd, "write terminal", "Write running configuration to memory, network, or terminal\n" "Write to terminal\n") { u_int i; char line[] = "write terminal\n"; FILE *fp = NULL; if (vtysh_pager_name) { fp = popen (vtysh_pager_name, "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); vty_out (vty, "!%s", VTY_NEWLINE); for (i = 0; i < array_size(vtysh_client); i++) vtysh_client_execute (&vtysh_client[i], line, NULL); /* Integrate vtysh specific configuration. */ vtysh_config_write (); vtysh_config_dump (fp); if (vtysh_pager_name && fp) { fflush (fp); if (pclose (fp) == -1) { perror ("pclose"); exit (1); } fp = NULL; } vty_out (vty, "end%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (vtysh_write_terminal_daemon, vtysh_write_terminal_daemon_cmd, "write terminal (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|babeld)", "Write running configuration to memory, network, or terminal\n" "Write to terminal\n" "For the zebra daemon\n" "For the rip daemon\n" "For the ripng daemon\n" "For the ospf daemon\n" "For the ospfv6 daemon\n" "For the bgp daemon\n" "For the isis daemon\n" "For the babel daemon\n") { unsigned int i; int ret = CMD_SUCCESS; for (i = 0; i < array_size(vtysh_client); i++) { if (strcmp(vtysh_client[i].name, argv[0]) == 0) break; } if (i == array_size(vtysh_client)) return CMD_ERR_NO_MATCH; ret = vtysh_client_execute(&vtysh_client[i], "show running-config\n", stdout); return ret; } DEFUN (vtysh_integrated_config, vtysh_integrated_config_cmd, "service integrated-vtysh-config", "Set up miscellaneous service\n" "Write configuration into integrated file\n") { vtysh_writeconfig_integrated = 1; return CMD_SUCCESS; } DEFUN (no_vtysh_integrated_config, no_vtysh_integrated_config_cmd, "no service integrated-vtysh-config", NO_STR "Set up miscellaneous service\n" "Write configuration into integrated file\n") { vtysh_writeconfig_integrated = 0; return CMD_SUCCESS; } static int write_config_integrated(void) { u_int i; char line[] = "write terminal\n"; FILE *fp; char *integrate_sav = NULL; integrate_sav = malloc (strlen (integrate_default) + strlen (CONF_BACKUP_EXT) + 1); strcpy (integrate_sav, integrate_default); strcat (integrate_sav, CONF_BACKUP_EXT); fprintf (stdout,"Building Configuration...\n"); /* Move current configuration file to backup config file. */ unlink (integrate_sav); rename (integrate_default, integrate_sav); free (integrate_sav); fp = fopen (integrate_default, "w"); if (fp == NULL) { fprintf (stdout,"%% Can't open configuration file %s.\n", integrate_default); return CMD_SUCCESS; } for (i = 0; i < array_size(vtysh_client); i++) vtysh_client_execute (&vtysh_client[i], line, NULL); vtysh_config_write (); vtysh_config_dump (fp); fclose (fp); if (chmod (integrate_default, CONFIGFILE_MASK) != 0) { fprintf (stdout,"%% Can't chmod configuration file %s: %s (%d)\n", integrate_default, safe_strerror(errno), errno); return CMD_WARNING; } fprintf(stdout,"Integrated configuration saved to %s\n",integrate_default); fprintf (stdout,"[OK]\n"); 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 = CMD_SUCCESS; char line[] = "write memory\n"; u_int i; /* If integrated Quagga.conf explicitely set. */ if (vtysh_writeconfig_integrated) return write_config_integrated(); fprintf (stdout,"Building Configuration...\n"); for (i = 0; i < array_size(vtysh_client); i++) ret = vtysh_client_execute (&vtysh_client[i], line, stdout); fprintf (stdout,"[OK]\n"); return ret; } 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_memory, vtysh_write_cmd, "write", "Write running configuration to memory, network, or terminal\n") ALIAS (vtysh_write_terminal, vtysh_show_running_config_cmd, "show running-config", SHOW_STR "Current operating configuration\n") ALIAS (vtysh_write_terminal_daemon, vtysh_show_running_config_daemon_cmd, "show running-config (zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|babeld)", SHOW_STR "Current operating configuration\n" "For the zebra daemon\n" "For the rip daemon\n" "For the ripng daemon\n" "For the ospf daemon\n" "For the ospfv6 daemon\n" "For the bgp daemon\n" "For the isis daemon\n" "For the babel daemon\n") DEFUN (vtysh_terminal_length, vtysh_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; char default_pager[10]; 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; } if (vtysh_pager_name) { free (vtysh_pager_name); vtysh_pager_name = NULL; } if (lines != 0) { snprintf(default_pager, 10, "more -%i", lines); vtysh_pager_name = strdup (default_pager); } return CMD_SUCCESS; } DEFUN (vtysh_terminal_no_length, vtysh_terminal_no_length_cmd, "terminal no length", "Set terminal line parameters\n" NO_STR "Set number of lines on a screen\n") { if (vtysh_pager_name) { free (vtysh_pager_name); vtysh_pager_name = NULL; } vtysh_pager_init(); return CMD_SUCCESS; } DEFUN (vtysh_show_daemons, vtysh_show_daemons_cmd, "show daemons", SHOW_STR "Show list of running daemons\n") { u_int i; for (i = 0; i < array_size(vtysh_client); i++) if ( vtysh_client[i].fd >= 0 ) vty_out(vty, " %s", vtysh_client[i].name); vty_out(vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } /* Execute command in child process. */ static int execute_command (const char *command, int argc, const char *arg1, const char *arg2) { pid_t pid; int status; /* Call fork(). */ pid = fork (); if (pid < 0) { /* Failure of fork(). */ fprintf (stderr, "Can't fork: %s\n", safe_strerror (errno)); exit (1); } else if (pid == 0) { /* This is child process. */ switch (argc) { case 0: execlp (command, command, (const char *)NULL); break; case 1: execlp (command, command, arg1, (const char *)NULL); break; case 2: execlp (command, command, arg1, arg2, (const char *)NULL); break; } /* When execlp suceed, this part is not executed. */ fprintf (stderr, "Can't execute %s: %s\n", command, safe_strerror (errno)); exit (1); } else { /* This is parent. */ execute_flag = 1; 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; } ALIAS (vtysh_ping, vtysh_ping_ip_cmd, "ping ip WORD", "Send echo messages\n" "IP echo\n" "Ping destination address or hostname\n") 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; } ALIAS (vtysh_traceroute, vtysh_traceroute_ip_cmd, "traceroute ip WORD", "Trace route to destination\n" "IP trace\n" "Trace route to destination address or hostname\n") #ifdef HAVE_IPV6 DEFUN (vtysh_ping6, vtysh_ping6_cmd, "ping ipv6 WORD", "Send echo messages\n" "IPv6 echo\n" "Ping destination address or hostname\n") { execute_command ("ping6", 1, argv[0], NULL); return CMD_SUCCESS; } DEFUN (vtysh_traceroute6, vtysh_traceroute6_cmd, "traceroute ipv6 WORD", "Trace route to destination\n" "IPv6 trace\n" "Trace route to destination address or hostname\n") { execute_command ("traceroute6", 1, argv[0], NULL); return CMD_SUCCESS; } #endif 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_ssh, vtysh_ssh_cmd, "ssh WORD", "Open an ssh connection\n" "[user@]host\n") { execute_command ("ssh", 1, argv[0], NULL); 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; } static void vtysh_install_default (enum node_type node) { install_element (node, &config_list_cmd); } /* Making connection to protocol daemon. */ static int vtysh_connect (struct vtysh_client *vclient) { int ret; int sock, len; struct sockaddr_un addr; struct stat s_stat; /* Stat socket to see if we have permission to access it. */ ret = stat (vclient->path, &s_stat); if (ret < 0 && errno != ENOENT) { fprintf (stderr, "vtysh_connect(%s): stat = %s\n", vclient->path, safe_strerror(errno)); exit(1); } if (ret >= 0) { if (! S_ISSOCK(s_stat.st_mode)) { fprintf (stderr, "vtysh_connect(%s): Not a socket\n", vclient->path); exit (1); } } sock = socket (AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { #ifdef DEBUG fprintf(stderr, "vtysh_connect(%s): socket = %s\n", vclient->path, safe_strerror(errno)); #endif /* DEBUG */ return -1; } memset (&addr, 0, sizeof (struct sockaddr_un)); addr.sun_family = AF_UNIX; strncpy (addr.sun_path, vclient->path, strlen (vclient->path)); #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN len = addr.sun_len = SUN_LEN(&addr); #else len = sizeof (addr.sun_family) + strlen (addr.sun_path); #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ ret = connect (sock, (struct sockaddr *) &addr, len); if (ret < 0) { #ifdef DEBUG fprintf(stderr, "vtysh_connect(%s): connect = %s\n", vclient->path, safe_strerror(errno)); #endif /* DEBUG */ close (sock); return -1; } vclient->fd = sock; return 0; } int vtysh_connect_all(const char *daemon_name) { u_int i; int rc = 0; int matches = 0; for (i = 0; i < array_size(vtysh_client); i++) { if (!daemon_name || !strcmp(daemon_name, vtysh_client[i].name)) { matches++; if (vtysh_connect(&vtysh_client[i]) == 0) rc++; /* We need direct access to ripd in vtysh_exit_ripd_only. */ if (vtysh_client[i].flag == VTYSH_RIPD) ripd_client = &vtysh_client[i]; } } if (!matches) fprintf(stderr, "Error: no daemons match name %s!\n", daemon_name); return rc; } /* To disable readline's filename completion. */ static char * vtysh_completion_entry_function (const char *ignore, int invoking_key) { return NULL; } void vtysh_readline_init (void) { /* readline related settings. */ rl_bind_key ('?', (rl_command_func_t *) vtysh_rl_describe); rl_completion_entry_function = vtysh_completion_entry_function; rl_attempted_completion_function = (rl_completion_func_t *)new_completion; } char * vtysh_prompt (void) { static struct utsname names; static char buf[100]; const char*hostname; extern struct host host; hostname = host.name; if (!hostname) { if (!names.nodename[0]) uname (&names); hostname = names.nodename; } snprintf (buf, sizeof buf, cmd_prompt (vty->node), hostname); return buf; } void vtysh_init_vty (void) { /* 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 (&link_params_node, NULL); install_node (&rmap_node, NULL); install_node (&zebra_node, NULL); install_node (&bgp_vpnv4_node, NULL); install_node (&bgp_vpnv6_node, NULL); install_node (&bgp_encap_node, NULL); install_node (&bgp_encapv6_node, NULL); install_node (&bgp_ipv4_node, NULL); install_node (&bgp_ipv4m_node, NULL); /* #ifdef HAVE_IPV6 */ install_node (&bgp_ipv6_node, NULL); install_node (&bgp_ipv6m_node, NULL); /* #endif */ install_node (&ospf_node, NULL); /* #ifdef HAVE_IPV6 */ install_node (&ripng_node, NULL); install_node (&ospf6_node, NULL); /* #endif */ install_node (&babel_node, NULL); install_node (&keychain_node, NULL); install_node (&keychain_key_node, NULL); install_node (&isis_node, NULL); install_node (&vty_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 (LINK_PARAMS_NODE); vtysh_install_default (RMAP_NODE); vtysh_install_default (ZEBRA_NODE); vtysh_install_default (BGP_VPNV4_NODE); vtysh_install_default (BGP_VPNV6_NODE); vtysh_install_default (BGP_ENCAP_NODE); vtysh_install_default (BGP_ENCAPV6_NODE); vtysh_install_default (BGP_IPV4_NODE); vtysh_install_default (BGP_IPV4M_NODE); vtysh_install_default (BGP_IPV6_NODE); vtysh_install_default (BGP_IPV6M_NODE); vtysh_install_default (OSPF_NODE); vtysh_install_default (RIPNG_NODE); vtysh_install_default (OSPF6_NODE); vtysh_install_default (BABEL_NODE); vtysh_install_default (ISIS_NODE); vtysh_install_default (KEYCHAIN_NODE); vtysh_install_default (KEYCHAIN_KEY_NODE); vtysh_install_default (VTY_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_VPNV6_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_VPNV6_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_ENCAP_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_ENCAP_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_ENCAPV6_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_ENCAPV6_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 (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); install_element (ISIS_NODE, &vtysh_exit_isisd_cmd); install_element (ISIS_NODE, &vtysh_quit_isisd_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); install_element (VTY_NODE, &vtysh_exit_line_vty_cmd); install_element (VTY_NODE, &vtysh_quit_line_vty_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 (BABEL_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_VPNV6_NODE, &vtysh_end_all_cmd); install_element (BGP_ENCAP_NODE, &vtysh_end_all_cmd); install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element (ISIS_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 (VTY_NODE, &vtysh_end_all_cmd); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &vtysh_end_all_cmd); install_element (INTERFACE_NODE, &vtysh_exit_interface_cmd); install_element (LINK_PARAMS_NODE, &exit_link_params_cmd); install_element (LINK_PARAMS_NODE, &vtysh_end_all_cmd); install_element (LINK_PARAMS_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_isis_cmd); install_element (CONFIG_NODE, &router_bgp_cmd); install_element (CONFIG_NODE, &router_bgp_view_cmd); install_element (BGP_NODE, &address_family_vpnv4_cmd); install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); install_element (BGP_NODE, &address_family_vpnv6_cmd); install_element (BGP_NODE, &address_family_vpnv6_unicast_cmd); install_element (BGP_NODE, &address_family_encap_cmd); install_element (BGP_NODE, &address_family_encapv6_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); install_element (BGP_NODE, &address_family_ipv6_multicast_cmd); #endif install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); install_element (BGP_ENCAP_NODE, &exit_address_family_cmd); install_element (BGP_ENCAPV6_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 (BGP_IPV6M_NODE, &exit_address_family_cmd); install_element (CONFIG_NODE, &key_chain_cmd); install_element (CONFIG_NODE, &route_map_cmd); install_element (CONFIG_NODE, &vtysh_line_vty_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 (CONFIG_NODE, &vtysh_no_interface_cmd); install_element (CONFIG_NODE, &vtysh_interface_vrf_cmd); install_element (CONFIG_NODE, &vtysh_no_interface_vrf_cmd); install_element (INTERFACE_NODE, &vtysh_link_params_cmd); install_element (ENABLE_NODE, &vtysh_show_running_config_cmd); install_element (ENABLE_NODE, &vtysh_show_running_config_daemon_cmd); install_element (ENABLE_NODE, &vtysh_copy_runningconfig_startupconfig_cmd); install_element (ENABLE_NODE, &vtysh_write_file_cmd); install_element (ENABLE_NODE, &vtysh_write_cmd); /* distribute-list commands. (based on lib/distribute.c distribute_list_init()) */ 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); 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); install_element (RIPNG_NODE, &distribute_list_all_cmd); install_element (RIPNG_NODE, &no_distribute_list_all_cmd); install_element (RIPNG_NODE, &distribute_list_cmd); install_element (RIPNG_NODE, &no_distribute_list_cmd); install_element (RIPNG_NODE, &distribute_list_prefix_all_cmd); install_element (RIPNG_NODE, &no_distribute_list_prefix_all_cmd); install_element (RIPNG_NODE, &distribute_list_prefix_cmd); install_element (RIPNG_NODE, &no_distribute_list_prefix_cmd); /* "write terminal" command. */ install_element (ENABLE_NODE, &vtysh_write_terminal_cmd); install_element (ENABLE_NODE, &vtysh_write_terminal_daemon_cmd); install_element (CONFIG_NODE, &vtysh_integrated_config_cmd); install_element (CONFIG_NODE, &no_vtysh_integrated_config_cmd); /* "write memory" command. */ install_element (ENABLE_NODE, &vtysh_write_memory_cmd); install_element (VIEW_NODE, &vtysh_terminal_length_cmd); install_element (ENABLE_NODE, &vtysh_terminal_length_cmd); install_element (VIEW_NODE, &vtysh_terminal_no_length_cmd); install_element (ENABLE_NODE, &vtysh_terminal_no_length_cmd); install_element (VIEW_NODE, &vtysh_show_daemons_cmd); install_element (ENABLE_NODE, &vtysh_show_daemons_cmd); install_element (VIEW_NODE, &vtysh_ping_cmd); install_element (VIEW_NODE, &vtysh_ping_ip_cmd); install_element (VIEW_NODE, &vtysh_traceroute_cmd); install_element (VIEW_NODE, &vtysh_traceroute_ip_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &vtysh_ping6_cmd); install_element (VIEW_NODE, &vtysh_traceroute6_cmd); #endif install_element (VIEW_NODE, &vtysh_telnet_cmd); install_element (VIEW_NODE, &vtysh_telnet_port_cmd); install_element (VIEW_NODE, &vtysh_ssh_cmd); install_element (ENABLE_NODE, &vtysh_ping_cmd); install_element (ENABLE_NODE, &vtysh_ping_ip_cmd); install_element (ENABLE_NODE, &vtysh_traceroute_cmd); install_element (ENABLE_NODE, &vtysh_traceroute_ip_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &vtysh_ping6_cmd); install_element (ENABLE_NODE, &vtysh_traceroute6_cmd); #endif install_element (ENABLE_NODE, &vtysh_telnet_cmd); install_element (ENABLE_NODE, &vtysh_telnet_port_cmd); install_element (ENABLE_NODE, &vtysh_ssh_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 (VIEW_NODE, &vtysh_show_memory_cmd); install_element (ENABLE_NODE, &vtysh_show_memory_cmd); install_element (VIEW_NODE, &vtysh_show_work_queues_cmd); install_element (ENABLE_NODE, &vtysh_show_work_queues_cmd); install_element (ENABLE_NODE, &vtysh_show_work_queues_daemon_cmd); install_element (VIEW_NODE, &vtysh_show_work_queues_daemon_cmd); install_element (VIEW_NODE, &vtysh_show_thread_cmd); install_element (ENABLE_NODE, &vtysh_show_thread_cmd); /* Logging */ install_element (ENABLE_NODE, &vtysh_show_logging_cmd); install_element (VIEW_NODE, &vtysh_show_logging_cmd); install_element (CONFIG_NODE, &vtysh_log_stdout_cmd); install_element (CONFIG_NODE, &vtysh_log_stdout_level_cmd); install_element (CONFIG_NODE, &no_vtysh_log_stdout_cmd); install_element (CONFIG_NODE, &vtysh_log_file_cmd); install_element (CONFIG_NODE, &vtysh_log_file_level_cmd); install_element (CONFIG_NODE, &no_vtysh_log_file_cmd); install_element (CONFIG_NODE, &no_vtysh_log_file_level_cmd); install_element (CONFIG_NODE, &vtysh_log_monitor_cmd); install_element (CONFIG_NODE, &vtysh_log_monitor_level_cmd); install_element (CONFIG_NODE, &no_vtysh_log_monitor_cmd); install_element (CONFIG_NODE, &vtysh_log_syslog_cmd); install_element (CONFIG_NODE, &vtysh_log_syslog_level_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_facility_cmd); install_element (CONFIG_NODE, &no_vtysh_log_facility_cmd); install_element (CONFIG_NODE, &vtysh_log_record_priority_cmd); install_element (CONFIG_NODE, &no_vtysh_log_record_priority_cmd); install_element (CONFIG_NODE, &vtysh_log_timestamp_precision_cmd); install_element (CONFIG_NODE, &no_vtysh_log_timestamp_precision_cmd); install_element (CONFIG_NODE, &vtysh_service_password_encrypt_cmd); install_element (CONFIG_NODE, &no_vtysh_service_password_encrypt_cmd); install_element (CONFIG_NODE, &vtysh_password_cmd); install_element (CONFIG_NODE, &vtysh_password_text_cmd); install_element (CONFIG_NODE, &vtysh_enable_password_cmd); install_element (CONFIG_NODE, &vtysh_enable_password_text_cmd); install_element (CONFIG_NODE, &no_vtysh_enable_password_cmd); } quagga-1.2.4/vtysh/vtysh.conf.sample000066400000000000000000000002001325323223500174340ustar00rootroot00000000000000! ! Sample configuration file for vtysh. ! !service integrated-vtysh-config !hostname quagga-router !username root nopassword ! quagga-1.2.4/vtysh/vtysh.h000066400000000000000000000043101325323223500154640ustar00rootroot00000000000000/* 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_ISISD 0x40 #define VTYSH_BABELD 0x80 #define VTYSH_PIMD 0x100 #define VTYSH_NHRPD 0x200 #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD|VTYSH_NHRPD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_BABELD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD|VTYSH_PIMD|VTYSH_NHRPD /* vtysh local configuration file. */ #define VTYSH_DEFAULT_CONFIG "vtysh.conf" void vtysh_init_vty (void); void vtysh_init_cmd (void); extern int vtysh_connect_all (const char *optional_daemon_name); void vtysh_readline_init (void); void vtysh_user_init (void); int vtysh_execute (const char *); int vtysh_execute_no_pager (const char *); char *vtysh_prompt (void); void vtysh_config_write (void); int vtysh_config_from_file (struct vty *, FILE *); int vtysh_read_config (char *); void vtysh_config_parse (char *); void vtysh_config_dump (FILE *); void vtysh_config_init (void); void vtysh_pager_init (void); /* Child process execution flag. */ extern int execute_flag; extern struct vty *vty; #endif /* VTYSH_H */ quagga-1.2.4/vtysh/vtysh_config.c000066400000000000000000000276151325323223500170210ustar00rootroot00000000000000/* 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; extern int vtysh_writeconfig_integrated; 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; static int line_cmp (char *c1, char *c2) { return strcmp (c1, c2); } static void line_del (char *line) { XFREE (MTYPE_VTYSH_CONFIG_LINE, line); } static struct config * config_new () { struct config *config; config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config)); return config; } static int config_cmp (struct config *c1, struct config *c2) { return strcmp (c1->name, c2->name); } static 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); } static struct config * config_get (int index, const char *line) { struct config *config; struct config *config_loop; struct list *master; struct listnode *node, *nnode; 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); } for (ALL_LIST_ELEMENTS (master, node, nnode, config_loop)) { 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; } static void config_add_line (struct list *config, const char *line) { listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); } static void config_add_line_uniq (struct list *config, const char *line) { struct listnode *node, *nnode; char *pnt; for (ALL_LIST_ELEMENTS (config, node, nnode, pnt)) { if (strcmp (pnt, line) == 0) return; } listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); } static void vtysh_config_parse_line (const 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 vpn6", strlen (" address-family vpn6")) == 0) config = config_get (BGP_VPNV6_NODE, line); else if (strncmp (line, " address-family encapv6", strlen (" address-family encapv6")) == 0) config = config_get (BGP_ENCAPV6_NODE, line); else if (strncmp (line, " address-family encap", strlen (" address-family encap")) == 0) config = config_get (BGP_ENCAP_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 (strncmp (line, " link-params", strlen (" link-params")) == 0) { config_add_line (config->line, line); config->index = LINK_PARAMS_NODE; } else if (config->index == LINK_PARAMS_NODE && strncmp (line, " exit-link-params", strlen (" exit")) == 0) { config_add_line (config->line, line); config->index = INTERFACE_NODE; } else if (config->index == RMAP_NODE || config->index == INTERFACE_NODE || config->index == VTY_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-id", strlen ("router-id")) == 0) config = config_get (ZEBRA_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 isis", strlen ("router isis")) == 0) config = config_get (ISIS_NODE, line); else if (strncmp (line, "router bgp", strlen ("router bgp")) == 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, "line", strlen ("line")) == 0) config = config_get (VTY_NODE, line); else if ( (strncmp (line, "ipv6 forwarding", strlen ("ipv6 forwarding")) == 0) || (strncmp (line, "ip forwarding", strlen ("ip forwarding")) == 0) ) config = config_get (FORWARDING_NODE, line); else if (strncmp (line, "service", strlen ("service")) == 0) config = config_get (SERVICE_NODE, line); else if (strncmp (line, "debug", strlen ("debug")) == 0) config = config_get (DEBUG_NODE, line); else if (strncmp (line, "password", strlen ("password")) == 0 || strncmp (line, "enable password", strlen ("enable password")) == 0) config = config_get (AAA_NODE, line); else if (strncmp (line, "ip protocol", strlen ("ip protocol")) == 0) config = config_get (PROTOCOL_NODE, line); else { if (strncmp (line, "log", strlen ("log")) == 0 || strncmp (line, "hostname", 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 \ || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \ || (I) == AAA_NODE) /* Display configuration to file pointer. */ void vtysh_config_dump (FILE *fp) { struct listnode *node, *nnode; struct listnode *mnode, *mnnode; struct config *config; struct list *master; char *line; unsigned int i; for (ALL_LIST_ELEMENTS (config_top, node, nnode, line)) { fprintf (fp, "%s\n", line); fflush (fp); } fprintf (fp, "!\n"); fflush (fp); for (i = 0; i < vector_active (configvec); i++) if ((master = vector_slot (configvec, i)) != NULL) { for (ALL_LIST_ELEMENTS (master, node, nnode, config)) { fprintf (fp, "%s\n", config->name); fflush (fp); for (ALL_LIST_ELEMENTS (config->line, mnode, mnnode, line)) { 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_active (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 occurred during reading below line.\n%s\n", vty->buf); exit (1); } } /* Read up configuration file from config_default_dir. */ int vtysh_read_config (char *config_default_dir) { FILE *confp = NULL; confp = fopen (config_default_dir, "r"); if (confp == NULL) return (1); vtysh_read_file (confp); fclose (confp); host_config_set (config_default_dir); return (0); } /* We don't write vtysh specific into file from vtysh. vtysh.conf should * be edited by hand. So, we handle only "write terminal" case here and * integrate vtysh specific conf with conf from daemons. */ void vtysh_config_write () { char line[81]; extern struct host host; if (host.name) { sprintf (line, "hostname %s", host.name); vtysh_config_parse_line(line); } if (vtysh_writeconfig_integrated) vtysh_config_parse_line ("service integrated-vtysh-config"); } void vtysh_config_init () { config_top = list_new (); config_top->del = (void (*) (void *))line_del; configvec = vector_init (1); } quagga-1.2.4/vtysh/vtysh_main.c000066400000000000000000000235241325323223500164730ustar00rootroot00000000000000/* 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 #include "getopt.h" #include "command.h" #include "memory.h" #include "vtysh/vtysh.h" #include "vtysh/vtysh_user.h" /* VTY shell program name. */ char *progname; /* Configuration file name and directory. */ char config_default[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG; char history_file[MAXPATHLEN]; /* 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; /* Command logging */ FILE *logfile; /* SIGTSTP handler. This function care user's ^Z input. */ static 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. */ static void sigint (int sig) { /* Check this process is not child process. */ if (! execute_flag) { rl_initialize (); printf ("\n"); rl_forced_update_display (); } } /* Signale wrapper for vtysh. We don't use sigevent because * vtysh doesn't use threads. TODO */ static void vtysh_signal_set (int signo, void (*func)(int)) { 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 */ sigaction (signo, &sig, &osig); } /* Initialization of signal handles. */ static void vtysh_signal_init () { vtysh_signal_set (SIGINT, sigint); vtysh_signal_set (SIGTSTP, sigtstp); vtysh_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" \ "Integrated shell for Quagga routing software suite. \n\n" \ "-b, --boot Execute boot startup configuration\n" \ "-c, --command Execute argument as command\n" \ "-d, --daemon Connect only to the specified daemon\n" \ "-E, --echo Echo prompt and command in -c mode\n" \ "-C, --dryrun Check configuration for validity and exit\n" \ "-h, --help Display this help and exit\n\n" \ "Note that multiple commands may be executed from the command\n" \ "line by passing multiple -c args, or by embedding linefeed\n" \ "characters in one or more of the commands.\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'}, /* For compatibility with older zebra/quagga versions */ { "eval", required_argument, NULL, 'e'}, { "command", required_argument, NULL, 'c'}, { "daemon", required_argument, NULL, 'd'}, { "echo", no_argument, NULL, 'E'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { "noerror", no_argument, NULL, 'n'}, { 0 } }; /* Read a string, and return a pointer to it. Returns NULL on EOF. */ static char * vtysh_rl_gets () { HIST_ENTRY *last; /* 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. But only if * last command in history isn't the same one. */ if (line_read && *line_read) { using_history(); last = previous_history(); if (!last || strcmp (last->line, line_read) != 0) { add_history (line_read); append_history(1,history_file); } } return (line_read); } static void log_it(const char *line) { time_t t = time(NULL); struct tm *tmp = localtime(&t); const char *user = getenv("USER"); char tod[64]; if (!user) user = "boot"; strftime(tod, sizeof tod, "%Y%m%d-%H:%M.%S", tmp); fprintf(logfile, "%s:%s %s\n", tod, user, line); } /* VTY shell main routine. */ int main (int argc, char **argv, char **env) { char *p; int opt; int dryrun = 0; int boot_flag = 0; const char *daemon_name = NULL; struct cmd_rec { const char *line; struct cmd_rec *next; } *cmd = NULL; struct cmd_rec *tail = NULL; int echo_command = 0; int no_error = 0; char *homedir = NULL; /* Preserve name of myself. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); /* if logging open now */ if ((p = getenv("VTYSH_LOG")) != NULL) logfile = fopen(p, "a"); /* Option handling. */ while (1) { opt = getopt_long (argc, argv, "be:c:d:nEhC", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'b': boot_flag = 1; break; case 'e': case 'c': { struct cmd_rec *cr; cr = XMALLOC(MTYPE_TMP, sizeof(*cr)); cr->line = optarg; cr->next = NULL; if (tail) tail->next = cr; else cmd = cr; tail = cr; } break; case 'd': daemon_name = optarg; break; case 'n': no_error = 1; break; case 'E': echo_command = 1; break; case 'C': dryrun = 1; break; case 'h': usage (0); break; default: usage (1); break; } } /* Initialize user input buffer. */ line_read = NULL; setlinebuf(stdout); /* Signal and others. */ vtysh_signal_init (); /* Make vty structure and register commands. */ vtysh_init_vty (); vtysh_init_cmd (); vtysh_user_init (); vtysh_config_init (); vty_init_vtysh (); /* Read vtysh configuration file before connecting to daemons. */ vtysh_read_config (config_default); /* Start execution only if not in dry-run mode */ if(dryrun) return(0); /* Ignore error messages */ if (no_error) freopen("/dev/null", "w", stdout); /* Make sure we pass authentication before proceeding. */ vtysh_auth (); /* Do not connect until we have passed authentication. */ if (vtysh_connect_all (daemon_name) <= 0) { fprintf(stderr, "Exiting: failed to connect to any daemons.\n"); exit(1); } /* * Setup history file for use by both -c and regular input * If we can't find the home directory, then don't store * the history information */ homedir = vtysh_get_home (); if (homedir) { snprintf(history_file, sizeof(history_file), "%s/.history_quagga", homedir); if (read_history (history_file) != 0) { int fp; fp = open (history_file, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fp) close (fp); read_history (history_file); } } /* If eval mode. */ if (cmd) { /* Enter into enable node. */ vtysh_execute ("enable"); while (cmd != NULL) { int ret; char *eol; while ((eol = strchr(cmd->line, '\n')) != NULL) { *eol = '\0'; add_history (cmd->line); append_history (1, history_file); if (echo_command) printf("%s%s\n", vtysh_prompt(), cmd->line); if (logfile) log_it(cmd->line); ret = vtysh_execute_no_pager(cmd->line); if (!no_error && ! (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING)) exit(1); cmd->line = eol+1; } add_history (cmd->line); append_history (1, history_file); if (echo_command) printf("%s%s\n", vtysh_prompt(), cmd->line); if (logfile) log_it(cmd->line); ret = vtysh_execute_no_pager(cmd->line); if (!no_error && ! (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING)) exit(1); { struct cmd_rec *cr; cr = cmd; cmd = cmd->next; XFREE(0, cr); } } history_truncate_file(history_file,1000); exit (0); } /* Boot startup configuration file. */ if (boot_flag) { if (vtysh_read_config (integrate_default)) { fprintf (stderr, "Can't open configuration file [%s]\n", integrate_default); exit (1); } else exit (0); } vtysh_pager_init (); vtysh_readline_init (); vty_hello (vty); /* Enter into enable node. */ vtysh_execute ("enable"); /* Preparation for longjmp() in sigtstp(). */ sigsetjmp (jmpbuf, 1); jmpflag = 1; /* Main command loop. */ while (vtysh_rl_gets ()) vtysh_execute (line_read); history_truncate_file(history_file,1000); printf ("\n"); /* Rest in peace. */ exit (0); } quagga-1.2.4/vtysh/vtysh_user.c000066400000000000000000000102431325323223500165170ustar00rootroot00000000000000/* 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 #include #ifdef USE_PAM #include #ifdef HAVE_PAM_MISC_H #include #endif #ifdef HAVE_OPENPAM_H #include #endif #endif /* USE_PAM */ #include "memory.h" #include "linklist.h" #include "command.h" #include "vtysh_user.h" #ifdef USE_PAM static struct pam_conv conv = { PAM_CONV_FUNC, NULL }; static int vtysh_pam (const char *user) { int ret; pam_handle_t *pamh = NULL; /* Start PAM. */ ret = pam_start(QUAGGA_PROGNAME, user, &conv, &pamh); /* printf ("ret %d\n", ret); */ /* Is user really user? */ if (ret == PAM_SUCCESS) ret = pam_authenticate (pamh, 0); if (ret != PAM_SUCCESS) printf("Not authenticated. Check /etc/pam.d/quagga.\n"); /* 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 vtysh_user { char *name; u_char nopassword; }; struct list *userlist; static struct vtysh_user * user_new () { return XCALLOC (MTYPE_TMP, sizeof (struct vtysh_user)); } #if 0 static void user_free (struct vtysh_user *user) { XFREE (0, user); } #endif static struct vtysh_user * user_lookup (const char *name) { struct listnode *node, *nnode; struct vtysh_user *user; for (ALL_LIST_ELEMENTS (userlist, node, nnode, user)) { if (strcmp (user->name, name) == 0) return user; } return NULL; } #if 0 static void user_config_write () { struct listnode *node, *nnode; struct vtysh_user *user; for (ALL_LIST_ELEMENTS (userlist, node, nnode, user)) { if (user->nopassword) printf (" username %s nopassword\n", user->name); } } #endif static struct vtysh_user * user_get (const char *name) { struct vtysh_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 vtysh_user *user; user = user_get (argv[0]); user->nopassword = 1; return CMD_SUCCESS; } int vtysh_auth (void) { struct vtysh_user *user; struct passwd *passwd; if ((passwd = getpwuid (geteuid ())) == NULL) { fprintf (stderr, "could not lookup user ID %d\n", (int) geteuid()); exit (1); } 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; } char * vtysh_get_home (void) { struct passwd *passwd; passwd = getpwuid (getuid ()); return passwd ? passwd->pw_dir : NULL; } void vtysh_user_init (void) { userlist = list_new (); install_element (CONFIG_NODE, &username_nopassword_cmd); } quagga-1.2.4/vtysh/vtysh_user.h000066400000000000000000000017411325323223500165270ustar00rootroot00000000000000/* 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 (void); void vtysh_user_init (void); char *vtysh_get_home (void); #endif /* _VTYSH_USER_H */ quagga-1.2.4/watchquagga/000077500000000000000000000000001325323223500152575ustar00rootroot00000000000000quagga-1.2.4/watchquagga/Makefile.am000066400000000000000000000004721325323223500173160ustar00rootroot00000000000000## Process this file with Automake to create Makefile.in AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" AM_CFLAGS = $(WERROR) sbin_PROGRAMS = watchquagga watchquagga_SOURCES = watchquagga.c watchquagga_LDADD = ../lib/libzebra.la @LIBCAP@ quagga-1.2.4/watchquagga/Makefile.in000066400000000000000000000511371325323223500173330ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = watchquagga$(EXEEXT) subdir = watchquagga ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am_watchquagga_OBJECTS = watchquagga.$(OBJEXT) watchquagga_OBJECTS = $(am_watchquagga_OBJECTS) watchquagga_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(watchquagga_SOURCES) DIST_SOURCES = $(watchquagga_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) watchquagga_SOURCES = watchquagga.c watchquagga_LDADD = ../lib/libzebra.la @LIBCAP@ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu watchquagga/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu watchquagga/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list watchquagga$(EXEEXT): $(watchquagga_OBJECTS) $(watchquagga_DEPENDENCIES) $(EXTRA_watchquagga_DEPENDENCIES) @rm -f watchquagga$(EXEEXT) $(AM_V_CCLD)$(LINK) $(watchquagga_OBJECTS) $(watchquagga_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watchquagga.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool clean-sbinPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS .PRECIOUS: Makefile # 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: quagga-1.2.4/watchquagga/watchquagga.c000066400000000000000000001133341325323223500177240ustar00rootroot00000000000000/* Monitor status of quagga daemons and restart if necessary. Copyright (C) 2004 Andrew J. Schorr This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #ifndef MIN #define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y)) #endif /* Macros to help randomize timers. */ #define JITTER(X) ((random() % ((X)+1))-((X)/2)) #define FUZZY(X) ((X)+JITTER((X)/20)) #define DEFAULT_PERIOD 5 #define DEFAULT_TIMEOUT 10 #define DEFAULT_RESTART_TIMEOUT 20 #define DEFAULT_LOGLEVEL LOG_INFO #define DEFAULT_MIN_RESTART 60 #define DEFAULT_MAX_RESTART 600 #ifdef PATH_WATCHQUAGGA_PID #define DEFAULT_PIDFILE PATH_WATCHQUAGGA_PID #else #define DEFAULT_PIDFILE STATEDIR "/watchquagga.pid" #endif #ifdef DAEMON_VTY_DIR #define VTYDIR DAEMON_VTY_DIR #else #define VTYDIR STATEDIR #endif #define PING_TOKEN "PING" /* Needs to be global, referenced somewhere inside libzebra. */ struct thread_master *master; typedef enum { MODE_MONITOR = 0, MODE_GLOBAL_RESTART, MODE_SEPARATE_RESTART, MODE_PHASED_ZEBRA_RESTART, MODE_PHASED_ALL_RESTART } watch_mode_t; static const char *mode_str[] = { "monitor", "global restart", "individual daemon restart", "phased zebra restart", "phased global restart for any failure", }; typedef enum { PHASE_NONE = 0, PHASE_STOPS_PENDING, PHASE_WAITING_DOWN, PHASE_ZEBRA_RESTART_PENDING, PHASE_WAITING_ZEBRA_UP } restart_phase_t; static const char *phase_str[] = { "None", "Stop jobs running", "Waiting for other daemons to come down", "Zebra restart job running", "Waiting for zebra to come up", "Start jobs running", }; #define PHASE_TIMEOUT (3*gs.restart_timeout) struct restart_info { const char *name; const char *what; pid_t pid; struct timeval time; long interval; struct thread *t_kill; int kills; }; static struct global_state { watch_mode_t mode; restart_phase_t phase; struct thread *t_phase_hanging; const char *vtydir; long period; long timeout; long restart_timeout; long min_restart_interval; long max_restart_interval; int do_ping; struct daemon *daemons; const char *restart_command; const char *start_command; const char *stop_command; struct restart_info restart; int unresponsive_restart; int loglevel; struct daemon *special; /* points to zebra when doing phased restart */ int numdaemons; int numpids; int numdown; /* # of daemons that are not UP or UNRESPONSIVE */ } gs = { .mode = MODE_MONITOR, .phase = PHASE_NONE, .vtydir = VTYDIR, .period = 1000*DEFAULT_PERIOD, .timeout = DEFAULT_TIMEOUT, .restart_timeout = DEFAULT_RESTART_TIMEOUT, .loglevel = DEFAULT_LOGLEVEL, .min_restart_interval = DEFAULT_MIN_RESTART, .max_restart_interval = DEFAULT_MAX_RESTART, .do_ping = 1, }; typedef enum { DAEMON_INIT, DAEMON_DOWN, DAEMON_CONNECTING, DAEMON_UP, DAEMON_UNRESPONSIVE } daemon_state_t; #define IS_UP(DMN) \ (((DMN)->state == DAEMON_UP) || ((DMN)->state == DAEMON_UNRESPONSIVE)) static const char *state_str[] = { "Init", "Down", "Connecting", "Up", "Unresponsive", }; struct daemon { const char *name; daemon_state_t state; int fd; struct timeval echo_sent; u_int connect_tries; struct thread *t_wakeup; struct thread *t_read; struct thread *t_write; struct daemon *next; struct restart_info restart; }; static const struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "statedir", required_argument, NULL, 'S'}, { "no-echo", no_argument, NULL, 'e'}, { "loglevel", required_argument, NULL, 'l'}, { "interval", required_argument, NULL, 'i'}, { "timeout", required_argument, NULL, 't'}, { "restart-timeout", required_argument, NULL, 'T'}, { "restart", required_argument, NULL, 'r'}, { "start-command", required_argument, NULL, 's'}, { "kill-command", required_argument, NULL, 'k'}, { "restart-all", required_argument, NULL, 'R'}, { "all-restart", no_argument, NULL, 'a'}, { "always-all-restart", no_argument, NULL, 'A'}, { "unresponsive-restart", no_argument, NULL, 'z'}, { "min-restart-interval", required_argument, NULL, 'm'}, { "max-restart-interval", required_argument, NULL, 'M'}, { "pid-file", required_argument, NULL, 'p'}, { "blank-string", required_argument, NULL, 'b'}, { "help", no_argument, NULL, 'h'}, { "version", no_argument, NULL, 'v'}, { NULL, 0, NULL, 0 } }; static int try_connect(struct daemon *dmn); static int wakeup_send_echo(struct thread *t_wakeup); static void try_restart(struct daemon *dmn); static void phase_check(void); static int usage(const char *progname, int status) { if (status != 0) fprintf(stderr, "Try `%s --help' for more information.\n", progname); else { printf("Usage : %s [OPTION...] ...\n\n\ Watchdog program to monitor status of quagga daemons and try to restart\n\ them if they are down or unresponsive. It determines whether a daemon is\n\ up based on whether it can connect to the daemon's vty unix stream socket.\n\ It then repeatedly sends echo commands over that socket to determine whether\n\ the daemon is responsive. If the daemon crashes, we will receive an EOF\n\ on the socket connection and know immediately that the daemon is down.\n\n\ The daemons to be monitored should be listed on the command line.\n\n\ This program can run in one of 5 modes:\n\n\ 0. Mode: %s.\n\ Just monitor and report on status changes. Example:\n\ %s -d zebra ospfd bgpd\n\n\ 1. Mode: %s.\n\ Whenever any daemon hangs or crashes, use the given command to restart\n\ them all. Example:\n\ %s -dz \\\n\ -R '/sbin/service zebra restart; /sbin/service ospfd restart' \\\n\ zebra ospfd\n\n\ 2. Mode: %s.\n\ When any single daemon hangs or crashes, restart only the daemon that's\n\ in trouble using the supplied restart command. Example:\n\ %s -dz -r '/sbin/service %%s restart' zebra ospfd bgpd\n\n\ 3. Mode: %s.\n\ The same as the previous mode, except that there is special treatment when\n\ the zebra daemon is in trouble. In that case, a phased restart approach\n\ is used: 1. stop all other daemons; 2. restart zebra; 3. start the other\n\ daemons. Example:\n\ %s -adz -r '/sbin/service %%s restart' \\\n\ -s '/sbin/service %%s start' \\\n\ -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ 4. Mode: %s.\n\ This is the same as the previous mode, except that the phased restart\n\ procedure is used whenever any of the daemons hangs or crashes. Example:\n\ %s -Adz -r '/sbin/service %%s restart' \\\n\ -s '/sbin/service %%s start' \\\n\ -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ As of this writing, it is believed that mode 2 [%s]\n\ is not safe, and mode 3 [%s] may not be safe with some of the\n\ routing daemons.\n\n\ In order to avoid attempting to restart the daemons in a fast loop,\n\ the -m and -M options allow you to control the minimum delay between\n\ restart commands. The minimum restart delay is recalculated each time\n\ a restart is attempted: if the time since the last restart attempt exceeds\n\ twice the -M value, then the restart delay is set to the -m value.\n\ Otherwise, the interval is doubled (but capped at the -M value).\n\n", progname,mode_str[0],progname,mode_str[1],progname,mode_str[2], progname,mode_str[3],progname,mode_str[4],progname,mode_str[2], mode_str[3]); printf("Options:\n\ -d, --daemon Run in daemon mode. In this mode, error messages are sent\n\ to syslog instead of stdout.\n\ -S, --statedir Set the vty socket directory (default is %s)\n\ -e, --no-echo Do not ping the daemons to test responsiveness (this\n\ option is necessary if the daemons do not support the\n\ echo command)\n\ -l, --loglevel Set the logging level (default is %d).\n\ The value should range from %d (LOG_EMERG) to %d (LOG_DEBUG),\n\ but it can be set higher than %d if extra-verbose debugging\n\ messages are desired.\n\ -m, --min-restart-interval\n\ Set the minimum seconds to wait between invocations of daemon\n\ restart commands (default is %d).\n\ -M, --max-restart-interval\n\ Set the maximum seconds to wait between invocations of daemon\n\ restart commands (default is %d).\n\ -i, --interval Set the status polling interval in seconds (default is %d)\n\ -t, --timeout Set the unresponsiveness timeout in seconds (default is %d)\n\ -T, --restart-timeout\n\ Set the restart (kill) timeout in seconds (default is %d).\n\ If any background jobs are still running after this much\n\ time has elapsed, they will be killed.\n\ -r, --restart Supply a Bourne shell command to use to restart a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ Note that -r and -R are incompatible.\n\ -s, --start-command\n\ Supply a Bourne shell to command to use to start a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ -k, --kill-command\n\ Supply a Bourne shell to command to use to stop a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ -R, --restart-all\n\ When one or more daemons is down, try to restart everything\n\ using the Bourne shell command supplied as the argument.\n\ Note that -r and -R are incompatible.\n\ -z, --unresponsive-restart\n\ When a daemon is unresponsive, treat it as being down for\n\ restart purposes.\n\ -a, --all-restart\n\ When zebra hangs or crashes, restart all daemons using\n\ this phased approach: 1. stop all other daemons; 2. restart\n\ zebra; 3. start other daemons. Requires -r, -s, and -k.\n\ -A, --always-all-restart\n\ When any daemon (not just zebra) hangs or crashes, use the\n\ same phased restart mechanism described above for -a.\n\ Requires -r, -s, and -k.\n\ -p, --pid-file Set process identifier file name\n\ (default is %s).\n\ -b, --blank-string\n\ When the supplied argument string is found in any of the\n\ various shell command arguments (-r, -s, -k, or -R), replace\n\ it with a space. This is an ugly hack to circumvent problems\n\ passing command-line arguments with embedded spaces.\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n", VTYDIR,DEFAULT_LOGLEVEL,LOG_EMERG,LOG_DEBUG,LOG_DEBUG, DEFAULT_MIN_RESTART,DEFAULT_MAX_RESTART, DEFAULT_PERIOD,DEFAULT_TIMEOUT,DEFAULT_RESTART_TIMEOUT, DEFAULT_PIDFILE); } return status; } static pid_t run_background(char *shell_cmd) { pid_t child; switch (child = fork()) { case -1: zlog_err("fork failed, cannot run command [%s]: %s", shell_cmd,safe_strerror(errno)); return -1; case 0: /* Child process. */ /* Use separate process group so child processes can be killed easily. */ if (setpgid(0,0) < 0) zlog_warn("warning: setpgid(0,0) failed: %s",safe_strerror(errno)); { char shell[] = "sh"; char dashc[] = "-c"; char *const argv[4] = { shell, dashc, shell_cmd, NULL}; execv("/bin/sh", argv); zlog_err("execv(/bin/sh -c '%s') failed: %s", shell_cmd,safe_strerror(errno)); _exit(127); } default: /* Parent process: we will reap the child later. */ zlog_err("Forked background command [pid %d]: %s",(int)child,shell_cmd); return child; } } static struct timeval * time_elapsed(struct timeval *result, const struct timeval *start_time) { gettimeofday(result,NULL); result->tv_sec -= start_time->tv_sec; result->tv_usec -= start_time->tv_usec; while (result->tv_usec < 0) { result->tv_usec += 1000000L; result->tv_sec--; } return result; } static int restart_kill(struct thread *t_kill) { struct restart_info *restart = THREAD_ARG(t_kill); struct timeval delay; time_elapsed(&delay,&restart->time); zlog_warn("Warning: %s %s child process %d still running after " "%ld seconds, sending signal %d", restart->what,restart->name,(int)restart->pid, (long)delay.tv_sec, (restart->kills ? SIGKILL : SIGTERM)); kill(-restart->pid,(restart->kills ? SIGKILL : SIGTERM)); restart->kills++; restart->t_kill = thread_add_timer(master,restart_kill,restart, gs.restart_timeout); return 0; } static struct restart_info * find_child(pid_t child) { if (gs.mode == MODE_GLOBAL_RESTART) { if (gs.restart.pid == child) return &gs.restart; } else { struct daemon *dmn; for (dmn = gs.daemons; dmn; dmn = dmn->next) { if (dmn->restart.pid == child) return &dmn->restart; } } return NULL; } static void sigchild(void) { pid_t child; int status; const char *name; const char *what; struct restart_info *restart; switch (child = waitpid(-1,&status,WNOHANG)) { case -1: zlog_err("waitpid failed: %s",safe_strerror(errno)); return; case 0: zlog_warn("SIGCHLD received, but waitpid did not reap a child"); return; } if ((restart = find_child(child)) != NULL) { name = restart->name; what = restart->what; restart->pid = 0; gs.numpids--; thread_cancel(restart->t_kill); restart->t_kill = NULL; /* Update restart time to reflect the time the command completed. */ gettimeofday(&restart->time,NULL); } else { zlog_err("waitpid returned status for an unknown child process %d", (int)child); name = "(unknown)"; what = "background"; } if (WIFSTOPPED(status)) zlog_warn("warning: %s %s process %d is stopped", what,name,(int)child); else if (WIFSIGNALED(status)) zlog_warn("%s %s process %d terminated due to signal %d", what,name,(int)child,WTERMSIG(status)); else if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) zlog_warn("%s %s process %d exited with non-zero status %d", what,name,(int)child,WEXITSTATUS(status)); else zlog_debug("%s %s process %d exited normally",what,name,(int)child); } else zlog_err("cannot interpret %s %s process %d wait status 0x%x", what,name,(int)child,status); phase_check(); } static int run_job(struct restart_info *restart, const char *cmdtype, const char *command, int force, int update_interval) { struct timeval delay; if (gs.loglevel > LOG_DEBUG+1) zlog_debug("attempting to %s %s",cmdtype,restart->name); if (restart->pid) { if (gs.loglevel > LOG_DEBUG+1) zlog_debug("cannot %s %s, previous pid %d still running", cmdtype,restart->name,(int)restart->pid); return -1; } /* Note: time_elapsed test must come before the force test, since we need to make sure that delay is initialized for use below in updating the restart interval. */ if ((time_elapsed(&delay,&restart->time)->tv_sec < restart->interval) && !force) { if (gs.loglevel > LOG_DEBUG+1) zlog_debug("postponing %s %s: " "elapsed time %ld < retry interval %ld", cmdtype,restart->name,(long)delay.tv_sec,restart->interval); return -1; } gettimeofday(&restart->time,NULL); restart->kills = 0; { char cmd[strlen(command)+strlen(restart->name)+1]; snprintf(cmd,sizeof(cmd),command,restart->name); if ((restart->pid = run_background(cmd)) > 0) { restart->t_kill = thread_add_timer(master,restart_kill,restart, gs.restart_timeout); restart->what = cmdtype; gs.numpids++; } else restart->pid = 0; } /* Calculate the new restart interval. */ if (update_interval) { if (delay.tv_sec > 2*gs.max_restart_interval) restart->interval = gs.min_restart_interval; else if ((restart->interval *= 2) > gs.max_restart_interval) restart->interval = gs.max_restart_interval; if (gs.loglevel > LOG_DEBUG+1) zlog_debug("restart %s interval is now %ld", restart->name,restart->interval); } return restart->pid; } #define SET_READ_HANDLER(DMN) \ (DMN)->t_read = thread_add_read(master,handle_read,(DMN),(DMN)->fd) #define SET_WAKEUP_DOWN(DMN) \ (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_down,(DMN), \ FUZZY(gs.period)) #define SET_WAKEUP_UNRESPONSIVE(DMN) \ (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_unresponsive,(DMN), \ FUZZY(gs.period)) #define SET_WAKEUP_ECHO(DMN) \ (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_send_echo,(DMN), \ FUZZY(gs.period)) static int wakeup_down(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; if (try_connect(dmn) < 0) SET_WAKEUP_DOWN(dmn); if ((dmn->connect_tries > 1) && (dmn->state != DAEMON_UP)) try_restart(dmn); return 0; } static int wakeup_init(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; if (try_connect(dmn) < 0) { SET_WAKEUP_DOWN(dmn); zlog_err("%s state -> down : initial connection attempt failed", dmn->name); dmn->state = DAEMON_DOWN; } return 0; } static void daemon_down(struct daemon *dmn, const char *why) { if (IS_UP(dmn) || (dmn->state == DAEMON_INIT)) zlog_err("%s state -> down : %s",dmn->name,why); else if (gs.loglevel > LOG_DEBUG) zlog_debug("%s still down : %s",dmn->name,why); if (IS_UP(dmn)) gs.numdown++; dmn->state = DAEMON_DOWN; if (dmn->fd >= 0) { close(dmn->fd); dmn->fd = -1; } THREAD_OFF(dmn->t_read); THREAD_OFF(dmn->t_write); THREAD_OFF(dmn->t_wakeup); if (try_connect(dmn) < 0) SET_WAKEUP_DOWN(dmn); phase_check(); } static int handle_read(struct thread *t_read) { struct daemon *dmn = THREAD_ARG(t_read); static const char resp[sizeof(PING_TOKEN)+4] = PING_TOKEN "\n"; char buf[sizeof(resp)+100]; ssize_t rc; struct timeval delay; dmn->t_read = NULL; if ((rc = read(dmn->fd,buf,sizeof(buf))) < 0) { char why[100]; if (ERRNO_IO_RETRY(errno)) { /* Pretend it never happened. */ SET_READ_HANDLER(dmn); return 0; } snprintf(why,sizeof(why),"unexpected read error: %s", safe_strerror(errno)); daemon_down(dmn,why); return 0; } if (rc == 0) { daemon_down(dmn,"read returned EOF"); return 0; } if (!dmn->echo_sent.tv_sec) { char why[sizeof(buf)+100]; snprintf(why,sizeof(why),"unexpected read returns %d bytes: %.*s", (int)rc,(int)rc,buf); daemon_down(dmn,why); return 0; } /* We are expecting an echo response: is there any chance that the response would not be returned entirely in the first read? That seems inconceivable... */ if ((rc != sizeof(resp)) || memcmp(buf,resp,sizeof(resp))) { char why[100+sizeof(buf)]; snprintf(why,sizeof(why),"read returned bad echo response of %d bytes " "(expecting %u): %.*s", (int)rc,(u_int)sizeof(resp),(int)rc,buf); daemon_down(dmn,why); return 0; } time_elapsed(&delay,&dmn->echo_sent); dmn->echo_sent.tv_sec = 0; if (dmn->state == DAEMON_UNRESPONSIVE) { if (delay.tv_sec < gs.timeout) { dmn->state = DAEMON_UP; zlog_warn("%s state -> up : echo response received after %ld.%06ld " "seconds", dmn->name, (long)delay.tv_sec, (long)delay.tv_usec); } else zlog_warn("%s: slow echo response finally received after %ld.%06ld " "seconds", dmn->name, (long)delay.tv_sec, (long)delay.tv_usec); } else if (gs.loglevel > LOG_DEBUG+1) zlog_debug("%s: echo response received after %ld.%06ld seconds", dmn->name, (long)delay.tv_sec, (long)delay.tv_usec); SET_READ_HANDLER(dmn); if (dmn->t_wakeup) thread_cancel(dmn->t_wakeup); SET_WAKEUP_ECHO(dmn); return 0; } static void daemon_up(struct daemon *dmn, const char *why) { dmn->state = DAEMON_UP; gs.numdown--; dmn->connect_tries = 0; zlog_notice("%s state -> up : %s",dmn->name,why); if (gs.do_ping) SET_WAKEUP_ECHO(dmn); phase_check(); } static int check_connect(struct thread *t_write) { struct daemon *dmn = THREAD_ARG(t_write); int sockerr; socklen_t reslen = sizeof(sockerr); dmn->t_write = NULL; if (getsockopt(dmn->fd,SOL_SOCKET,SO_ERROR,(char *)&sockerr,&reslen) < 0) { zlog_warn("%s: check_connect: getsockopt failed: %s", dmn->name,safe_strerror(errno)); daemon_down(dmn,"getsockopt failed checking connection success"); return 0; } if ((reslen == sizeof(sockerr)) && sockerr) { char why[100]; snprintf(why,sizeof(why), "getsockopt reports that connection attempt failed: %s", safe_strerror(sockerr)); daemon_down(dmn,why); return 0; } daemon_up(dmn,"delayed connect succeeded"); return 0; } static int wakeup_connect_hanging(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); char why[100]; dmn->t_wakeup = NULL; snprintf(why,sizeof(why),"connection attempt timed out after %ld seconds", gs.timeout); daemon_down(dmn,why); return 0; } /* Making connection to protocol daemon. */ static int try_connect(struct daemon *dmn) { int sock; struct sockaddr_un addr; socklen_t len; if (gs.loglevel > LOG_DEBUG+1) zlog_debug("%s: attempting to connect",dmn->name); dmn->connect_tries++; memset (&addr, 0, sizeof (struct sockaddr_un)); addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s.vty", gs.vtydir,dmn->name); #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN len = addr.sun_len = SUN_LEN(&addr); #else len = sizeof (addr.sun_family) + strlen (addr.sun_path); #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ /* Quick check to see if we might succeed before we go to the trouble of creating a socket. */ if (access(addr.sun_path, W_OK) < 0) { if (errno != ENOENT) zlog_err("%s: access to socket %s denied: %s", dmn->name,addr.sun_path,safe_strerror(errno)); return -1; } if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { zlog_err("%s(%s): cannot make socket: %s", __func__,addr.sun_path, safe_strerror(errno)); return -1; } if (set_nonblocking(sock) < 0) { zlog_err("%s(%s): set_nonblocking(%d) failed", __func__, addr.sun_path, sock); close(sock); return -1; } if (connect (sock, (struct sockaddr *) &addr, len) < 0) { if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { if (gs.loglevel > LOG_DEBUG) zlog_debug("%s(%s): connect failed: %s", __func__,addr.sun_path, safe_strerror(errno)); close (sock); return -1; } if (gs.loglevel > LOG_DEBUG) zlog_debug("%s: connection in progress",dmn->name); dmn->state = DAEMON_CONNECTING; dmn->fd = sock; dmn->t_write = thread_add_write(master,check_connect,dmn,dmn->fd); dmn->t_wakeup = thread_add_timer(master,wakeup_connect_hanging,dmn, gs.timeout); SET_READ_HANDLER(dmn); return 0; } dmn->fd = sock; SET_READ_HANDLER(dmn); daemon_up(dmn,"connect succeeded"); return 1; } static int phase_hanging(struct thread *t_hanging) { gs.t_phase_hanging = NULL; zlog_err("Phase [%s] hanging for %ld seconds, aborting phased restart", phase_str[gs.phase],PHASE_TIMEOUT); gs.phase = PHASE_NONE; return 0; } static void set_phase(restart_phase_t new_phase) { gs.phase = new_phase; if (gs.t_phase_hanging) thread_cancel(gs.t_phase_hanging); gs.t_phase_hanging = thread_add_timer(master,phase_hanging,NULL, PHASE_TIMEOUT); } static void phase_check(void) { switch (gs.phase) { case PHASE_NONE: break; case PHASE_STOPS_PENDING: if (gs.numpids) break; zlog_info("Phased restart: all routing daemon stop jobs have completed."); set_phase(PHASE_WAITING_DOWN); /*FALLTHRU*/ case PHASE_WAITING_DOWN: if (gs.numdown+IS_UP(gs.special) < gs.numdaemons) break; zlog_info("Phased restart: all routing daemons now down."); run_job(&gs.special->restart,"restart",gs.restart_command,1,1); set_phase(PHASE_ZEBRA_RESTART_PENDING); /*FALLTHRU*/ case PHASE_ZEBRA_RESTART_PENDING: if (gs.special->restart.pid) break; zlog_info("Phased restart: %s restart job completed.",gs.special->name); set_phase(PHASE_WAITING_ZEBRA_UP); /*FALLTHRU*/ case PHASE_WAITING_ZEBRA_UP: if (!IS_UP(gs.special)) break; zlog_info("Phased restart: %s is now up.",gs.special->name); { struct daemon *dmn; for (dmn = gs.daemons; dmn; dmn = dmn->next) { if (dmn != gs.special) run_job(&dmn->restart,"start",gs.start_command,1,0); } } gs.phase = PHASE_NONE; THREAD_OFF(gs.t_phase_hanging); zlog_notice("Phased global restart has completed."); break; } } static void try_restart(struct daemon *dmn) { switch (gs.mode) { case MODE_MONITOR: return; case MODE_GLOBAL_RESTART: run_job(&gs.restart,"restart",gs.restart_command,0,1); break; case MODE_SEPARATE_RESTART: run_job(&dmn->restart,"restart",gs.restart_command,0,1); break; case MODE_PHASED_ZEBRA_RESTART: if (dmn != gs.special) { if ((gs.special->state == DAEMON_UP) && (gs.phase == PHASE_NONE)) run_job(&dmn->restart,"restart",gs.restart_command,0,1); else zlog_debug("%s: postponing restart attempt because master %s daemon " "not up [%s], or phased restart in progress", dmn->name,gs.special->name,state_str[gs.special->state]); break; } /*FALLTHRU*/ case MODE_PHASED_ALL_RESTART: if ((gs.phase != PHASE_NONE) || gs.numpids) { if (gs.loglevel > LOG_DEBUG+1) zlog_debug("postponing phased global restart: restart already in " "progress [%s], or outstanding child processes [%d]", phase_str[gs.phase],gs.numpids); break; } /* Is it too soon for a restart? */ { struct timeval delay; if (time_elapsed(&delay,&gs.special->restart.time)->tv_sec < gs.special->restart.interval) { if (gs.loglevel > LOG_DEBUG+1) zlog_debug("postponing phased global restart: " "elapsed time %ld < retry interval %ld", (long)delay.tv_sec,gs.special->restart.interval); break; } } zlog_info("Phased restart: stopping all routing daemons."); /* First step: stop all other daemons. */ for (dmn = gs.daemons; dmn; dmn = dmn->next) { if (dmn != gs.special) run_job(&dmn->restart,"stop",gs.stop_command,1,1); } set_phase(PHASE_STOPS_PENDING); break; default: zlog_err("error: unknown restart mode %d",gs.mode); break; } } static int wakeup_unresponsive(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; if (dmn->state != DAEMON_UNRESPONSIVE) zlog_err("%s: no longer unresponsive (now %s), " "wakeup should have been cancelled!", dmn->name,state_str[dmn->state]); else { SET_WAKEUP_UNRESPONSIVE(dmn); try_restart(dmn); } return 0; } static int wakeup_no_answer(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; dmn->state = DAEMON_UNRESPONSIVE; zlog_err("%s state -> unresponsive : no response yet to ping " "sent %ld seconds ago",dmn->name,gs.timeout); if (gs.unresponsive_restart) { SET_WAKEUP_UNRESPONSIVE(dmn); try_restart(dmn); } return 0; } static int wakeup_send_echo(struct thread *t_wakeup) { static const char echocmd[] = "echo " PING_TOKEN; ssize_t rc; struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; if (((rc = write(dmn->fd,echocmd,sizeof(echocmd))) < 0) || ((size_t)rc != sizeof(echocmd))) { char why[100+sizeof(echocmd)]; snprintf(why,sizeof(why),"write '%s' returned %d instead of %u", echocmd,(int)rc,(u_int)sizeof(echocmd)); daemon_down(dmn,why); } else { gettimeofday(&dmn->echo_sent,NULL); dmn->t_wakeup = thread_add_timer(master,wakeup_no_answer,dmn,gs.timeout); } return 0; } static void sigint(void) { zlog_notice("Terminating on signal"); exit(0); } static int valid_command(const char *cmd) { char *p; return ((p = strchr(cmd,'%')) != NULL) && (*(p+1) == 's') && !strchr(p+1,'%'); } /* This is an ugly hack to circumvent problems with passing command-line arguments that contain spaces. The fix is to use a configuration file. */ static char * translate_blanks(const char *cmd, const char *blankstr) { char *res; char *p; size_t bslen = strlen(blankstr); if (!(res = strdup(cmd))) { perror("strdup"); exit(1); } while ((p = strstr(res,blankstr)) != NULL) { *p = ' '; if (bslen != 1) memmove(p+1,p+bslen,strlen(p+bslen)+1); } return res; } int main(int argc, char **argv) { const char *progname; int opt; int daemon_mode = 0; const char *pidfile = DEFAULT_PIDFILE; const char *special = "zebra"; const char *blankstr = NULL; static struct quagga_signal_t my_signals[] = { { .signal = SIGINT, .handler = sigint, }, { .signal = SIGTERM, .handler = sigint, }, { .signal = SIGCHLD, .handler = sigchild, }, }; if ((progname = strrchr (argv[0], '/')) != NULL) progname++; else progname = argv[0]; gs.restart.name = "all"; while ((opt = getopt_long(argc, argv, "aAb:dek:l:m:M:i:p:r:R:S:s:t:T:zvh", longopts, 0)) != EOF) { switch (opt) { case 0: break; case 'a': if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART)) { fputs("Ambiguous operating mode selected.\n",stderr); return usage(progname,1); } gs.mode = MODE_PHASED_ZEBRA_RESTART; break; case 'A': if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART)) { fputs("Ambiguous operating mode selected.\n",stderr); return usage(progname,1); } gs.mode = MODE_PHASED_ALL_RESTART; break; case 'b': blankstr = optarg; break; case 'd': daemon_mode = 1; break; case 'e': gs.do_ping = 0; break; case 'k': if (!valid_command(optarg)) { fprintf(stderr,"Invalid kill command, must contain '%%s': %s\n", optarg); return usage(progname,1); } gs.stop_command = optarg; break; case 'l': { char garbage[3]; if ((sscanf(optarg,"%d%1s",&gs.loglevel,garbage) != 1) || (gs.loglevel < LOG_EMERG)) { fprintf(stderr,"Invalid loglevel argument: %s\n",optarg); return usage(progname,1); } } break; case 'm': { char garbage[3]; if ((sscanf(optarg,"%ld%1s", &gs.min_restart_interval,garbage) != 1) || (gs.min_restart_interval < 0)) { fprintf(stderr,"Invalid min_restart_interval argument: %s\n", optarg); return usage(progname,1); } } break; case 'M': { char garbage[3]; if ((sscanf(optarg,"%ld%1s", &gs.max_restart_interval,garbage) != 1) || (gs.max_restart_interval < 0)) { fprintf(stderr,"Invalid max_restart_interval argument: %s\n", optarg); return usage(progname,1); } } break; case 'i': { char garbage[3]; int period; if ((sscanf(optarg,"%d%1s",&period,garbage) != 1) || (gs.period < 1)) { fprintf(stderr,"Invalid interval argument: %s\n",optarg); return usage(progname,1); } gs.period = 1000*period; } break; case 'p': pidfile = optarg; break; case 'r': if ((gs.mode == MODE_GLOBAL_RESTART) || (gs.mode == MODE_SEPARATE_RESTART)) { fputs("Ambiguous operating mode selected.\n",stderr); return usage(progname,1); } if (!valid_command(optarg)) { fprintf(stderr, "Invalid restart command, must contain '%%s': %s\n", optarg); return usage(progname,1); } gs.restart_command = optarg; if (gs.mode == MODE_MONITOR) gs.mode = MODE_SEPARATE_RESTART; break; case 'R': if (gs.mode != MODE_MONITOR) { fputs("Ambiguous operating mode selected.\n",stderr); return usage(progname,1); } if (strchr(optarg,'%')) { fprintf(stderr, "Invalid restart-all arg, must not contain '%%s': %s\n", optarg); return usage(progname,1); } gs.restart_command = optarg; gs.mode = MODE_GLOBAL_RESTART; break; case 's': if (!valid_command(optarg)) { fprintf(stderr,"Invalid start command, must contain '%%s': %s\n", optarg); return usage(progname,1); } gs.start_command = optarg; break; case 'S': gs.vtydir = optarg; break; case 't': { char garbage[3]; if ((sscanf(optarg,"%ld%1s",&gs.timeout,garbage) != 1) || (gs.timeout < 1)) { fprintf(stderr,"Invalid timeout argument: %s\n",optarg); return usage(progname,1); } } break; case 'T': { char garbage[3]; if ((sscanf(optarg,"%ld%1s",&gs.restart_timeout,garbage) != 1) || (gs.restart_timeout < 1)) { fprintf(stderr,"Invalid restart timeout argument: %s\n",optarg); return usage(progname,1); } } break; case 'z': gs.unresponsive_restart = 1; break; case 'v': printf ("%s version %s\n", progname, QUAGGA_VERSION); puts("Copyright 2004 Andrew J. Schorr"); return 0; case 'h': return usage(progname,0); default: fputs("Invalid option.\n",stderr); return usage(progname,1); } } if (gs.unresponsive_restart && (gs.mode == MODE_MONITOR)) { fputs("Option -z requires a -r or -R restart option.\n",stderr); return usage(progname,1); } switch (gs.mode) { case MODE_MONITOR: if (gs.restart_command || gs.start_command || gs.stop_command) { fprintf(stderr,"No kill/(re)start commands needed for %s mode.\n", mode_str[gs.mode]); return usage(progname,1); } break; case MODE_GLOBAL_RESTART: case MODE_SEPARATE_RESTART: if (!gs.restart_command || gs.start_command || gs.stop_command) { fprintf(stderr,"No start/kill commands needed in [%s] mode.\n", mode_str[gs.mode]); return usage(progname,1); } break; case MODE_PHASED_ZEBRA_RESTART: case MODE_PHASED_ALL_RESTART: if (!gs.restart_command || !gs.start_command || !gs.stop_command) { fprintf(stderr, "Need start, kill, and restart commands in [%s] mode.\n", mode_str[gs.mode]); return usage(progname,1); } break; } if (blankstr) { if (gs.restart_command) gs.restart_command = translate_blanks(gs.restart_command,blankstr); if (gs.start_command) gs.start_command = translate_blanks(gs.start_command,blankstr); if (gs.stop_command) gs.stop_command = translate_blanks(gs.stop_command,blankstr); } gs.restart.interval = gs.min_restart_interval; master = thread_master_create(); signal_init (master, array_size(my_signals), my_signals); srandom(time(NULL)); { int i; struct daemon *tail = NULL; for (i = optind; i < argc; i++) { struct daemon *dmn; if (!(dmn = (struct daemon *)calloc(1,sizeof(*dmn)))) { fprintf(stderr,"calloc(1,%u) failed: %s\n", (u_int)sizeof(*dmn), safe_strerror(errno)); return 1; } dmn->name = dmn->restart.name = argv[i]; dmn->state = DAEMON_INIT; gs.numdaemons++; gs.numdown++; dmn->fd = -1; dmn->t_wakeup = thread_add_timer_msec(master,wakeup_init,dmn, 100+(random() % 900)); dmn->restart.interval = gs.min_restart_interval; if (tail) tail->next = dmn; else gs.daemons = dmn; tail = dmn; if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) || (gs.mode == MODE_PHASED_ALL_RESTART)) && !strcmp(dmn->name,special)) gs.special = dmn; } } if (!gs.daemons) { fputs("Must specify one or more daemons to monitor.\n",stderr); return usage(progname,1); } if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) || (gs.mode == MODE_PHASED_ALL_RESTART)) && !gs.special) { fprintf(stderr,"In mode [%s], but cannot find master daemon %s\n", mode_str[gs.mode],special); return usage(progname,1); } if (gs.special && (gs.numdaemons < 2)) { fprintf(stderr,"Mode [%s] does not make sense with only 1 daemon " "to watch.\n",mode_str[gs.mode]); return usage(progname,1); } zlog_default = openzlog(progname, ZLOG_NONE, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); if (daemon_mode) { zlog_set_level(NULL, ZLOG_DEST_SYSLOG, MIN(gs.loglevel,LOG_DEBUG)); if (daemon (0, 0) < 0) { fprintf(stderr, "Watchquagga daemon failed: %s", strerror(errno)); exit (1); } } else zlog_set_level(NULL, ZLOG_DEST_STDOUT, MIN(gs.loglevel,LOG_DEBUG)); /* Make sure we're not already running. */ pid_output (pidfile); /* Announce which daemons are being monitored. */ { struct daemon *dmn; size_t len = 0; for (dmn = gs.daemons; dmn; dmn = dmn->next) len += strlen(dmn->name)+1; { char buf[len+1]; char *p = buf; for (dmn = gs.daemons; dmn; dmn = dmn->next) { if (p != buf) *p++ = ' '; strcpy(p,dmn->name); p += strlen(p); } zlog_notice("%s %s watching [%s], mode [%s]", progname, QUAGGA_VERSION, buf, mode_str[gs.mode]); } } thread_main (master); /* Not reached. */ return 0; } quagga-1.2.4/zebra/000077500000000000000000000000001325323223500140665ustar00rootroot00000000000000quagga-1.2.4/zebra/GNOME-PRODUCT-ZEBRA-MIB000066400000000000000000000037001325323223500172420ustar00rootroot00000000000000GNOME-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 quagga-1.2.4/zebra/GNOME-SMI000066400000000000000000000021731325323223500153070ustar00rootroot00000000000000GNOME-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 quagga-1.2.4/zebra/Makefile.am000066400000000000000000000041251325323223500161240ustar00rootroot00000000000000include ../common.am ## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 LIBCAP = @LIBCAP@ ipforward = @IPFORWARD@ if_method = @IF_METHOD@ rt_method = @RT_METHOD@ rtread_method = @RTREAD_METHOD@ kernel_method = @KERNEL_METHOD@ ioctl_method = @IOCTL_METHOD@ otherobj = $(ioctl_method) $(ipforward) $(if_method) \ $(rt_method) $(rtread_method) $(kernel_method) if HAVE_NETLINK othersrc = zebra_fpm_netlink.c endif if HAVE_PROTOBUF protobuf_srcs = zebra_fpm_protobuf.c endif if DEV_BUILD dev_srcs = zebra_fpm_dt.c endif AM_CFLAGS = $(WERROR) sbin_PROGRAMS = zebra noinst_PROGRAMS = testzebra zebra_SOURCES = \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ zebra_rnh.c \ $(othersrc) $(protobuf_srcs) $(dev_srcs) testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c \ kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.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 router-id.h kernel_socket.h \ rt_netlink.h zebra_fpm.h zebra_fpm_private.h \ ioctl_solaris.h zebra_rnh.h zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS) testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) zebra_DEPENDENCIES = $(otherobj) EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \ if_sysctl.c ipforward_proc.c \ ipforward_solaris.c ipforward_sysctl.c rt_netlink.c \ rt_socket.c rtread_netlink.c rtread_sysctl.c \ rtread_getmsg.c kernel_socket.c kernel_netlink.c \ ioctl.c ioctl_solaris.c \ GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB client : client_main.o ../lib/libzebra.la $(CC) -g -o client client_main.o ../liblzebra.la $(LIBS) $(LIB_IPV6) quaggaconfdir = $(sysconfdir) examplesdir = $(exampledir) dist_examples_DATA = zebra.conf.sample quagga-1.2.4/zebra/Makefile.in000066400000000000000000000736051325323223500161460ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ # # Automake fragment intended to be shared by Makefile.am files in the # tree. # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = zebra$(EXEEXT) noinst_PROGRAMS = testzebra$(EXEEXT) subdir = zebra ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_examples_DATA) \ $(noinst_HEADERS) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(noinst_PROGRAMS) $(sbin_PROGRAMS) am_testzebra_OBJECTS = test_main.$(OBJEXT) zebra_rib.$(OBJEXT) \ interface.$(OBJEXT) connected.$(OBJEXT) debug.$(OBJEXT) \ zebra_vty.$(OBJEXT) kernel_null.$(OBJEXT) \ redistribute_null.$(OBJEXT) ioctl_null.$(OBJEXT) \ misc_null.$(OBJEXT) zebra_rnh_null.$(OBJEXT) testzebra_OBJECTS = $(am_testzebra_OBJECTS) am__DEPENDENCIES_1 = testzebra_DEPENDENCIES = ../lib/libzebra.la $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am__zebra_SOURCES_DIST = zserv.c main.c interface.c connected.c \ zebra_rib.c zebra_routemap.c redistribute.c debug.c rtadv.c \ zebra_snmp.c zebra_vty.c irdp_main.c irdp_interface.c \ irdp_packet.c router-id.c zebra_fpm.c zebra_rnh.c \ zebra_fpm_netlink.c zebra_fpm_protobuf.c zebra_fpm_dt.c @HAVE_NETLINK_TRUE@am__objects_1 = zebra_fpm_netlink.$(OBJEXT) @HAVE_PROTOBUF_TRUE@am__objects_2 = zebra_fpm_protobuf.$(OBJEXT) @DEV_BUILD_TRUE@am__objects_3 = zebra_fpm_dt.$(OBJEXT) am_zebra_OBJECTS = zserv.$(OBJEXT) main.$(OBJEXT) interface.$(OBJEXT) \ connected.$(OBJEXT) zebra_rib.$(OBJEXT) \ zebra_routemap.$(OBJEXT) redistribute.$(OBJEXT) \ debug.$(OBJEXT) rtadv.$(OBJEXT) zebra_snmp.$(OBJEXT) \ zebra_vty.$(OBJEXT) irdp_main.$(OBJEXT) \ irdp_interface.$(OBJEXT) irdp_packet.$(OBJEXT) \ router-id.$(OBJEXT) zebra_fpm.$(OBJEXT) zebra_rnh.$(OBJEXT) \ $(am__objects_1) $(am__objects_2) $(am__objects_3) zebra_OBJECTS = $(am_zebra_OBJECTS) am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) @HAVE_PROTOBUF_TRUE@am__DEPENDENCIES_3 = \ @HAVE_PROTOBUF_TRUE@ $(top_srcdir)/qpb/libquagga_pb.la \ @HAVE_PROTOBUF_TRUE@ $(am__DEPENDENCIES_1) @HAVE_PROTOBUF_TRUE@am__DEPENDENCIES_4 = \ @HAVE_PROTOBUF_TRUE@ $(top_srcdir)/fpm/libfpm_pb.la \ @HAVE_PROTOBUF_TRUE@ $(am__DEPENDENCIES_3) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(testzebra_SOURCES) $(zebra_SOURCES) DIST_SOURCES = $(testzebra_SOURCES) $(am__zebra_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/../common.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BGPD = @BGPD@ CARES_CFLAGS = @CARES_CFLAGS@ CARES_LIBS = @CARES_LIBS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NHRPD = @NHRPD@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PANDOC = @PANDOC@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PIMD = @PIMD@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ PROTOC_C = @PROTOC_C@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ WERROR = @WERROR@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # Uncomment to use an non-system version of libprotobuf-c. # # Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src # Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_INCLUDES = @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_LDOPTS = -lprotobuf-c @HAVE_PROTOBUF_TRUE@Q_PROTOC = protoc @HAVE_PROTOBUF_TRUE@Q_PROTOC_C = protoc-c @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_CFILES = $(filter %.pb-c.c,$(SOURCES)) @HAVE_PROTOBUF_TRUE@Q_PROTOBUF_SRCS = $(Q_PROTOBUF_CFILES) $(Q_PROTOBUF_HFILES) # # Information about how to link to various libraries. # @HAVE_PROTOBUF_TRUE@Q_QUAGGA_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libquagga_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS) @HAVE_PROTOBUF_TRUE@Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfpm_pb.la $(Q_QUAGGA_PB_CLIENT_LDOPTS) Q_CLEANFILES = $(Q_PROTOBUF_SRCS) Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS) AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 ipforward = @IPFORWARD@ if_method = @IF_METHOD@ rt_method = @RT_METHOD@ rtread_method = @RTREAD_METHOD@ kernel_method = @KERNEL_METHOD@ ioctl_method = @IOCTL_METHOD@ otherobj = $(ioctl_method) $(ipforward) $(if_method) \ $(rt_method) $(rtread_method) $(kernel_method) @HAVE_NETLINK_TRUE@othersrc = zebra_fpm_netlink.c @HAVE_PROTOBUF_TRUE@protobuf_srcs = zebra_fpm_protobuf.c @DEV_BUILD_TRUE@dev_srcs = zebra_fpm_dt.c AM_CFLAGS = $(WERROR) zebra_SOURCES = \ zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \ irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \ zebra_rnh.c \ $(othersrc) $(protobuf_srcs) $(dev_srcs) testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \ zebra_vty.c \ kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.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 router-id.h kernel_socket.h \ rt_netlink.h zebra_fpm.h zebra_fpm_private.h \ ioctl_solaris.h zebra_rnh.h zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS) testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) zebra_DEPENDENCIES = $(otherobj) EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \ if_sysctl.c ipforward_proc.c \ ipforward_solaris.c ipforward_sysctl.c rt_netlink.c \ rt_socket.c rtread_netlink.c rtread_sysctl.c \ rtread_getmsg.c kernel_socket.c kernel_netlink.c \ ioctl.c ioctl_solaris.c \ GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB quaggaconfdir = $(sysconfdir) examplesdir = $(exampledir) dist_examples_DATA = zebra.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../common.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu zebra/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu zebra/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(srcdir)/../common.am $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list testzebra$(EXEEXT): $(testzebra_OBJECTS) $(testzebra_DEPENDENCIES) $(EXTRA_testzebra_DEPENDENCIES) @rm -f testzebra$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testzebra_OBJECTS) $(testzebra_LDADD) $(LIBS) zebra$(EXEEXT): $(zebra_OBJECTS) $(zebra_DEPENDENCIES) $(EXTRA_zebra_DEPENDENCIES) @rm -f zebra$(EXEEXT) $(AM_V_CCLD)$(LINK) $(zebra_OBJECTS) $(zebra_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) 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_null.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)/kernel_null.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc_null.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redistribute.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redistribute_null.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/router-id.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtadv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_fpm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_fpm_dt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_fpm_netlink.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_fpm_protobuf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_rib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_rnh.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_rnh_null.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_routemap.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@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$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: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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-libtool clean-noinstPROGRAMS \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Rules @HAVE_PROTOBUF_TRUE@%.pb.h: %.proto @HAVE_PROTOBUF_TRUE@ $(Q_PROTOC) $(PROTOBUF_INCLUDES) --cpp_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ @HAVE_PROTOBUF_TRUE@%.pb-c.c %.pb-c.h: %.proto @HAVE_PROTOBUF_TRUE@ $(Q_PROTOC_C) $(PROTOBUF_INCLUDES) --c_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ client : client_main.o ../lib/libzebra.la $(CC) -g -o client client_main.o ../liblzebra.la $(LIBS) $(LIB_IPV6) # 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: quagga-1.2.4/zebra/connected.c000066400000000000000000000306671325323223500162100ustar00rootroot00000000000000/* * 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 "memory.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/interface.h" #include "zebra/connected.h" extern struct zebra_t zebrad; /* communicate the withdrawal of a connected address */ static void connected_withdraw (struct connected *ifc) { if (! ifc) return; /* Update interface address information to protocol daemon. */ if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) { zebra_interface_address_delete_update (ifc->ifp, ifc); if (ifc->address->family == AF_INET) if_subnet_delete (ifc->ifp, ifc); if (ifc->address->family == AF_INET) connected_down_ipv4 (ifc->ifp, ifc); #ifdef HAVE_IPV6 else connected_down_ipv6 (ifc->ifp, ifc); #endif UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); } /* The address is not in the kernel anymore, so clear the flag */ UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) { listnode_delete (ifc->ifp->connected, ifc); connected_free (ifc); } } static void connected_announce (struct interface *ifp, struct connected *ifc) { if (!ifc) return; if (!if_is_loopback(ifp) && ifc->address->family == AF_INET) { if (ifc->address->prefixlen == 32) SET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED); else UNSET_FLAG (ifc->flags, ZEBRA_IFA_UNNUMBERED); } listnode_add (ifp->connected, ifc); /* Update interface address information to protocol daemon. */ if (ifc->address->family == AF_INET) if_subnet_add (ifp, ifc); zebra_interface_address_add_update (ifp, ifc); if (if_is_operative(ifp)) { if (ifc->address->family == AF_INET) connected_up_ipv4 (ifp, ifc); #ifdef HAVE_IPV6 else connected_up_ipv6 (ifp, ifc); #endif } } /* If same interface address is already exist... */ struct connected * connected_check (struct interface *ifp, struct prefix *p) { struct connected *ifc; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) if (prefix_same (ifc->address, p)) return ifc; return NULL; } /* Check if two ifc's describe the same address in the same state */ static int connected_same (struct connected *ifc1, struct connected *ifc2) { if (ifc1->ifp != ifc2->ifp) return 0; if (ifc1->destination) if (!ifc2->destination) return 0; if (ifc2->destination) if (!ifc1->destination) return 0; if (ifc1->destination && ifc2->destination) if (!prefix_same (ifc1->destination, ifc2->destination)) return 0; if (ifc1->flags != ifc2->flags) return 0; if (ifc1->conf != ifc2->conf) return 0; return 1; } /* Handle changes to addresses and send the neccesary announcements * to clients. */ static void connected_update(struct interface *ifp, struct connected *ifc) { struct connected *current; /* Check same connected route. */ if ((current = connected_check (ifp, (struct prefix *) ifc->address))) { if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED)) SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); /* Avoid spurious withdraws, this might be just the kernel 'reflecting' * back an address we have already added. */ if (connected_same (current, ifc)) { /* nothing to do */ connected_free (ifc); return; } /* Clear the configured flag on the old ifc, so it will be freed by * connected withdraw. */ UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED); connected_withdraw (current); /* implicit withdraw - freebsd does this */ } /* If the connected is new or has changed, announce it, if it is usable */ if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) connected_announce(ifp, ifc); } /* Called from if_up(). */ void connected_up_ipv4 (struct interface *ifp, struct connected *ifc) { struct prefix_ipv4 p; if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) return; PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); /* 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, NULL, ifp->ifindex, ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST); rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_MULTICAST); rib_update (ifp->vrf_id); } /* Add connected IPv4 route to the interface. */ void connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, struct in_addr *broad, const char *label) { struct prefix_ipv4 *p; struct connected *ifc; /* Make connected structure. */ ifc = connected_new (); ifc->ifp = ifp; ifc->flags = flags; /* If we get a notification from the kernel, * we can safely assume the address is known to the kernel */ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* 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 peer address. */ if (broad) { p = prefix_ipv4_new (); p->family = AF_INET; p->prefix = *broad; p->prefixlen = prefixlen; ifc->destination = (struct prefix *) p; /* validate the destination address */ if (CONNECTED_PEER(ifc)) { if (IPV4_ADDR_SAME(addr,broad)) zlog_warn("warning: interface %s has same local and peer " "address %s, routing protocols may malfunction", ifp->name,inet_ntoa(*addr)); } else { if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen)) { char buf[2][INET_ADDRSTRLEN]; struct in_addr bcalc; bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen); zlog_warn("warning: interface %s broadcast addr %s/%d != " "calculated %s, routing protocols may malfunction", ifp->name, inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])), prefixlen, inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1]))); } } } else { if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { zlog_warn("warning: %s called for interface %s " "with peer flag set, but no peer address supplied", __func__, ifp->name); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } /* no broadcast or destination address was supplied */ if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp)) zlog_warn("warning: PtP interface %s with addr %s/%d needs a " "peer address",ifp->name,inet_ntoa(*addr),prefixlen); } /* Label of this address. */ if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); /* For all that I know an IPv4 address is always ready when we receive * the notification. So it should be safe to set the REAL flag here. */ SET_FLAG(ifc->conf, ZEBRA_IFC_REAL); connected_update(ifp, ifc); } void connected_down_ipv4 (struct interface *ifp, struct connected *ifc) { struct prefix_ipv4 p; if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) return; PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); /* 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; /* Same logic as for connected_up_ipv4(): push the changes into the head. */ rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, SAFI_UNICAST); rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, SAFI_MULTICAST); rib_update (ifp->vrf_id); } /* Delete connected IPv4 route to the interface. */ void connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, struct in_addr *broad) { 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 (ifp, (struct prefix *) &p); if (! ifc) return; connected_withdraw (ifc); rib_update (ifp->vrf_id); } #ifdef HAVE_IPV6 void connected_up_ipv6 (struct interface *ifp, struct connected *ifc) { struct prefix_ipv6 p; if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) return; PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); /* Apply mask to the network. */ apply_mask_ipv6 (&p); #ifndef LINUX /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */ if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) return; #endif rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST); rib_update (ifp->vrf_id); } /* Add connected IPv6 route to the interface. */ void connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr, u_char prefixlen, struct in6_addr *broad, const char *label) { struct prefix_ipv6 *p; struct connected *ifc; /* Make connected structure. */ ifc = connected_new (); ifc->ifp = ifp; ifc->flags = flags; /* If we get a notification from the kernel, * we can safely assume the address is known to the kernel */ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* 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 peer address. */ if (broad) { if (IN6_IS_ADDR_UNSPECIFIED(broad)) zlog_warn("warning: %s called for interface %s with unspecified " "destination address; ignoring!", __func__, ifp->name); else { p = prefix_ipv6_new (); p->family = AF_INET6; IPV6_ADDR_COPY (&p->prefix, broad); p->prefixlen = prefixlen; ifc->destination = (struct prefix *) p; } } if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination) { zlog_warn("warning: %s called for interface %s " "with peer flag set, but no peer address supplied", __func__, ifp->name); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } /* Label of this address. */ if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); /* On Linux, we only get here when DAD is complete, therefore we can set * ZEBRA_IFC_REAL. * * On BSD, there currently doesn't seem to be a way to check for completion of * DAD, so we replicate the old behaviour and set ZEBRA_IFC_REAL, although DAD * might still be running. */ SET_FLAG(ifc->conf, ZEBRA_IFC_REAL); connected_update(ifp, ifc); } void connected_down_ipv6 (struct interface *ifp, struct connected *ifc) { struct prefix_ipv6 p; if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) return; PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv6 (&p); if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) return; rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id, SAFI_UNICAST); rib_update (ifp->vrf_id); } void connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, u_char 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 (ifp, (struct prefix *) &p); if (! ifc) return; connected_withdraw (ifc); rib_update (ifp->vrf_id); } #endif /* HAVE_IPV6 */ quagga-1.2.4/zebra/connected.h000066400000000000000000000036501325323223500162050ustar00rootroot00000000000000/* * 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 extern struct connected * connected_check (struct interface *ifp, struct prefix *p); extern void connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, struct in_addr *broad, const char *label); extern void connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, struct in_addr *broad); extern void connected_up_ipv4 (struct interface *, struct connected *); extern void connected_down_ipv4 (struct interface *, struct connected *); #ifdef HAVE_IPV6 extern void connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *address, u_char prefixlen, struct in6_addr *broad, const char *label); extern void connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, u_char prefixlen, struct in6_addr *broad); extern void connected_up_ipv6 (struct interface *, struct connected *); extern void connected_down_ipv6 (struct interface *ifp, struct connected *); #endif /* HAVE_IPV6 */ #endif /*_ZEBRA_CONNECTED_H */ quagga-1.2.4/zebra/debug.c000066400000000000000000000264411325323223500153270ustar00rootroot00000000000000/* * 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; unsigned long zebra_debug_rib; unsigned long zebra_debug_fpm; unsigned long zebra_debug_nht; DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, "show debugging zebra", SHOW_STR "Debugging information\n" "Zebra configuration\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); if (IS_ZEBRA_DEBUG_RIB) vty_out (vty, " Zebra RIB debugging is on%s", VTY_NEWLINE); if (IS_ZEBRA_DEBUG_RIB_Q) vty_out (vty, " Zebra RIB queue debugging is on%s", VTY_NEWLINE); if (IS_ZEBRA_DEBUG_FPM) vty_out (vty, " Zebra FPM debugging is on%s", VTY_NEWLINE); if (IS_ZEBRA_DEBUG_NHT) vty_out (vty, " Zebra next-hop tracking 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_nht, debug_zebra_nht_cmd, "debug zebra nht", DEBUG_STR "Zebra configuration\n" "Debug option set for zebra next hop tracking\n") { zebra_debug_nht = ZEBRA_DEBUG_NHT; 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; SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_SEND); SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_RECV); return CMD_SUCCESS; } DEFUN (debug_zebra_packet_direct, debug_zebra_packet_direct_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") { zebra_debug_packet = ZEBRA_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_SEND); if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_RECV); if (strncmp ("detail", argv[0], strlen (argv[0])) == 0) SET_FLAG(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 detailed information\n") { zebra_debug_packet = ZEBRA_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_SEND); if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) SET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_RECV); SET_FLAG(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 (debug_zebra_rib, debug_zebra_rib_cmd, "debug zebra rib", DEBUG_STR "Zebra configuration\n" "Debug RIB events\n") { SET_FLAG (zebra_debug_rib, ZEBRA_DEBUG_RIB); return CMD_SUCCESS; } DEFUN (debug_zebra_rib_q, debug_zebra_rib_q_cmd, "debug zebra rib queue", DEBUG_STR "Zebra configuration\n" "Debug RIB events\n" "Debug RIB queueing\n") { SET_FLAG (zebra_debug_rib, ZEBRA_DEBUG_RIB_Q); return CMD_SUCCESS; } DEFUN (debug_zebra_fpm, debug_zebra_fpm_cmd, "debug zebra fpm", DEBUG_STR "Zebra configuration\n" "Debug zebra FPM events\n") { SET_FLAG (zebra_debug_fpm, ZEBRA_DEBUG_FPM); 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_nht, no_debug_zebra_nht_cmd, "no debug zebra nht", NO_STR DEBUG_STR "Zebra configuration\n" "Debug option set for zebra next hop tracking\n") { zebra_debug_nht = 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) UNSET_FLAG(zebra_debug_packet, ZEBRA_DEBUG_SEND); if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) UNSET_FLAG(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; } DEFUN (no_debug_zebra_rib, no_debug_zebra_rib_cmd, "no debug zebra rib", NO_STR DEBUG_STR "Zebra configuration\n" "Debug zebra RIB\n") { zebra_debug_rib = 0; return CMD_SUCCESS; } DEFUN (no_debug_zebra_rib_q, no_debug_zebra_rib_q_cmd, "no debug zebra rib queue", NO_STR DEBUG_STR "Zebra configuration\n" "Debug zebra RIB\n" "Debug RIB queueing\n") { UNSET_FLAG (zebra_debug_rib, ZEBRA_DEBUG_RIB_Q); return CMD_SUCCESS; } DEFUN (no_debug_zebra_fpm, no_debug_zebra_fpm_cmd, "no debug zebra fpm", NO_STR DEBUG_STR "Zebra configuration\n" "Debug zebra FPM events\n") { zebra_debug_fpm = 0; return CMD_SUCCESS; } /* Debug node. */ struct cmd_node debug_node = { DEBUG_NODE, "", /* Debug node has no interface. */ 1 }; static 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++; } if (IS_ZEBRA_DEBUG_RIB) { vty_out (vty, "debug zebra rib%s", VTY_NEWLINE); write++; } if (IS_ZEBRA_DEBUG_RIB_Q) { vty_out (vty, "debug zebra rib queue%s", VTY_NEWLINE); write++; } if (IS_ZEBRA_DEBUG_FPM) { vty_out (vty, "debug zebra fpm%s", VTY_NEWLINE); write++; } return write; } void zebra_debug_init (void) { zebra_debug_event = 0; zebra_debug_packet = 0; zebra_debug_kernel = 0; zebra_debug_rib = 0; zebra_debug_fpm = 0; install_node (&debug_node, config_write_debug); install_element (VIEW_NODE, &show_debugging_zebra_cmd); install_element (ENABLE_NODE, &debug_zebra_events_cmd); install_element (ENABLE_NODE, &debug_zebra_nht_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, &debug_zebra_rib_cmd); install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd); install_element (ENABLE_NODE, &debug_zebra_fpm_cmd); install_element (ENABLE_NODE, &no_debug_zebra_events_cmd); install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd); install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd); install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd); install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd); install_element (ENABLE_NODE, &no_debug_zebra_rib_q_cmd); install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd); install_element (CONFIG_NODE, &debug_zebra_events_cmd); install_element (CONFIG_NODE, &debug_zebra_nht_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, &debug_zebra_rib_cmd); install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd); install_element (CONFIG_NODE, &debug_zebra_fpm_cmd); install_element (CONFIG_NODE, &no_debug_zebra_events_cmd); install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd); install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd); install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd); install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd); install_element (CONFIG_NODE, &no_debug_zebra_rib_q_cmd); install_element (CONFIG_NODE, &no_debug_zebra_fpm_cmd); } quagga-1.2.4/zebra/debug.h000066400000000000000000000043261325323223500153320ustar00rootroot00000000000000/* * 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 #define ZEBRA_DEBUG_RIB 0x01 #define ZEBRA_DEBUG_RIB_Q 0x02 #define ZEBRA_DEBUG_FPM 0x01 #define ZEBRA_DEBUG_NHT 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) #define IS_ZEBRA_DEBUG_RIB (zebra_debug_rib & ZEBRA_DEBUG_RIB) #define IS_ZEBRA_DEBUG_RIB_Q (zebra_debug_rib & ZEBRA_DEBUG_RIB_Q) #define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM) #define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT) extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; extern unsigned long zebra_debug_kernel; extern unsigned long zebra_debug_rib; extern unsigned long zebra_debug_fpm; extern unsigned long zebra_debug_nht; extern void zebra_debug_init (void); #endif /* _ZEBRA_DEBUG_H */ quagga-1.2.4/zebra/if_ioctl.c000066400000000000000000000271011325323223500160230ustar00rootroot00000000000000/* * 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 "vrf.h" #include "vty.h" #include "zebra/interface.h" #include "zebra/rib.h" /* Interface looking up using infamous SIOCGIFCONF. */ static int interface_list_ioctl (void) { 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", safe_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", safe_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_len(ifreq->ifr_name, strnlen(ifreq->ifr_name, sizeof(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_len(ifreq->ifr_name, strnlen(ifreq->ifr_name, sizeof(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. */ static int if_get_index (struct interface *ifp) { #if defined(HAVE_IF_NAMETOINDEX) /* Modern systems should have if_nametoindex(3). */ ifp->ifindex = if_nametoindex(ifp->name); #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES) /* Fall-back for older linuxes. */ int ret; struct ifreq ifreq; static int if_fake_index; 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 #else /* Linux 2.2.X does not provide individual interface index for aliases and we know it. For others issue a warning. */ #if !defined(HAVE_BROKEN_ALIASES) #warning "Using if_fake_index. You may want to add appropriate" #warning "mapping from ifname to ifindex for your system..." #endif /* This branch probably won't provide usable results, but anyway... */ static int if_fake_index = 1; ifp->ifindex = if_fake_index++; #endif return ifp->ifindex; } #ifdef SIOCGIFHWADDR static 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 static int if_getaddrs (void) { int ret; struct ifaddrs *ifap; struct ifaddrs *ifapfree; struct interface *ifp; int prefixlen; ret = getifaddrs (&ifap); if (ret != 0) { zlog_err ("getifaddrs(): %s", safe_strerror (errno)); return -1; } for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) { if (ifap->ifa_addr == NULL) { zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s", __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)")); continue; } 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; int flags = 0; 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_dstaddr && !IPV4_ADDR_SAME(&addr->sin_addr, &((struct sockaddr_in *) ifap->ifa_dstaddr)->sin_addr)) { dest = (struct sockaddr_in *) ifap->ifa_dstaddr; dest_pnt = &dest->sin_addr; flags = ZEBRA_IFA_PEER; } else if (ifap->ifa_broadaddr && !IPV4_ADDR_SAME(&addr->sin_addr, &((struct sockaddr_in *) ifap->ifa_broadaddr)->sin_addr)) { dest = (struct sockaddr_in *) ifap->ifa_broadaddr; dest_pnt = &dest->sin_addr; } connected_add_ipv4 (ifp, flags, &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; int flags = 0; 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_dstaddr && !IPV6_ADDR_SAME(&addr->sin6_addr, &((struct sockaddr_in6 *) ifap->ifa_dstaddr)->sin6_addr)) { dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; dest_pnt = &dest->sin6_addr; flags = ZEBRA_IFA_PEER; } else if (ifap->ifa_broadaddr && !IPV6_ADDR_SAME(&addr->sin6_addr, &((struct sockaddr_in6 *) ifap->ifa_broadaddr)->sin6_addr)) { dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; dest_pnt = &dest->sin6_addr; } #if defined(KAME) if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { addr->sin6_scope_id = ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]); addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0; } #endif connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen, dest_pnt, NULL); } #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; int flags = 0; /* 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", safe_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", safe_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; ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno)); } else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr)) { memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in)); dest_pnt = &dest.sin_addr; flags = ZEBRA_IFA_PEER; } if (!dest_pnt) { ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno)); } else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr)) { memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = &dest.sin_addr; } } /* Set address to the interface. */ connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL); return 0; } #endif /* HAVE_GETIFADDRS */ /* Fetch interface information via ioctl(). */ static void interface_info_ioctl () { struct listnode *node, *nnode; struct interface *ifp; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { 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 (struct zebra_vrf *zvrf) { if (zvrf->vrf_id != VRF_DEFAULT) { zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id); return; } /* 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 */ } quagga-1.2.4/zebra/if_ioctl_solaris.c000066400000000000000000000243671325323223500175720ustar00rootroot00000000000000/* * Interface looking up by ioctl () on Solaris. * 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 "privs.h" #include "vrf.h" #include "vty.h" #include "zebra/interface.h" #include "zebra/ioctl_solaris.h" #include "zebra/rib.h" static int if_get_addr (struct interface *, struct sockaddr *, const char *); static void interface_info_ioctl (struct interface *); extern struct zebra_privs_t zserv_privs; static int interface_list_ioctl (int af) { int ret; int sock; #define IFNUM_BASE 32 struct lifnum lifn; int ifnum; struct lifreq *lifreq; struct lifconf lifconf; struct interface *ifp; int n; int save_errno; size_t needed, lastneeded = 0; char *buf = NULL; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (af, SOCK_DGRAM, 0); if (sock < 0) { zlog_warn ("Can't make %s socket stream: %s", (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno)); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return -1; } calculate_lifc_len: /* must hold privileges to enter here */ lifn.lifn_family = af; lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */ ret = ioctl (sock, SIOCGLIFNUM, &lifn); save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); if (ret < 0) { zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s", safe_strerror (save_errno)); close (sock); return -1; } ifnum = lifn.lifn_count; /* * When calculating the buffer size needed, add a small number * of interfaces to those we counted. We do this to capture * the interface status of potential interfaces which may have * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. */ needed = (ifnum + 4) * sizeof (struct lifreq); if (needed > lastneeded || needed < lastneeded / 2) { if (buf != NULL) XFREE (MTYPE_TMP, buf); if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL) { zlog_warn ("interface_list_ioctl: malloc failed"); close (sock); return -1; } } lastneeded = needed; lifconf.lifc_family = af; lifconf.lifc_flags = LIFC_NOXMIT; lifconf.lifc_len = needed; lifconf.lifc_buf = buf; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); ret = ioctl (sock, SIOCGLIFCONF, &lifconf); if (ret < 0) { if (errno == EINVAL) goto calculate_lifc_len; /* deliberately hold privileges */ zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno)); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); goto end; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); /* Allocate interface. */ lifreq = lifconf.lifc_req; for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq)) { /* we treat Solaris logical interfaces as addresses, because that is * how PF_ROUTE on Solaris treats them. Hence we can not directly use * the lifreq_name to get the ifp. We need to normalise the name * before attempting get. * * Solaris logical interface names are in the form of: * : */ unsigned int normallen = 0; uint64_t lifflags; /* We should exclude ~IFF_UP interfaces, as we'll find out about them * coming up later through RTM_NEWADDR message on the route socket. */ if (if_get_flags_direct (lifreq->lifr_name, &lifflags, lifreq->lifr_addr.ss_family) || !CHECK_FLAG (lifflags, IFF_UP)) { lifreq++; continue; } /* Find the normalised name */ while ( (normallen < sizeof(lifreq->lifr_name)) && ( *(lifreq->lifr_name + normallen) != '\0') && ( *(lifreq->lifr_name + normallen) != ':') ) normallen++; ifp = if_get_by_name_len(lifreq->lifr_name, normallen); if (lifreq->lifr_addr.ss_family == AF_INET) ifp->flags |= IFF_IPV4; if (lifreq->lifr_addr.ss_family == AF_INET6) { #ifdef HAVE_IPV6 ifp->flags |= IFF_IPV6; #else lifreq++; continue; #endif /* HAVE_IPV6 */ } if_add_update (ifp); interface_info_ioctl (ifp); /* If a logical interface pass the full name so it can be * as a label on the address */ if ( *(lifreq->lifr_name + normallen) != '\0') if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, lifreq->lifr_name); else if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL); /* Poke the interface flags. Lets IFF_UP mangling kick in */ if_flags_update (ifp, ifp->flags); lifreq++; } end: close (sock); XFREE (MTYPE_TMP, lifconf.lifc_buf); return ret; } /* Get interface's index by ioctl. */ static int if_get_index (struct interface *ifp) { int ret; struct lifreq lifreq; lifreq_set_name (&lifreq, ifp->name); if (ifp->flags & IFF_IPV4) ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq); else if (ifp->flags & IFF_IPV6) ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq); else ret = -1; if (ret < 0) { zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name); return ret; } /* OK we got interface index. */ #ifdef ifr_ifindex ifp->ifindex = lifreq.lifr_ifindex; #else ifp->ifindex = lifreq.lifr_index; #endif return ifp->ifindex; } /* Interface address lookup by ioctl. This function only looks up IPv4 address. */ #define ADDRLEN(sa) (((sa)->sa_family == AF_INET ? \ sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6))) #define SIN(s) ((struct sockaddr_in *)(s)) #define SIN6(s) ((struct sockaddr_in6 *)(s)) /* Retrieve address information for the given ifp */ static int if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label) { int ret; struct lifreq lifreq; struct sockaddr_storage mask, dest; char *dest_pnt = NULL; u_char prefixlen = 0; afi_t af; int flags = 0; /* Interface's name and address family. * We need to use the logical interface name / label, if we've been * given one, in order to get the right address */ strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ); /* Interface's address. */ memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr)); af = addr->sa_family; /* Point to point or broad cast address pointer init. */ dest_pnt = NULL; if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0) { memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr)); if (af == AF_INET) dest_pnt = (char *) &(SIN (&dest)->sin_addr); else dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr); flags = ZEBRA_IFA_PEER; } if (af == AF_INET) { ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name, safe_strerror (errno)); return ret; } return 0; } memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr)); prefixlen = ip_masklen (SIN (&mask)->sin_addr); if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0)) { memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = (char *) &SIN (&dest)->sin_addr; } } #ifdef HAVE_IPV6 else if (af == AF_INET6) { if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0) { if (ifp->flags & IFF_POINTOPOINT) prefixlen = IPV6_MAX_BITLEN; else zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s", ifp->name, safe_strerror (errno)); } else { prefixlen = lifreq.lifr_addrlen; } } #endif /* HAVE_IPV6 */ /* Set address to the interface. */ if (af == AF_INET) connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen, (struct in_addr *) dest_pnt, label); #ifdef HAVE_IPV6 else if (af == AF_INET6) connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen, (struct in6_addr *) dest_pnt, label); #endif /* HAVE_IPV6 */ return 0; } /* Fetch interface information via ioctl(). */ static void interface_info_ioctl (struct interface *ifp) { if_get_index (ifp); if_get_flags (ifp); if_get_mtu (ifp); if_get_metric (ifp); } /* Lookup all interface information. */ void interface_list (struct zebra_vrf *zvrf) { if (zvrf->vrf_id != VRF_DEFAULT) { zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id); return; } interface_list_ioctl (AF_INET); interface_list_ioctl (AF_INET6); interface_list_ioctl (AF_UNSPEC); } struct connected * if_lookup_linklocal (struct interface *ifp) { #ifdef HAVE_IPV6 struct listnode *node; struct connected *ifc; if (ifp == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { if ((ifc->address->family == AF_INET6) && (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6))) return ifc; } #endif /* HAVE_IPV6 */ return NULL; } quagga-1.2.4/zebra/if_netlink.c000066400000000000000000000020221325323223500163500ustar00rootroot00000000000000/* * 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 #include "zebra/zserv.h" #include "rt_netlink.h" /* Interface information read by netlink. */ void interface_list (struct zebra_vrf *zvrf) { interface_lookup_netlink (zvrf); } quagga-1.2.4/zebra/if_sysctl.c000066400000000000000000000072131325323223500162340ustar00rootroot00000000000000/* * 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" #include "interface.h" #include "vrf.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" #include "zebra/rib.h" void ifstat_update_sysctl (void) { 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", safe_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", safe_strerror (errno)); return; } /* 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; } /* Interface listing up function using sysctl(). */ void interface_list (struct zebra_vrf *zvrf) { caddr_t ref, buf, end; size_t bufsiz; struct if_msghdr *ifm; #define MIBSIZ 6 int mib[MIBSIZ] = { CTL_NET, PF_ROUTE, 0, 0, /* AF_INET & AF_INET6 */ NET_RT_IFLIST, 0 }; if (zvrf->vrf_id != VRF_DEFAULT) { zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id); return; } /* Query buffer size. */ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { zlog (NULL, LOG_WARNING, "sysctl() error by %s", safe_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", safe_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); } quagga-1.2.4/zebra/interface.c000066400000000000000000002343361325323223500162050ustar00rootroot00000000000000/* * 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 "vrf.h" #include "command.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" #include "zebra/irdp.h" #if defined (HAVE_RTADV) /* Order is intentional. Matches RFC4191. This array is also used for command matching, so only modify with care. */ const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 }; #endif /* HAVE_RTADV */ /* We don't have a tidy top-level instance object for zebra, or interfaces */ static struct zebra_if_defaults zif_defaults = { .linkdetect = IF_LINKDETECT_UNSPEC, }; /* helper only for if_zebra_linkdetect */ static void if_zebra_linkdetect_set_val (struct interface *ifp, zebra_if_linkdetect val) { switch (val) { case IF_LINKDETECT_ON: SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); break; case IF_LINKDETECT_OFF: UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); break; default: break; } } static void if_zebra_linkdetect_set (struct interface *ifp) { struct zebra_if *zif = ifp->info; assert (zif != NULL); int if_was_operative = if_is_operative(ifp); /* If user has explicitly configured for the interface, let that set */ if (zif->linkdetect != IF_LINKDETECT_UNSPEC) if_zebra_linkdetect_set_val (ifp, zif->linkdetect); else { /* general compiled in default is to set */ SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); /* but user can specify a default too */ if_zebra_linkdetect_set_val (ifp, zif_defaults.linkdetect); } /* When linkdetection is enabled, interface might come down */ if (!if_is_operative(ifp) && if_was_operative) if_down(ifp); /* Alternatively, it may come up after disabling link detection */ if (if_is_operative(ifp) && !if_was_operative) if_up(ifp); } /* Called when new interface is added. */ static int if_zebra_new_hook (struct interface *ifp) { struct zebra_if *zebra_if; zebra_if = XCALLOC (MTYPE_TMP, sizeof (struct zebra_if)); zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC; zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF; switch (zif_defaults.linkdetect) { case IF_LINKDETECT_OFF: UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); break; case IF_LINKDETECT_UNSPEC: case IF_LINKDETECT_ON: default: SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); break; } #if defined (HAVE_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->AdvHomeAgentFlag = 0; rtadv->AdvLinkMTU = 0; rtadv->AdvReachableTime = 0; rtadv->AdvRetransTimer = 0; rtadv->AdvCurHopLimit = 0; rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */ rtadv->HomeAgentPreference = 0; rtadv->HomeAgentLifetime = -1; /* derive from AdvDefaultLifetime */ rtadv->AdvIntervalOption = 0; rtadv->DefaultPreference = RTADV_PREF_MEDIUM; rtadv->AdvPrefixList = list_new (); } #endif /* HAVE_RTADV */ /* Initialize installed address chains tree. */ zebra_if->ipv4_subnets = route_table_init (); ifp->info = zebra_if; return 0; } /* Called when interface is deleted. */ static int if_zebra_delete_hook (struct interface *ifp) { struct zebra_if *zebra_if; if (ifp->info) { zebra_if = ifp->info; /* Free installed address chains tree. */ if (zebra_if->ipv4_subnets) route_table_finish (zebra_if->ipv4_subnets); XFREE (MTYPE_TMP, zebra_if); } return 0; } /* Tie an interface address to its derived subnet list of addresses. */ int if_subnet_add (struct interface *ifp, struct connected *ifc) { struct route_node *rn; struct zebra_if *zebra_if; struct prefix cp; struct list *addr_list; assert (ifp && ifp->info && ifc); zebra_if = ifp->info; /* Get address derived subnet node and associated address list, while marking address secondary attribute appropriately. */ cp = *ifc->address; apply_mask (&cp); rn = route_node_get (zebra_if->ipv4_subnets, &cp); if ((addr_list = rn->info)) SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); else { UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); rn->info = addr_list = list_new (); route_lock_node (rn); } /* Tie address at the tail of address list. */ listnode_add (addr_list, ifc); /* Return list element count. */ return (addr_list->count); } /* Untie an interface address from its derived subnet list of addresses. */ int if_subnet_delete (struct interface *ifp, struct connected *ifc) { struct route_node *rn; struct zebra_if *zebra_if; struct list *addr_list; assert (ifp && ifp->info && ifc); zebra_if = ifp->info; /* Get address derived subnet node. */ rn = route_node_lookup (zebra_if->ipv4_subnets, ifc->address); if (! (rn && rn->info)) { zlog_warn("Trying to remove an address from an unknown subnet." " (please report this bug)"); return -1; } route_unlock_node (rn); /* Untie address from subnet's address list. */ addr_list = rn->info; /* Deleting an address that is not registered is a bug. * In any case, we shouldn't decrement the lock counter if the address * is unknown. */ if (!listnode_lookup(addr_list, ifc)) { zlog_warn("Trying to remove an address from a subnet where it is not" " currently registered. (please report this bug)"); return -1; } listnode_delete (addr_list, ifc); route_unlock_node (rn); /* Return list element count, if not empty. */ if (addr_list->count) { /* If deleted address is primary, mark subsequent one as such and distribute. */ if (! CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) { ifc = listgetdata ((struct listnode *)listhead (addr_list)); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); /* XXX: Linux kernel removes all the secondary addresses when the primary * address is removed. We could try to work around that, though this is * non-trivial. */ zebra_interface_address_add_update (ifp, ifc); } return addr_list->count; } /* Otherwise, free list and route node. */ list_free (addr_list); rn->info = NULL; route_unlock_node (rn); return 0; } /* if_flags_mangle: A place for hacks that require mangling * or tweaking the interface flags. * * ******************** Solaris flags hacks ************************** * * Solaris IFF_UP flag reflects only the primary interface as the * routing socket only sends IFINFO for the primary interface. Hence * ~IFF_UP does not per se imply all the logical interfaces are also * down - which we only know of as addresses. Instead we must determine * whether the interface really is up or not according to how many * addresses are still attached. (Solaris always sends RTM_DELADDR if * an interface, logical or not, goes ~IFF_UP). * * Ie, we mangle IFF_UP to *additionally* reflect whether or not there * are addresses left in struct connected, not just the actual underlying * IFF_UP flag. * * We must hence remember the real state of IFF_UP, which we do in * struct zebra_if.primary_state. * * Setting IFF_UP within zebra to administratively shutdown the * interface will affect only the primary interface/address on Solaris. ************************End Solaris flags hacks *********************** */ static void if_flags_mangle (struct interface *ifp, uint64_t *newflags) { #ifdef SUNOS_5 struct zebra_if *zif = ifp->info; zif->primary_state = *newflags & (IFF_UP & 0xff); if (CHECK_FLAG (zif->primary_state, IFF_UP) || listcount(ifp->connected) > 0) SET_FLAG (*newflags, IFF_UP); else UNSET_FLAG (*newflags, IFF_UP); #endif /* SUNOS_5 */ } /* Update the flags field of the ifp with the new flag set provided. * Take whatever actions are required for any changes in flags we care * about. * * newflags should be the raw value, as obtained from the OS. */ void if_flags_update (struct interface *ifp, uint64_t newflags) { if_flags_mangle (ifp, &newflags); if (if_is_operative (ifp)) { /* operative -> inoperative? */ ifp->flags = newflags; if (!if_is_operative (ifp)) if_down (ifp); } else { /* inoperative -> operative? */ ifp->flags = newflags; if (if_is_operative (ifp)) if_up (ifp); } } /* Wake up configured address if it is not in current kernel address. */ static void if_addr_wakeup (struct interface *ifp) { struct listnode *node, *nnode; struct connected *ifc; struct prefix *p; int ret; for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc)) { p = ifc->address; if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED) && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)) { /* Address check. */ if (p->family == AF_INET) { if (! if_is_up (ifp)) { /* Assume zebra is configured like following: * * interface gre0 * ip addr 192.0.2.1/24 * ! * * As soon as zebra becomes first aware that gre0 exists in the * kernel, it will set gre0 up and configure its addresses. * * (This may happen at startup when the interface already exists * or during runtime when the interface is added to the kernel) * * XXX: IRDP code is calling here via if_add_update - this seems * somewhat weird. * XXX: RUNNING is not a settable flag on any system * I (paulj) am aware of. */ 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", safe_strerror(errno)); continue; } SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* The address will be advertised to zebra clients when the notification * from the kernel has been received. * It will also be added to the interface's subnet list then. */ } #ifdef HAVE_IPV6 if (p->family == AF_INET6) { if (! if_is_up (ifp)) { /* See long comment above */ 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", safe_strerror(errno)); continue; } SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* The address will be advertised to zebra clients when the notification * from the kernel has been received. */ } #endif /* HAVE_IPV6 */ } } } static void if_count_up(struct zebra_if *zif) { event_counter_inc(&zif->up_events); } static void if_count_down(struct zebra_if *zif) { event_counter_inc(&zif->down_events); } void if_startup_count_up (void) { vrf_iter_t iter; struct interface *ifp; struct zebra_if *zif; struct listnode *node; for (iter = vrf_first(); iter != VRF_ITER_INVALID; iter = vrf_next(iter)) { for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist(iter), node, ifp)) { zif = ifp->info; if (!zif->up_events.count && if_is_operative(ifp)) if_count_up(zif); } } } /* Handle interface addition */ void if_add_update (struct interface *ifp) { struct zebra_if *if_data; if_data = ifp->info; assert(if_data); if (if_data->multicast == IF_ZEBRA_MULTICAST_ON) if_set_flags (ifp, IFF_MULTICAST); else if (if_data->multicast == IF_ZEBRA_MULTICAST_OFF) if_unset_flags (ifp, IFF_MULTICAST); zebra_interface_add_update (ifp); if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); if (if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("interface %s vrf %u index %d is shutdown. " "Won't wake it up.", ifp->name, ifp->vrf_id, ifp->ifindex); return; } if_addr_wakeup (ifp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("interface %s vrf %u index %d becomes active.", ifp->name, ifp->vrf_id, ifp->ifindex); } else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("interface %s vrf %u index %d is added.", ifp->name, ifp->vrf_id, ifp->ifindex); } if (host_config_get()) { /* If configuration and therefore link-detect have already been * loaded, count an initial up event when new interfaces are added * in up state. * If configuration has not been loaded yet, this is handled by * if_startup_count_up which is called after reading the config. */ if (!if_data->up_events.count && if_is_operative(ifp)) if_count_up(if_data); } } /* Handle an interface delete event */ void if_delete_update (struct interface *ifp) { struct connected *ifc; struct prefix *p; struct route_node *rn; struct zebra_if *zebra_if; zebra_if = ifp->info; if (if_is_up(ifp)) { zlog_err ("interface %s vrf %u index %d is still up while being deleted.", ifp->name, ifp->vrf_id, ifp->ifindex); return; } /* Mark interface as inactive */ UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("interface %s vrf %u index %d is now inactive.", ifp->name, ifp->vrf_id, ifp->ifindex); /* Delete connected routes from the kernel. */ if (ifp->connected) { struct listnode *node; struct listnode *last = NULL; while ((node = (last ? last->next : listhead (ifp->connected)))) { ifc = listgetdata (node); p = ifc->address; if (p->family == AF_INET && (rn = route_node_lookup (zebra_if->ipv4_subnets, p))) { struct listnode *anode; struct listnode *next; struct listnode *first; struct list *addr_list; route_unlock_node (rn); addr_list = (struct list *) rn->info; /* Remove addresses, secondaries first. */ first = listhead (addr_list); for (anode = first->next; anode || first; anode = next) { if (!anode) { anode = first; first = NULL; } next = anode->next; ifc = listgetdata (anode); p = ifc->address; connected_down_ipv4 (ifp, ifc); /* XXX: We have to send notifications here explicitly, because we destroy * the ifc before receiving the notification about the address being deleted. */ zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* Remove from subnet chain. */ list_delete_node (addr_list, anode); route_unlock_node (rn); /* Remove from interface address list (unconditionally). */ if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) { listnode_delete (ifp->connected, ifc); connected_free (ifc); } else last = node; } /* Free chain list and respective route node. */ list_delete (addr_list); rn->info = NULL; route_unlock_node (rn); } #ifdef HAVE_IPV6 else if (p->family == AF_INET6) { connected_down_ipv6 (ifp, ifc); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) last = node; else { listnode_delete (ifp->connected, ifc); connected_free (ifc); } } #endif /* HAVE_IPV6 */ else { last = node; } } } zebra_interface_delete_update (ifp); /* Update ifindex after distributing the delete message. This is in case any client needs to have the old value of ifindex available while processing the deletion. Each client daemon is responsible for setting ifindex to IFINDEX_INTERNAL after processing the interface deletion message. */ ifp->ifindex = IFINDEX_INTERNAL; } /* Interface is up. */ void if_up (struct interface *ifp) { struct listnode *node; struct listnode *next; struct connected *ifc; struct prefix *p; if_count_up(ifp->info); /* Notify the protocol daemons. */ zebra_interface_up_update (ifp); /* Install connected routes to the kernel. */ if (ifp->connected) { for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc)) { 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 (ifp->vrf_id); } /* Interface goes down. We have to manage different behavior of based OS. */ void if_down (struct interface *ifp) { struct listnode *node; struct listnode *next; struct connected *ifc; struct prefix *p; struct zebra_if *zif; zif = ifp->info; if (zif->up_events.count) if_count_down(zif); /* Notify to the protocol daemons. */ zebra_interface_down_update (ifp); /* Delete connected routes from the kernel. */ if (ifp->connected) { for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc)) { 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 (ifp->vrf_id); } void if_refresh (struct interface *ifp) { if_get_flags (ifp); } /* Output prefix string to vty. */ static 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. */ static void connected_dump_vty (struct vty *vty, struct connected *connected) { struct prefix *p; /* 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. */ if (connected->destination) { vty_out (vty, (CONNECTED_PEER(connected) ? " peer " : " broadcast ")); prefix_vty_out (vty, connected->destination); } if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY)) vty_out (vty, " secondary"); if (CHECK_FLAG (connected->flags, ZEBRA_IFA_UNNUMBERED)) vty_out (vty, " unnumbered"); if (connected->label) vty_out (vty, " %s", connected->label); vty_out (vty, "%s", VTY_NEWLINE); } #if defined (HAVE_RTADV) /* Dump interface ND information to vty. */ static void nd_dump_vty (struct vty *vty, struct interface *ifp) { struct zebra_if *zif; struct rtadvconf *rtadv; int interval; 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); interval = rtadv->MaxRtrAdvInterval; if (interval % 1000) vty_out (vty, " ND router advertisements are sent every " "%d milliseconds%s", interval, VTY_NEWLINE); else vty_out (vty, " ND router advertisements are sent every " "%d seconds%s", interval / 1000, VTY_NEWLINE); if (rtadv->AdvDefaultLifetime != -1) vty_out (vty, " ND router advertisements live for %d seconds%s", rtadv->AdvDefaultLifetime, VTY_NEWLINE); else vty_out (vty, " ND router advertisements lifetime tracks ra-interval%s", VTY_NEWLINE); vty_out (vty, " ND router advertisement default router preference is " "%s%s", rtadv_pref_strs[rtadv->DefaultPreference], 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); if (rtadv->AdvHomeAgentFlag) { vty_out (vty, " ND router advertisements with " "Home Agent flag bit set.%s", VTY_NEWLINE); if (rtadv->HomeAgentLifetime != -1) vty_out (vty, " Home Agent lifetime is %u seconds%s", rtadv->HomeAgentLifetime, VTY_NEWLINE); else vty_out (vty, " Home Agent lifetime tracks ra-lifetime%s", VTY_NEWLINE); vty_out (vty, " Home Agent preference is %u%s", rtadv->HomeAgentPreference, VTY_NEWLINE); } if (rtadv->AdvIntervalOption) vty_out (vty, " ND router advertisements with Adv. Interval option.%s", VTY_NEWLINE); } } #endif /* HAVE_RTADV */ /* Interface's information print out to vty interface. */ static void if_dump_vty (struct vty *vty, struct interface *ifp) { struct connected *connected; struct listnode *node; struct route_node *rn; struct zebra_if *zebra_if; zebra_if = ifp->info; vty_out (vty, "Interface %s is ", ifp->name); if (if_is_up(ifp)) { vty_out (vty, "up, line protocol "); if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) { if (if_is_running(ifp)) vty_out (vty, "is up%s", VTY_NEWLINE); else vty_out (vty, "is down%s", VTY_NEWLINE); } else { vty_out (vty, "detection is disabled%s", VTY_NEWLINE); } } else { vty_out (vty, "down%s", VTY_NEWLINE); } vty_out (vty, " Link ups: %s%s", event_counter_format(&zebra_if->up_events), VTY_NEWLINE); vty_out (vty, " Link downs: %s%s", event_counter_format(&zebra_if->down_events), VTY_NEWLINE); vty_out (vty, " vrf: %u%s", ifp->vrf_id, VTY_NEWLINE); if (ifp->desc) vty_out (vty, " Description: %s%s", ifp->desc, VTY_NEWLINE); if (ifp->ifindex == IFINDEX_INTERNAL) { vty_out(vty, " pseudo interface%s", 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); #ifdef HAVE_IPV6 if (ifp->mtu6 != ifp->mtu) vty_out (vty, "mtu6 %d ", ifp->mtu6); #endif vty_out (vty, "%s flags: %s%s", VTY_NEWLINE, if_flag_dump (ifp->flags), VTY_NEWLINE); /* Hardware address. */ vty_out (vty, " Type: %s%s", if_link_type_str (ifp->ll_type), VTY_NEWLINE); 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); } /* Bandwidth in kbps */ if (ifp->bandwidth != 0) { vty_out(vty, " bandwidth %u kbps", ifp->bandwidth); vty_out(vty, "%s", VTY_NEWLINE); } for (rn = route_top (zebra_if->ipv4_subnets); rn; rn = route_next (rn)) { if (! rn->info) continue; for (ALL_LIST_ELEMENTS_RO ((struct list *)rn->info, node, connected)) connected_dump_vty (vty, connected); } for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL) && (connected->address->family == AF_INET6)) connected_dump_vty (vty, connected); } if (HAS_LINK_PARAMS(ifp)) { int i; struct if_link_params *iflp = ifp->link_params; vty_out(vty, " Traffic Engineering Link Parameters:%s", VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_TE)) vty_out(vty, " TE metric %u%s",iflp->te_metric, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_MAX_BW)) vty_out(vty, " Maximum Bandwidth %g (Byte/s)%s", iflp->max_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW)) vty_out(vty, " Maximum Reservable Bandwidth %g (Byte/s)%s", iflp->max_rsv_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) { vty_out(vty, " Unreserved Bandwidth per Class Type in Byte/s:%s", VTY_NEWLINE); for (i = 0; i < MAX_CLASS_TYPE; i+=2) vty_out(vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", i, iflp->unrsv_bw[i], i+1, iflp->unrsv_bw[i+1], VTY_NEWLINE); } if (IS_PARAM_SET(iflp, LP_ADM_GRP)) vty_out(vty, " Administrative Group:%u%s", iflp->admin_grp, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_DELAY)) { vty_out(vty, " Link Delay Average: %u (micro-sec.)", iflp->av_delay); if (IS_PARAM_SET(iflp, LP_MM_DELAY)) { vty_out(vty, " Min: %u (micro-sec.)", iflp->min_delay); vty_out(vty, " Max: %u (micro-sec.)", iflp->max_delay); } vty_out(vty, "%s", VTY_NEWLINE); } if (IS_PARAM_SET(iflp, LP_DELAY_VAR)) vty_out(vty, " Link Delay Variation %u (micro-sec.)%s", iflp->delay_var, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) vty_out(vty, " Link Packet Loss %g (in %%)%s", iflp->pkt_loss, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_AVA_BW)) vty_out(vty, " Available Bandwidth %g (Byte/s)%s", iflp->ava_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_RES_BW)) vty_out(vty, " Residual Bandwidth %g (Byte/s)%s", iflp->res_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_USE_BW)) vty_out(vty, " Utilized Bandwidth %g (Byte/s)%s", iflp->use_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_RMT_AS)) vty_out(vty, " Neighbor ASBR IP: %s AS: %u %s", inet_ntoa(iflp->rmt_ip), iflp->rmt_as, VTY_NEWLINE); } #ifdef RTADV nd_dump_vty (vty, ifp); #endif /* RTADV */ #if defined (HAVE_RTADV) nd_dump_vty (vty, ifp); #endif /* HAVE_RTADV */ #ifdef HAVE_PROC_NET_DEV /* Statistics print out using proc file system. */ vty_out (vty, " %lu input packets (%lu multicast), %lu bytes, " "%lu dropped%s", ifp->stats.rx_packets, ifp->stats.rx_multicast, ifp->stats.rx_bytes, ifp->stats.rx_dropped, VTY_NEWLINE); vty_out (vty, " %lu input errors, %lu length, %lu overrun," " %lu CRC, %lu frame%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, VTY_NEWLINE); vty_out (vty, " %lu fifo, %lu missed%s", ifp->stats.rx_fifo_errors, ifp->stats.rx_missed_errors, VTY_NEWLINE); vty_out (vty, " %lu output packets, %lu bytes, %lu dropped%s", ifp->stats.tx_packets, ifp->stats.tx_bytes, ifp->stats.tx_dropped, VTY_NEWLINE); vty_out (vty, " %lu output errors, %lu aborted, %lu carrier," " %lu fifo, %lu heartbeat%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, VTY_NEWLINE); vty_out (vty, " %lu window, %lu collisions%s", ifp->stats.tx_window_errors, 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 %llu, bytes %llu, dropped %llu," " multicast packets %llu%s", (unsigned long long)ifp->stats.ifi_ipackets, (unsigned long long)ifp->stats.ifi_ibytes, (unsigned long long)ifp->stats.ifi_iqdrops, (unsigned long long)ifp->stats.ifi_imcasts, VTY_NEWLINE); vty_out (vty, " input errors %llu%s", (unsigned long long)ifp->stats.ifi_ierrors, VTY_NEWLINE); vty_out (vty, " output packets %llu, bytes %llu," " multicast packets %llu%s", (unsigned long long)ifp->stats.ifi_opackets, (unsigned long long)ifp->stats.ifi_obytes, (unsigned long long)ifp->stats.ifi_omcasts, VTY_NEWLINE); vty_out (vty, " output errors %llu%s", (unsigned long long)ifp->stats.ifi_oerrors, VTY_NEWLINE); vty_out (vty, " collisions %llu%s", (unsigned long long)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 */ } /* 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() */ if ((ret = interface_cmd.func (self, vty, argc, argv)) != CMD_SUCCESS) return ret; ifp = vty->index; if (ifp->ifindex == IFINDEX_INTERNAL) /* Is this really necessary? Shouldn't status be initialized to 0 in that case? */ UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); return ret; } ALIAS (zebra_interface, zebra_interface_vrf_cmd, "interface IFNAME " VRF_CMD_STR, "Select an interface to configure\n" "Interface's name\n" VRF_CMD_HELP_STR) struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 }; /* Show all interfaces to vty. */ DEFUN (show_interface, show_interface_cmd, "show interface", SHOW_STR "Interface status and configuration\n") { struct listnode *node; struct interface *ifp; vrf_id_t vrf_id = VRF_DEFAULT; #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 */ if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); /* All interface print. */ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) if_dump_vty (vty, ifp); return CMD_SUCCESS; } ALIAS (show_interface, show_interface_vrf_cmd, "show interface " VRF_CMD_STR, SHOW_STR "Interface status and configuration\n" VRF_CMD_HELP_STR) /* Show all interfaces to vty. */ DEFUN (show_interface_vrf_all, show_interface_vrf_all_cmd, "show interface " VRF_ALL_CMD_STR, SHOW_STR "Interface status and configuration\n" VRF_ALL_CMD_HELP_STR) { struct listnode *node; struct interface *ifp; vrf_iter_t iter; #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 */ /* All interface print. */ for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp)) if_dump_vty (vty, ifp); return CMD_SUCCESS; } /* Show specified interface to vty. */ DEFUN (show_interface_name, show_interface_name_cmd, "show interface IFNAME", SHOW_STR "Interface status and configuration\n" "Interface name\n") { struct interface *ifp; vrf_id_t vrf_id = VRF_DEFAULT; #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 */ if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); /* Specified interface print. */ ifp = if_lookup_by_name_vrf (argv[0], vrf_id); 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; } ALIAS (show_interface_name, show_interface_name_vrf_cmd, "show interface IFNAME " VRF_CMD_STR, SHOW_STR "Interface status and configuration\n" "Interface name\n" VRF_CMD_HELP_STR) /* Show specified interface to vty. */ DEFUN (show_interface_name_vrf_all, show_interface_name_vrf_all_cmd, "show interface IFNAME " VRF_ALL_CMD_STR, SHOW_STR "Interface status and configuration\n" "Interface name\n" VRF_ALL_CMD_HELP_STR) { struct interface *ifp; vrf_iter_t iter; int found = 0; #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 */ /* All interface print. */ for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { /* Specified interface print. */ ifp = if_lookup_by_name_vrf (argv[0], vrf_iter2id (iter)); if (ifp) { if_dump_vty (vty, ifp); found++; } } if (!found) { vty_out (vty, "%% Can't find interface %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } static void if_show_description (struct vty *vty, vrf_id_t vrf_id) { struct listnode *node; struct interface *ifp; vty_out (vty, "Interface Status Protocol Description%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp)) { int len; len = vty_out (vty, "%s", ifp->name); vty_out (vty, "%*s", (16 - len), " "); if (if_is_up(ifp)) { vty_out (vty, "up "); if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) { if (if_is_running(ifp)) vty_out (vty, "up "); else vty_out (vty, "down "); } else { vty_out (vty, "unknown "); } } else { vty_out (vty, "down down "); } if (ifp->desc) vty_out (vty, "%s", ifp->desc); vty_out (vty, "%s", VTY_NEWLINE); } } DEFUN (show_interface_desc, show_interface_desc_cmd, "show interface description", SHOW_STR "Interface status and configuration\n" "Interface description\n") { vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); if_show_description (vty, vrf_id); return CMD_SUCCESS; } ALIAS (show_interface_desc, show_interface_desc_vrf_cmd, "show interface description " VRF_CMD_STR, SHOW_STR "Interface status and configuration\n" "Interface description\n" VRF_CMD_HELP_STR) DEFUN (show_interface_desc_vrf_all, show_interface_desc_vrf_all_cmd, "show interface description " VRF_ALL_CMD_STR, SHOW_STR "Interface status and configuration\n" "Interface description\n" VRF_ALL_CMD_HELP_STR) { vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if (!list_isempty (vrf_iter2iflist (iter))) { vty_out (vty, "%s\tVRF %u%s%s", VTY_NEWLINE, vrf_iter2id (iter), VTY_NEWLINE, VTY_NEWLINE); if_show_description (vty, vrf_iter2id (iter)); } 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; if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { 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; if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { 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; } /* Hacky: create a dummy node just to hang a config-writer callback off it */ static struct cmd_node zebra_if_defaults_node = { ZEBRA_IF_DEFAULTS_NODE, "", 1, }; static int config_write_zebra_if_defaults (struct vty *vty) { if (zif_defaults.linkdetect != IF_LINKDETECT_UNSPEC) vty_out (vty, "default link-detect %s%s", zif_defaults.linkdetect == IF_LINKDETECT_ON ? "on" : "off", VTY_NEWLINE); return 0; } DEFUN(default_linkdetect, default_linkdetect_cmd, "default link-detect (on|off)", "Configure defaults of settings\n" "Interface link detection\n" "Interface link-detect defaults to enabled\n" "Interface link-detect defaults to disabled\n") { zebra_if_linkdetect prev = zif_defaults.linkdetect; struct listnode *node; struct interface *ifp; vrf_iter_t iter; if (strcmp (argv[1], "on") == 0) zif_defaults.linkdetect = IF_LINKDETECT_ON; else zif_defaults.linkdetect = IF_LINKDETECT_OFF; if (zif_defaults.linkdetect != prev) for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp)) if_zebra_linkdetect_set (ifp); return CMD_SUCCESS; } DEFUN (linkdetect, linkdetect_cmd, "link-detect [default]", "Enable link detection on interface\n" "Leave link-detect to the default\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; assert (zif != NULL); zif->linkdetect = IF_LINKDETECT_ON; if_zebra_linkdetect_set (ifp); /* FIXME: Will defer status change forwarding if interface does not come down! */ return CMD_SUCCESS; } DEFUN (no_linkdetect, no_linkdetect_cmd, "no link-detect", NO_STR "Disable link detection on interface\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; assert (zif != NULL); zif->linkdetect = IF_LINKDETECT_OFF; if_zebra_linkdetect_set (ifp); /* FIXME: see linkdetect_cmd */ 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; if (ifp->ifindex != IFINDEX_INTERNAL) { 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; if (ifp->ifindex != IFINDEX_INTERNAL) { 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); /* Some addresses (in particular, IPv6 addresses on Linux) get * removed when the interface goes down. They need to be readded. */ if_addr_wakeup(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_operative (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_operative (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") struct cmd_node link_params_node = { LINK_PARAMS_NODE, "%s(config-link-params)# ", 1, }; static void link_param_cmd_set_uint32 (struct interface *ifp, uint32_t *field, uint32_t type, uint32_t value) { /* Update field as needed */ if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) { *field = value; SET_PARAM(ifp->link_params, type); /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative (ifp)) zebra_interface_parameters_update (ifp); } } static void link_param_cmd_set_float (struct interface *ifp, float *field, uint32_t type, float value) { /* Update field as needed */ if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) { *field = value; SET_PARAM(ifp->link_params, type); /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative (ifp)) zebra_interface_parameters_update (ifp); } } static void link_param_cmd_unset (struct interface *ifp, uint32_t type) { /* Unset field */ UNSET_PARAM(ifp->link_params, type); /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative (ifp)) zebra_interface_parameters_update (ifp); } DEFUN (link_params, link_params_cmd, "link-params", LINK_PARAMS_STR) { vty->node = LINK_PARAMS_NODE; return CMD_SUCCESS; } DEFUN (exit_link_params, exit_link_params_cmd, "exit-link-params", "Exit from Link Params configuration mode\n") { if (vty->node == LINK_PARAMS_NODE) vty->node = INTERFACE_NODE; return CMD_SUCCESS; } /* Specific Traffic Engineering parameters commands */ DEFUN (link_params_enable, link_params_enable_cmd, "enable", "Activate link parameters on this interface\n") { struct interface *ifp = (struct interface *) vty->index; /* This command could be issue at startup, when activate MPLS TE */ /* on a new interface or after a ON / OFF / ON toggle */ /* In all case, TE parameters are reset to their default factory */ if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("Link-params: enable TE link parameters on interface %s", ifp->name); if (!if_link_params_get (ifp)) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("Link-params: failed to init TE link parameters %s", ifp->name); return CMD_WARNING; } /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative (ifp)) zebra_interface_parameters_update (ifp); return CMD_SUCCESS; } DEFUN (no_link_params_enable, no_link_params_enable_cmd, "no enable", NO_STR "Disable link parameters on this interface\n") { struct interface *ifp = (struct interface *) vty->index; zlog_debug ("MPLS-TE: disable TE link parameters on interface %s", ifp->name); if_link_params_free (ifp); /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative (ifp)) zebra_interface_parameters_update (ifp); return CMD_SUCCESS; } /* STANDARD TE metrics */ DEFUN (link_params_metric, link_params_metric_cmd, "metric <0-4294967295>", "Link metric for MPLS-TE purpose\n" "Metric value in decimal\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); u_int32_t metric; VTY_GET_ULONG("metric", metric, argv[0]); /* Update TE metric if needed */ link_param_cmd_set_uint32 (ifp, &iflp->te_metric, LP_TE, metric); return CMD_SUCCESS; } DEFUN (no_link_params_metric, no_link_params_metric_cmd, "no metric", NO_STR "Disable Link Metric on this interface\n") { struct interface *ifp = (struct interface *) vty->index; /* Unset TE Metric */ link_param_cmd_unset(ifp, LP_TE); return CMD_SUCCESS; } DEFUN (link_params_maxbw, link_params_maxbw_cmd, "max-bw BANDWIDTH", "Maximum bandwidth that can be used\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); float bw; if (sscanf (argv[0], "%g", &bw) != 1) { vty_out (vty, "link_params_maxbw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Check that Maximum bandwidth is not lower than other bandwidth parameters */ if ((bw <= iflp->max_rsv_bw) || (bw <= iflp->unrsv_bw[0]) || (bw <= iflp->unrsv_bw[1]) || (bw <= iflp->unrsv_bw[2]) || (bw <= iflp->unrsv_bw[3]) || (bw <= iflp->unrsv_bw[4]) || (bw <= iflp->unrsv_bw[5]) || (bw <= iflp->unrsv_bw[6]) || (bw <= iflp->unrsv_bw[7]) || (bw <= iflp->ava_bw) || (bw <= iflp->res_bw) || (bw <= iflp->use_bw)) { vty_out (vty, "Maximum Bandwidth could not be lower than others bandwidth%s", VTY_NEWLINE); return CMD_WARNING; } /* Update Maximum Bandwidth if needed */ link_param_cmd_set_float (ifp, &iflp->max_bw, LP_MAX_BW, bw); return CMD_SUCCESS; } DEFUN (link_params_max_rsv_bw, link_params_max_rsv_bw_cmd, "max-rsv-bw BANDWIDTH", "Maximum bandwidth that may be reserved\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); float bw; if (sscanf (argv[0], "%g", &bw) != 1) { vty_out (vty, "link_params_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Check that bandwidth is not greater than maximum bandwidth parameter */ if (bw > iflp->max_bw) { vty_out (vty, "Maximum Reservable Bandwidth could not be greater than Maximum Bandwidth (%g)%s", iflp->max_bw, VTY_NEWLINE); return CMD_WARNING; } /* Update Maximum Reservable Bandwidth if needed */ link_param_cmd_set_float (ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, bw); return CMD_SUCCESS; } DEFUN (link_params_unrsv_bw, link_params_unrsv_bw_cmd, "unrsv-bw <0-7> BANDWIDTH", "Unreserved bandwidth at each priority level\n" "Priority\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); int priority; float bw; /* We don't have to consider about range check here. */ if (sscanf (argv[0], "%d", &priority) != 1) { vty_out (vty, "link_params_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (sscanf (argv[1], "%g", &bw) != 1) { vty_out (vty, "link_params_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Check that bandwidth is not greater than maximum bandwidth parameter */ if (bw > iflp->max_bw) { vty_out (vty, "UnReserved Bandwidth could not be greater than Maximum Bandwidth (%g)%s", iflp->max_bw, VTY_NEWLINE); return CMD_WARNING; } /* Update Unreserved Bandwidth if needed */ link_param_cmd_set_float (ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, bw); return CMD_SUCCESS; } DEFUN (link_params_admin_grp, link_params_admin_grp_cmd, "admin-grp BITPATTERN", "Administrative group membership\n" "32-bit Hexadecimal value (e.g. 0xa1)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); unsigned long value; if (sscanf (argv[0], "0x%lx", &value) != 1) { vty_out (vty, "link_params_admin_grp: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Update Administrative Group if needed */ link_param_cmd_set_uint32 (ifp, &iflp->admin_grp, LP_ADM_GRP, value); return CMD_SUCCESS; } DEFUN (no_link_params_admin_grp, no_link_params_admin_grp_cmd, "no admin-grp", NO_STR "Disable Administrative group membership on this interface\n") { struct interface *ifp = (struct interface *) vty->index; /* Unset Admin Group */ link_param_cmd_unset(ifp, LP_ADM_GRP); return CMD_SUCCESS; } /* RFC5392 & RFC5316: INTER-AS */ DEFUN (link_params_inter_as, link_params_inter_as_cmd, "neighbor A.B.C.D as <1-4294967295>", "Configure remote ASBR information (Neighbor IP address and AS number)\n" "Remote IP address in dot decimal A.B.C.D\n" "Remote AS number\n" "AS number in the range <1-4294967295>\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); struct in_addr addr; u_int32_t as; if (!inet_aton (argv[0], &addr)) { vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_ULONG("AS number", as, argv[1]); /* Update Remote IP and Remote AS fields if needed */ if (IS_PARAM_UNSET(iflp, LP_RMT_AS) || iflp->rmt_as != as || iflp->rmt_ip.s_addr != addr.s_addr) { iflp->rmt_as = as; iflp->rmt_ip.s_addr = addr.s_addr; SET_PARAM(iflp, LP_RMT_AS); /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative (ifp)) zebra_interface_parameters_update (ifp); } return CMD_SUCCESS; } DEFUN (no_link_params_inter_as, no_link_params_inter_as_cmd, "no neighbor", NO_STR "Remove Neighbor IP address and AS number for Inter-AS TE\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); /* Reset Remote IP and AS neighbor */ iflp->rmt_as = 0; iflp->rmt_ip.s_addr = 0; UNSET_PARAM(iflp, LP_RMT_AS); /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative (ifp)) zebra_interface_parameters_update (ifp); return CMD_SUCCESS; } /* RFC7471: OSPF Traffic Engineering (TE) Metric extensions & draft-ietf-isis-metric-extensions-07.txt */ DEFUN (link_params_delay, link_params_delay_cmd, "delay <0-16777215>", "Unidirectional Average Link Delay\n" "Average delay in micro-second as decimal (0...16777215)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); u_int32_t delay = 0, low = 0, high = 0; u_int8_t update = 0; /* Get and Check new delay values */ VTY_GET_ULONG("delay", delay, argv[0]); switch (argc) { case 1: /* Check new delay value against old Min and Max delays if set */ if (IS_PARAM_SET(iflp, LP_MM_DELAY) && (delay <= iflp->min_delay || delay >= iflp->max_delay)) { vty_out (vty, "Average delay should be comprise between Min (%d) and Max (%d) delay%s", iflp->min_delay, iflp->max_delay, VTY_NEWLINE); return CMD_WARNING; } /* Update delay if value is not set or change */ if (IS_PARAM_UNSET(iflp, LP_DELAY)|| iflp->av_delay != delay) { iflp->av_delay = delay; SET_PARAM(iflp, LP_DELAY); update = 1; } /* Unset Min and Max delays if already set */ if (IS_PARAM_SET(iflp, LP_MM_DELAY)) { iflp->min_delay = 0; iflp->max_delay = 0; UNSET_PARAM(iflp, LP_MM_DELAY); update = 1; } break; case 2: vty_out (vty, "You should specify both Minimum and Maximum delay with Average delay%s", VTY_NEWLINE); return CMD_WARNING; break; case 3: VTY_GET_ULONG("minimum delay", low, argv[1]); VTY_GET_ULONG("maximum delay", high, argv[2]); /* Check new delays value coherency */ if (delay <= low || delay >= high) { vty_out (vty, "Average delay should be comprise between Min (%d) and Max (%d) delay%s", low, high, VTY_NEWLINE); return CMD_WARNING; } /* Update Delays if needed */ if (IS_PARAM_UNSET(iflp, LP_DELAY) || IS_PARAM_UNSET(iflp, LP_MM_DELAY) || iflp->av_delay != delay || iflp->min_delay != low || iflp->max_delay != high) { iflp->av_delay = delay; SET_PARAM(iflp, LP_DELAY); iflp->min_delay = low; iflp->max_delay = high; SET_PARAM(iflp, LP_MM_DELAY); update = 1; } break; default: return CMD_WARNING; break; } /* force protocols to update LINK STATE due to parameters change */ if (update == 1 && if_is_operative (ifp)) zebra_interface_parameters_update (ifp); return CMD_SUCCESS; } ALIAS (link_params_delay, link_params_delay_mm_cmd, "delay <0-16777215> min <0-16777215> max <0-16777215>", "Unidirectional Average Link Delay (optionally Minimum and Maximum delays)\n" "Average delay in micro-second as decimal (0...16777215)\n" "Minimum delay\n" "Minimum delay in micro-second as decimal (0...16777215)\n" "Maximum delay\n" "Maximum delay in micro-second as decimal (0...16777215)\n") DEFUN (no_link_params_delay, no_link_params_delay_cmd, "no delay", NO_STR "Disable Unidirectional Average, Min & Max Link Delay on this interface\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); /* Unset Delays */ iflp->av_delay = 0; UNSET_PARAM(iflp, LP_DELAY); iflp->min_delay = 0; iflp->max_delay = 0; UNSET_PARAM(iflp, LP_MM_DELAY); /* force protocols to update LINK STATE due to parameters change */ if (if_is_operative (ifp)) zebra_interface_parameters_update (ifp); return CMD_SUCCESS; } DEFUN (link_params_delay_var, link_params_delay_var_cmd, "delay-variation <0-16777215>", "Unidirectional Link Delay Variation\n" "delay variation in micro-second as decimal (0...16777215)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); u_int32_t value; VTY_GET_ULONG("delay variation", value, argv[0]); /* Update Delay Variation if needed */ link_param_cmd_set_uint32 (ifp, &iflp->delay_var, LP_DELAY_VAR, value); return CMD_SUCCESS; } DEFUN (no_link_params_delay_var, no_link_params_delay_var_cmd, "no delay-variation", NO_STR "Disable Unidirectional Delay Variation on this interface\n") { struct interface *ifp = (struct interface *) vty->index; /* Unset Delay Variation */ link_param_cmd_unset(ifp, LP_DELAY_VAR); return CMD_SUCCESS; } DEFUN (link_params_pkt_loss, link_params_pkt_loss_cmd, "packet-loss PERCENTAGE", "Unidirectional Link Packet Loss\n" "percentage of total traffic by 0.000003% step and less than 50.331642%\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); float fval; if (sscanf (argv[0], "%g", &fval) != 1) { vty_out (vty, "link_params_pkt_loss: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (fval > MAX_PKT_LOSS) fval = MAX_PKT_LOSS; /* Update Packet Loss if needed */ link_param_cmd_set_float (ifp, &iflp->pkt_loss, LP_PKT_LOSS, fval); return CMD_SUCCESS; } DEFUN (no_link_params_pkt_loss, no_link_params_pkt_loss_cmd, "no packet-loss", NO_STR "Disable Unidirectional Link Packet Loss on this interface\n") { struct interface *ifp = (struct interface *) vty->index; /* Unset Packet Loss */ link_param_cmd_unset(ifp, LP_PKT_LOSS); return CMD_SUCCESS; } DEFUN (link_params_res_bw, link_params_res_bw_cmd, "res-bw BANDWIDTH", "Unidirectional Residual Bandwidth\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); float bw; if (sscanf (argv[0], "%g", &bw) != 1) { vty_out (vty, "link_params_res_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Check that bandwidth is not greater than maximum bandwidth parameter */ if (bw > iflp->max_bw) { vty_out (vty, "Residual Bandwidth could not be greater than Maximum Bandwidth (%g)%s", iflp->max_bw, VTY_NEWLINE); return CMD_WARNING; } /* Update Residual Bandwidth if needed */ link_param_cmd_set_float (ifp, &iflp->res_bw, LP_RES_BW, bw); return CMD_SUCCESS; } DEFUN (no_link_params_res_bw, no_link_params_res_bw_cmd, "no res-bw", NO_STR "Disable Unidirectional Residual Bandwidth on this interface\n") { struct interface *ifp = (struct interface *) vty->index; /* Unset Residual Bandwidth */ link_param_cmd_unset(ifp, LP_RES_BW); return CMD_SUCCESS; } DEFUN (link_params_ava_bw, link_params_ava_bw_cmd, "ava-bw BANDWIDTH", "Unidirectional Available Bandwidth\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); float bw; if (sscanf (argv[0], "%g", &bw) != 1) { vty_out (vty, "link_params_ava_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Check that bandwidth is not greater than maximum bandwidth parameter */ if (bw > iflp->max_bw) { vty_out (vty, "Available Bandwidth could not be greater than Maximum Bandwidth (%g)%s", iflp->max_bw, VTY_NEWLINE); return CMD_WARNING; } /* Update Residual Bandwidth if needed */ link_param_cmd_set_float (ifp, &iflp->ava_bw, LP_AVA_BW, bw); return CMD_SUCCESS; } DEFUN (no_link_params_ava_bw, no_link_params_ava_bw_cmd, "no ava-bw", NO_STR "Disable Unidirectional Available Bandwidth on this interface\n") { struct interface *ifp = (struct interface *) vty->index; /* Unset Available Bandwidth */ link_param_cmd_unset(ifp, LP_AVA_BW); return CMD_SUCCESS; } DEFUN (link_params_use_bw, link_params_use_bw_cmd, "use-bw BANDWIDTH", "Unidirectional Utilised Bandwidth\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct if_link_params *iflp = if_link_params_get (ifp); float bw; if (sscanf (argv[0], "%g", &bw) != 1) { vty_out (vty, "link_params_use_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } /* Check that bandwidth is not greater than maximum bandwidth parameter */ if (bw > iflp->max_bw) { vty_out (vty, "Utilised Bandwidth could not be greater than Maximum Bandwidth (%g)%s", iflp->max_bw, VTY_NEWLINE); return CMD_WARNING; } /* Update Utilized Bandwidth if needed */ link_param_cmd_set_float (ifp, &iflp->use_bw, LP_USE_BW, bw); return CMD_SUCCESS; } DEFUN (no_link_params_use_bw, no_link_params_use_bw_cmd, "no use-bw", NO_STR "Disable Unidirectional Utilised Bandwidth on this interface\n") { struct interface *ifp = (struct interface *) vty->index; /* Unset Utilised Bandwidth */ link_param_cmd_unset(ifp, LP_USE_BW); return CMD_SUCCESS; } static int ip_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const char *label) { struct zebra_if *if_data; struct prefix_ipv4 cp; struct connected *ifc; struct prefix_ipv4 *p; int ret; if_data = ifp->info; ret = str2prefix_ipv4 (addr_str, &cp); if (ret <= 0) { vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); return CMD_WARNING; } ifc = connected_check (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 <= IPV4_MAX_PREFIXLEN-2) { p = prefix_ipv4_new (); *p = cp; p->prefix.s_addr = ipv4_broadcast_addr(p->prefix.s_addr,p->prefixlen); ifc->destination = (struct prefix *) p; } /* Label. */ if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, 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_QUEUED) && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE) && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) { /* 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", safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* The address will be advertised to zebra clients when the notification * from the kernel has been received. * It will also be added to the subnet chain list, then. */ } return CMD_SUCCESS; } static int ip_address_uninstall (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const char *label) { 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 (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; UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); /* This is not real address or interface is not active. */ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED) || ! 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", safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* we will receive a kernel notification about this route being removed. * this will trigger its removal from the connected list. */ 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); } 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); } #ifdef HAVE_NETLINK 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]); } 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]); } #endif /* HAVE_NETLINK */ #ifdef HAVE_IPV6 static int ipv6_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const char *label, int secondary) { struct zebra_if *if_data; struct prefix_ipv6 cp; struct connected *ifc; struct prefix_ipv6 *p; int ret; if_data = ifp->info; ret = str2prefix_ipv6 (addr_str, &cp); if (ret <= 0) { vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); return CMD_WARNING; } ifc = connected_check (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 = XSTRDUP (MTYPE_CONNECTED_LABEL, 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_QUEUED) && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE) && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)) { /* 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", safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* The address will be advertised to zebra clients when the notification * from the kernel has been received. */ } return CMD_SUCCESS; } static int ipv6_address_uninstall (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const 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 (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; UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); /* This is not real address or interface is not active. */ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED) || ! 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", safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED); /* This information will be propagated to the zclients when the * kernel notification is received. */ return CMD_SUCCESS; } DEFUN (ipv6_address, ipv6_address_cmd, "ipv6 address X:X::X:X/M", "Interface IPv6 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 IPv6 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 */ static int link_params_config_write (struct vty *vty, struct interface *ifp) { int i; if ((ifp == NULL) || !HAS_LINK_PARAMS(ifp)) return -1; struct if_link_params *iflp = ifp->link_params; vty_out (vty, " link-params%s", VTY_NEWLINE); vty_out(vty, " enable%s", VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_TE)) vty_out(vty, " metric %u%s",iflp->te_metric, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_MAX_BW)) vty_out(vty, " max-bw %g%s", iflp->max_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW)) vty_out(vty, " max-rsv-bw %g%s", iflp->max_rsv_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) { for (i = 0; i < 8; i++) vty_out(vty, " unrsv-bw %d %g%s", i, iflp->unrsv_bw[i], VTY_NEWLINE); } if (IS_PARAM_SET(iflp, LP_ADM_GRP)) vty_out(vty, " admin-grp %u%s", iflp->admin_grp, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_DELAY)) { vty_out(vty, " delay %u", iflp->av_delay); if (IS_PARAM_SET(iflp, LP_MM_DELAY)) { vty_out(vty, " min %u", iflp->min_delay); vty_out(vty, " max %u", iflp->max_delay); } vty_out(vty, "%s", VTY_NEWLINE); } if (IS_PARAM_SET(iflp, LP_DELAY_VAR)) vty_out(vty, " delay-variation %u%s", iflp->delay_var, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) vty_out(vty, " packet-loss %g%s", iflp->pkt_loss, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_AVA_BW)) vty_out(vty, " ava-bw %g%s", iflp->ava_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_RES_BW)) vty_out(vty, " res-bw %g%s", iflp->res_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_USE_BW)) vty_out(vty, " use-bw %g%s", iflp->use_bw, VTY_NEWLINE); if (IS_PARAM_SET(iflp, LP_RMT_AS)) vty_out(vty, " neighbor %s as %u%s", inet_ntoa(iflp->rmt_ip), iflp->rmt_as, VTY_NEWLINE); vty_out(vty, " exit-link-params%s", VTY_NEWLINE); return 0; } static int if_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp)) { struct zebra_if *if_data; struct listnode *addrnode; struct connected *ifc; struct prefix *p; if_data = ifp->info; if (ifp->vrf_id == VRF_DEFAULT) vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); else vty_out (vty, "interface %s vrf %u%s", ifp->name, ifp->vrf_id, VTY_NEWLINE); if (if_data) { if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) vty_out (vty, " shutdown%s", 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); switch (if_data->linkdetect) { case IF_LINKDETECT_ON: vty_out(vty, " link-detect%s", VTY_NEWLINE); break; case IF_LINKDETECT_OFF: vty_out(vty, " no link-detect%s", VTY_NEWLINE); break; default: break; } for (ALL_LIST_ELEMENTS_RO (ifp->connected, addrnode, ifc)) { if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) { char buf[INET6_ADDRSTRLEN]; p = ifc->address; vty_out (vty, " ip%s address %s", p->family == AF_INET ? "" : "v6", prefix2str (p, buf, sizeof(buf))); if (ifc->label) vty_out (vty, " label %s", ifc->label); vty_out (vty, "%s", VTY_NEWLINE); } } if (if_data) { if (if_data->multicast != IF_ZEBRA_MULTICAST_UNSPEC) vty_out (vty, " %smulticast%s", if_data->multicast == IF_ZEBRA_MULTICAST_ON ? "" : "no ", VTY_NEWLINE); } #if defined (HAVE_RTADV) rtadv_config_write (vty, ifp); #endif /* HAVE_RTADV */ #ifdef HAVE_IRDP irdp_config_write (vty, ifp); #endif /* IRDP */ link_params_config_write (vty, ifp); vty_out (vty, "!%s", VTY_NEWLINE); } return 0; } /* Allocate and initialize interface vector. */ void zebra_if_init (void) { /* Initialize interface and new hook. */ 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_node (&zebra_if_defaults_node, config_write_zebra_if_defaults); install_node (&link_params_node, NULL); install_element (VIEW_NODE, &show_interface_cmd); install_element (VIEW_NODE, &show_interface_vrf_cmd); install_element (VIEW_NODE, &show_interface_vrf_all_cmd); install_element (VIEW_NODE, &show_interface_name_cmd); install_element (VIEW_NODE, &show_interface_name_vrf_cmd); install_element (VIEW_NODE, &show_interface_name_vrf_all_cmd); install_element (CONFIG_NODE, &zebra_interface_cmd); install_element (CONFIG_NODE, &zebra_interface_vrf_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_element (CONFIG_NODE, &no_interface_vrf_cmd); install_element (CONFIG_NODE, &default_linkdetect_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, &linkdetect_cmd); install_element (INTERFACE_NODE, &no_linkdetect_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 HAVE_NETLINK install_element (INTERFACE_NODE, &ip_address_label_cmd); install_element (INTERFACE_NODE, &no_ip_address_label_cmd); #endif /* HAVE_NETLINK */ install_element(INTERFACE_NODE, &link_params_cmd); install_default(LINK_PARAMS_NODE); install_element(LINK_PARAMS_NODE, &link_params_enable_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); install_element(LINK_PARAMS_NODE, &link_params_metric_cmd); install_element(LINK_PARAMS_NODE, &link_params_maxbw_cmd); install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_admin_grp_cmd); install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_inter_as_cmd); install_element(LINK_PARAMS_NODE, &link_params_delay_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_delay_cmd); install_element(LINK_PARAMS_NODE, &link_params_delay_mm_cmd); install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_delay_var_cmd); install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_pkt_loss_cmd); install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_ava_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_res_bw_cmd); install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_use_bw_cmd); install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); } quagga-1.2.4/zebra/interface.h000066400000000000000000000201521325323223500161770ustar00rootroot00000000000000/* 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. */ #ifndef _ZEBRA_INTERFACE_H #define _ZEBRA_INTERFACE_H #include "redistribute.h" #include "event_counter.h" #ifdef HAVE_IRDP #include "zebra/irdp.h" #endif /* 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_OFF 0 #define IF_ZEBRA_SHUTDOWN_ON 1 /* Global user-configured default for interface link-detect */ typedef enum { IF_LINKDETECT_UNSPEC = 0, IF_LINKDETECT_ON, IF_LINKDETECT_OFF, } zebra_if_linkdetect; /* Global defaults for interfaces */ struct zebra_if_defaults { /* Link-detect default configuration */ zebra_if_linkdetect linkdetect; }; #if defined (HAVE_RTADV) /* Router advertisement parameter. From RFC4861, RFC6275 and RFC4191. */ 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 milliseconds. MUST be no less than 70 ms [RFC6275 7.5] and no greater than 1800000 ms [RFC4861 6.2.1]. Default: 600000 milliseconds */ int MaxRtrAdvInterval; #define RTADV_MAX_RTR_ADV_INTERVAL 600000 /* The minimum time allowed between sending unsolicited multicast Router Advertisements from the interface, in milliseconds. MUST be no less than 30 ms [RFC6275 7.5]. MUST be no greater than .75 * MaxRtrAdvInterval. Default: 0.33 * MaxRtrAdvInterval */ int MinRtrAdvInterval; /* This field is currently unused. */ #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_MAX_RTRLIFETIME 9000 /* 2.5 hours */ /* 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. */ struct list *AdvPrefixList; /* The TRUE/FALSE value to be placed in the "Home agent" flag field in the Router Advertisement. See [RFC6275 7.1]. Default: FALSE */ int AdvHomeAgentFlag; #ifndef ND_RA_FLAG_HOME_AGENT #define ND_RA_FLAG_HOME_AGENT 0x20 #endif /* The value to be placed in Home Agent Information option if Home Flag is set. Default: 0 */ int HomeAgentPreference; /* The value to be placed in Home Agent Information option if Home Flag is set. Lifetime (seconds) MUST not be greater than 18.2 hours. The value 0 has special meaning: use of AdvDefaultLifetime value. Default: 0 */ int HomeAgentLifetime; #define RTADV_MAX_HALIFETIME 65520 /* 18.2 hours */ /* The TRUE/FALSE value to insert or not an Advertisement Interval option. See [RFC 6275 7.3] Default: FALSE */ int AdvIntervalOption; /* The value to be placed in the Default Router Preference field of a router advertisement. See [RFC 4191 2.1 & 2.2] Default: 0 (medium) */ int DefaultPreference; #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ }; #endif /* HAVE_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 specific link-detect configuration state */ zebra_if_linkdetect linkdetect; /* Installed addresses chains tree. */ struct route_table *ipv4_subnets; /* Information about up/down changes */ struct event_counter up_events; struct event_counter down_events; #if defined(HAVE_RTADV) struct rtadvconf rtadv; #endif /* RTADV */ #ifdef HAVE_IRDP struct irdp_interface irdp; #endif #ifdef HAVE_STRUCT_SOCKADDR_DL union { /* note that sdl_storage is never accessed, it only exists to make space. * all actual uses refer to sdl - but use sizeof(sdl_storage)! this fits * best with C aliasing rules. */ struct sockaddr_dl sdl; struct sockaddr_storage sdl_storage; }; #endif #ifdef SUNOS_5 /* the real IFF_UP state of the primary interface. * need this to differentiate between all interfaces being * down (but primary still plumbed) and primary having gone * ~IFF_UP, and all addresses gone. */ u_char primary_state; #endif /* SUNOS_5 */ }; extern void if_delete_update (struct interface *ifp); extern void if_add_update (struct interface *ifp); extern void if_up (struct interface *); extern void if_down (struct interface *); extern void if_refresh (struct interface *); extern void if_flags_update (struct interface *, uint64_t); extern void if_startup_count_up (void); extern int if_subnet_add (struct interface *, struct connected *); extern int if_subnet_delete (struct interface *, struct connected *); #ifdef HAVE_PROC_NET_DEV extern void ifstat_update_proc (void); #endif /* HAVE_PROC_NET_DEV */ #ifdef HAVE_NET_RT_IFLIST extern void ifstat_update_sysctl (void); #endif /* HAVE_NET_RT_IFLIST */ #ifdef HAVE_PROC_NET_DEV extern int interface_list_proc (void); #endif /* HAVE_PROC_NET_DEV */ #ifdef HAVE_PROC_NET_IF_INET6 extern int ifaddr_proc_ipv6 (void); #endif /* HAVE_PROC_NET_IF_INET6 */ #endif /* _ZEBRA_INTERFACE_H */ quagga-1.2.4/zebra/ioctl.c000066400000000000000000000352771325323223500153620ustar00rootroot00000000000000/* * 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 "privs.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/interface.h" #ifdef HAVE_BSD_LINK_DETECT #include #endif /* HAVE_BSD_LINK_DETECT*/ extern struct zebra_privs_t zserv_privs; /* 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; int err = 0; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno)); exit (1); } if ((ret = ioctl (sock, request, buffer)) < 0) err = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); close (sock); if (ret < 0) { errno = err; return ret; } return 0; } #ifdef HAVE_IPV6 static int if_ioctl_ipv6 (u_long request, caddr_t buffer) { int sock; int ret; int err = 0; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_err("Cannot create IPv6 datagram socket: %s", safe_strerror(save_errno)); exit (1); } if ((ret = ioctl (sock, request, buffer)) < 0) err = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); 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->mtu6 = ifp->mtu = -1; return; } #ifdef SUNOS_5 ifp->mtu6 = ifp->mtu = ifreq.ifr_metric; #else ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu; #endif /* SUNOS_5 */ /* propogate */ zebra_interface_up_update(ifp); #else zlog (NULL, LOG_INFO, "Can't lookup mtu on this system"); ifp->mtu6 = 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_STRUCT_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_STRUCT_SOCKADDR_IN_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_STRUCT_SOCKADDR_IN_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_STRUCT_SOCKADDR_IN_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_STRUCT_SOCKADDR_IN_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_STRUCT_IFALIASREQ */ #endif /* HAVE_NETLINK */ /* get interface flags */ void if_get_flags (struct interface *ifp) { int ret; struct ifreq ifreq; #ifdef HAVE_BSD_LINK_DETECT struct ifmediareq ifmr; #endif /* HAVE_BSD_LINK_DETECT */ ifreq_set_name (&ifreq, ifp); ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno)); return; } #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */ /* Per-default, IFF_RUNNING is held high, unless link-detect says * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag, * following practice on Linux and Solaris kernels */ SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) { (void) memset(&ifmr, 0, sizeof(ifmr)); strncpy (ifmr.ifm_name, ifp->name, IFNAMSIZ); /* Seems not all interfaces implement this ioctl */ if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno)); else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */ { if (ifmr.ifm_status & IFM_ACTIVE) SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); else UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); } } #endif /* HAVE_BSD_LINK_DETECT */ if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff)); } /* Set interface flags */ int if_set_flags (struct interface *ifp, uint64_t flags) { int ret; struct ifreq ifreq; memset (&ifreq, 0, sizeof(struct 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, uint64_t flags) { int ret; struct ifreq ifreq; memset (&ifreq, 0, sizeof(struct 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_STRUCT_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_STRUCT_SOCKADDR_IN_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_STRUCT_SOCKADDR_IN_SIN_LEN mask.sin6_len = sizeof (struct sockaddr_in6); #endif memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); addreq.ifra_lifetime.ia6t_vltime = 0xffffffff; addreq.ifra_lifetime.ia6t_pltime = 0xffffffff; #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; #endif 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_STRUCT_SOCKADDR_IN_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_STRUCT_SOCKADDR_IN_SIN_LEN mask.sin6_len = sizeof (struct sockaddr_in6); #endif memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; #endif 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_STRUCT_IN6_ALIASREQ */ #endif /* LINUX_IPV6 */ #endif /* HAVE_IPV6 */ quagga-1.2.4/zebra/ioctl.h000066400000000000000000000037411325323223500153560ustar00rootroot00000000000000/* * 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. */ extern void ifreq_set_name (struct ifreq *, struct interface *); extern int if_ioctl (u_long, caddr_t); extern int if_set_flags (struct interface *, uint64_t); extern int if_unset_flags (struct interface *, uint64_t); extern void if_get_flags (struct interface *); extern int if_set_prefix (struct interface *, struct connected *); extern int if_unset_prefix (struct interface *, struct connected *); extern void if_get_metric (struct interface *); extern void if_get_mtu (struct interface *); #ifdef HAVE_IPV6 extern int if_prefix_add_ipv6 (struct interface *, struct connected *); extern int if_prefix_delete_ipv6 (struct interface *, struct connected *); #endif /* HAVE_IPV6 */ #ifdef SOLARIS_IPV6 extern int if_ioctl_ipv6(u_long, caddr_t); extern struct connected *if_lookup_linklocal( struct interface *); #define AF_IOCTL(af, request, buffer) \ ((af) == AF_INET? if_ioctl(request, buffer) : \ if_ioctl_ipv6(request, buffer)) #else /* SOLARIS_IPV6 */ #define AF_IOCTL(af, request, buffer) if_ioctl(request, buffer) #endif /* SOLARIS_IPV6 */ #endif /* _ZEBRA_IOCTL_H */ quagga-1.2.4/zebra/ioctl_null.c000066400000000000000000000046031325323223500164010ustar00rootroot00000000000000/* * Copyright (C) 2006 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "zebra/rib.h" #include "zebra/rt.h" #include "zebra/ioctl.h" void ifreq_set_name (struct ifreq *a, struct interface *b) { return; } int if_set_prefix (struct interface *a, struct connected *b) { kernel_address_add_ipv4 (a, b); return 0; } int if_unset_prefix (struct interface *a, struct connected *b) { kernel_address_delete_ipv4 (a, b); return 0; } int if_prefix_add_ipv6 (struct interface *a, struct connected *b) { return 0; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak if_prefix_delete_ipv6 = if_prefix_add_ipv6 #else int if_prefix_delete_ipv6 (struct interface *a, struct connected *b) { return 0; } #endif int if_ioctl (u_long a, caddr_t b) { return 0; } int if_set_flags (struct interface *a, uint64_t b) { return 0; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak if_unset_flags = if_set_flags #else int if_unset_flags (struct interface *a, uint64_t b) { return 0; } #endif void if_get_flags (struct interface *a) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak if_get_metric = if_get_flags #pragma weak if_get_mtu = if_get_flags #else /* void if_get_metric (struct interface *a) { return; } */ /* void if_get_mtu (struct interface *a) { return; } */ #endif #ifdef SOLARIS_IPV6 #pragma weak if_ioctl_ipv6 = if_ioctl struct connected *if_lookup_linklocal(struct interface *a) { return 0; } #define AF_IOCTL(af, request, buffer) \ ((af) == AF_INET? if_ioctl(request, buffer) : \ if_ioctl_ipv6(request, buffer)) #else /* SOLARIS_IPV6 */ #define AF_IOCTL(af, request, buffer) if_ioctl(request, buffer) #endif /* SOLARIS_IPV6 */ quagga-1.2.4/zebra/ioctl_solaris.c000066400000000000000000000231711325323223500171040ustar00rootroot00000000000000/* * Common ioctl functions for Solaris. * 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 "privs.h" #include "vty.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/interface.h" #include "zebra/ioctl_solaris.h" extern struct zebra_privs_t zserv_privs; /* clear and set interface name string */ void lifreq_set_name (struct lifreq *lifreq, const char *ifname) { strncpy (lifreq->lifr_name, ifname, IFNAMSIZ); } /* call ioctl system call */ int if_ioctl (u_long request, caddr_t buffer) { int sock; int ret; int err; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno)); exit (1); } if ((ret = ioctl (sock, request, buffer)) < 0) err = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); close (sock); if (ret < 0) { errno = err; return ret; } return 0; } int if_ioctl_ipv6 (u_long request, caddr_t buffer) { #ifdef HAVE_IPV6 int sock; int ret; int err; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_err("Cannot create IPv6 datagram socket: %s", safe_strerror(save_errno)); exit (1); } if ((ret = ioctl (sock, request, buffer)) < 0) err = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); close (sock); if (ret < 0) { errno = err; return ret; } #endif /* HAVE_IPV6 */ return 0; } /* * get interface metric * -- if value is not avaliable set -1 */ void if_get_metric (struct interface *ifp) { struct lifreq lifreq; int ret; lifreq_set_name (&lifreq, ifp->name); if (ifp->flags & IFF_IPV4) ret = AF_IOCTL (AF_INET, SIOCGLIFMETRIC, (caddr_t) & lifreq); #ifdef SOLARIS_IPV6 else if (ifp->flags & IFF_IPV6) ret = AF_IOCTL (AF_INET6, SIOCGLIFMETRIC, (caddr_t) & lifreq); #endif /* SOLARIS_IPV6 */ else ret = -1; if (ret < 0) return; ifp->metric = lifreq.lifr_metric; if (ifp->metric == 0) ifp->metric = 1; } /* get interface MTU */ void if_get_mtu (struct interface *ifp) { struct lifreq lifreq; int ret; u_char changed = 0; if (ifp->flags & IFF_IPV4) { lifreq_set_name (&lifreq, ifp->name); ret = AF_IOCTL (AF_INET, SIOCGLIFMTU, (caddr_t) & lifreq); if (ret < 0) { zlog_info ("Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)", ifp->name); ifp->mtu = -1; } else { ifp->mtu = lifreq.lifr_metric; changed = 1; } } #ifdef HAVE_IPV6 if (ifp->flags & IFF_IPV6) { memset(&lifreq, 0, sizeof(lifreq)); lifreq_set_name (&lifreq, ifp->name); ret = AF_IOCTL (AF_INET6, SIOCGLIFMTU, (caddr_t) & lifreq); if (ret < 0) { zlog_info ("Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)", ifp->name); ifp->mtu6 = -1; } else { ifp->mtu6 = lifreq.lifr_metric; changed = 1; } } #endif /* HAVE_IPV6 */ if (changed) zebra_interface_up_update(ifp); } /* Set up interface's address, netmask (and broadcast? ). 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; strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); 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 /* SUNOS_5 */ ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) & ifreq); return ((ret < 0) ? ret : 0); } /* Set up interface's address, netmask (and broadcast). 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; strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); 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; } /* Get just the flags for the given name. * Used by the normal 'if_get_flags' function, as well * as the bootup interface-list code, which has to peek at per-address * flags in order to figure out which ones should be ignored.. */ int if_get_flags_direct (const char *ifname, uint64_t *flags, unsigned int af) { struct lifreq lifreq; int ret; lifreq_set_name (&lifreq, ifname); ret = AF_IOCTL (af, SIOCGLIFFLAGS, (caddr_t) &lifreq); if (ret) zlog_debug ("%s: ifname %s, error %s (%d)", __func__, ifname, safe_strerror (errno), errno); *flags = lifreq.lifr_flags; return ret; } /* get interface flags */ void if_get_flags (struct interface *ifp) { int ret4 = 0, ret6 = 0; uint64_t newflags = 0; uint64_t tmpflags; if (ifp->flags & IFF_IPV4) { ret4 = if_get_flags_direct (ifp->name, &tmpflags, AF_INET); if (!ret4) newflags |= tmpflags; else if (errno == ENXIO) { /* it's gone */ UNSET_FLAG (ifp->flags, IFF_UP); if_flags_update (ifp, ifp->flags); } } if (ifp->flags & IFF_IPV6) { ret6 = if_get_flags_direct (ifp->name, &tmpflags, AF_INET6); if (!ret6) newflags |= tmpflags; else if (errno == ENXIO) { /* it's gone */ UNSET_FLAG (ifp->flags, IFF_UP); if_flags_update (ifp, ifp->flags); } } /* only update flags if one of above succeeded */ if ( !(ret4 && ret6) ) if_flags_update (ifp, newflags); } /* Set interface flags */ int if_set_flags (struct interface *ifp, uint64_t flags) { int ret; struct lifreq lifreq; lifreq_set_name (&lifreq, ifp->name); lifreq.lifr_flags = ifp->flags; lifreq.lifr_flags |= flags; if (ifp->flags & IFF_IPV4) ret = AF_IOCTL (AF_INET, SIOCSLIFFLAGS, (caddr_t) & lifreq); else if (ifp->flags & IFF_IPV6) ret = AF_IOCTL (AF_INET6, SIOCSLIFFLAGS, (caddr_t) & lifreq); else ret = -1; if (ret < 0) zlog_info ("can't set interface flags on %s: %s", ifp->name, safe_strerror (errno)); else ret = 0; return ret; } /* Unset interface's flag. */ int if_unset_flags (struct interface *ifp, uint64_t flags) { int ret; struct lifreq lifreq; lifreq_set_name (&lifreq, ifp->name); lifreq.lifr_flags = ifp->flags; lifreq.lifr_flags &= ~flags; if (ifp->flags & IFF_IPV4) ret = AF_IOCTL (AF_INET, SIOCSLIFFLAGS, (caddr_t) & lifreq); else if (ifp->flags & IFF_IPV6) ret = AF_IOCTL (AF_INET6, SIOCSLIFFLAGS, (caddr_t) & lifreq); else ret = -1; if (ret < 0) zlog_info ("can't unset interface flags"); else ret = 0; return ret; } #ifdef HAVE_IPV6 /* Interface's address add/delete functions. */ int if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) { char addrbuf[PREFIX_STRLEN]; zlog_warn ("Can't set %s on interface %s", prefix2str(ifc->address, addrbuf, sizeof(addrbuf)), ifp->name); return 0; } int if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) { char addrbuf[PREFIX_STRLEN]; zlog_warn ("Can't delete %s on interface %s", prefix2str(ifc->address, addrbuf, sizeof(addrbuf)), ifp->name); return 0; } #endif /* HAVE_IPV6 */ quagga-1.2.4/zebra/ioctl_solaris.h000066400000000000000000000020611325323223500171040ustar00rootroot00000000000000/* * Interface looking up by ioctl () on Solaris. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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_IOCTL_SOLARIS_H #define _ZEBRA_IF_IOCTL_SOLARIS_H void lifreq_set_name (struct lifreq *, const char *); int if_get_flags_direct (const char *, uint64_t *, unsigned int af); #endif /* _ZEBRA_IF_IOCTL_SOLARIS_H */ quagga-1.2.4/zebra/ipforward.h000066400000000000000000000022121325323223500162310ustar00rootroot00000000000000/* 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 extern int ipforward (void); extern int ipforward_on (void); extern int ipforward_off (void); #ifdef HAVE_IPV6 extern int ipforward_ipv6 (void); extern int ipforward_ipv6_on (void); extern int ipforward_ipv6_off (void); #endif /* HAVE_IPV6 */ #endif /* _ZEBRA_IPFORWARD_H */ quagga-1.2.4/zebra/ipforward_proc.c000066400000000000000000000101621325323223500172520ustar00rootroot00000000000000/* * 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 #include "log.h" #include "privs.h" #include "zebra/ipforward.h" extern struct zebra_privs_t zserv_privs; char proc_net_snmp[] = "/proc/net/snmp"; static void dropline (FILE *fp) { int c; while ((c = getc (fp)) != '\n') ; } int ipforward (void) { FILE *fp; int ipforwarding = 0; 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. */ if (fgets (buf, 6, fp)) sscanf (buf, "Ip: %d", &ipforwarding); fclose(fp); 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 (void) { FILE *fp; if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog_err ("Can't raise privileges, %s", safe_strerror (errno) ); fp = fopen (proc_ipv4_forwarding, "w"); if (fp == NULL) { if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return -1; } fprintf (fp, "1\n"); fclose (fp); if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return ipforward (); } int ipforward_off (void) { FILE *fp; if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog_err ("Can't raise privileges, %s", safe_strerror (errno)); fp = fopen (proc_ipv4_forwarding, "w"); if (fp == NULL) { if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return -1; } fprintf (fp, "0\n"); fclose (fp); if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return ipforward (); } #ifdef HAVE_IPV6 char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding"; int ipforward_ipv6 (void) { FILE *fp; char buf[5]; int ipforwarding = 0; fp = fopen (proc_ipv6_forwarding, "r"); if (fp == NULL) return -1; if (fgets (buf, 2, fp)) sscanf (buf, "%d", &ipforwarding); fclose (fp); return ipforwarding; } int ipforward_ipv6_on (void) { FILE *fp; if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog_err ("Can't raise privileges, %s", safe_strerror (errno)); fp = fopen (proc_ipv6_forwarding, "w"); if (fp == NULL) { if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return -1; } fprintf (fp, "1\n"); fclose (fp); if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return ipforward_ipv6 (); } int ipforward_ipv6_off (void) { FILE *fp; if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog_err ("Can't raise privileges, %s", safe_strerror (errno)); fp = fopen (proc_ipv6_forwarding, "w"); if (fp == NULL) { if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return -1; } fprintf (fp, "0\n"); fclose (fp); if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return ipforward_ipv6 (); } #endif /* HAVE_IPV6 */ quagga-1.2.4/zebra/ipforward_solaris.c000066400000000000000000000104271325323223500177670ustar00rootroot00000000000000/* * 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 "log.h" #include "prefix.h" #include "privs.h" #include "zebra/ipforward.h" /* ** Solaris should define IP_DEV_NAME in , but we'll save ** configure.in changes for another day. We can use the same device ** for both IPv4 and IPv6. */ /* #include */ #ifndef IP_DEV_NAME #define IP_DEV_NAME "/dev/ip" #endif extern struct zebra_privs_t zserv_privs; /* This is a limited ndd style function that operates one integer ** value only. Errors return -1. ND_SET commands return 0 on ** success. ND_GET commands return the value on success (which could ** be -1 and be confused for an error). The parameter is the string ** name of the parameter being referenced. */ static int solaris_nd(const int cmd, const char* parameter, const int value) { #define ND_BUFFER_SIZE 1024 int fd; char nd_buf[ND_BUFFER_SIZE]; struct strioctl strioctl; const char* device = IP_DEV_NAME; int retval; memset(nd_buf, '\0', ND_BUFFER_SIZE); /* ** ND_SET takes a NULL delimited list of strings further terminated ** buy a NULL. ND_GET returns a list in a similar layout, although ** here we only use the first result. */ if (cmd == ND_SET) snprintf(nd_buf, ND_BUFFER_SIZE, "%s%c%d%c", parameter, '\0', value,'\0'); else if (cmd == ND_GET) snprintf(nd_buf, ND_BUFFER_SIZE, "%s", parameter); else { zlog_err("internal error - inappropriate command given to " "solaris_nd()%s:%d", __FILE__, __LINE__); return -1; } strioctl.ic_cmd = cmd; strioctl.ic_timout = 0; strioctl.ic_len = ND_BUFFER_SIZE; strioctl.ic_dp = nd_buf; if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("solaris_nd: Can't raise privileges"); if ((fd = open (device, O_RDWR)) < 0) { zlog_warn("failed to open device %s - %s", device, safe_strerror(errno)); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("solaris_nd: Can't lower privileges"); return -1; } if (ioctl (fd, I_STR, &strioctl) < 0) { int save_errno = errno; if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("solaris_nd: Can't lower privileges"); close (fd); zlog_warn("ioctl I_STR failed on device %s - %s", device, safe_strerror(save_errno)); return -1; } close(fd); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("solaris_nd: Can't lower privileges"); if (cmd == ND_GET) { errno = 0; retval = atoi(nd_buf); if (errno) { zlog_warn("failed to convert returned value to integer - %s", safe_strerror(errno)); retval = -1; } } else { retval = 0; } return retval; } static int solaris_nd_set(const char* parameter, const int value) { return solaris_nd(ND_SET, parameter, value); } static int solaris_nd_get(const char* parameter) { return solaris_nd(ND_GET, parameter, 0); } int ipforward(void) { return solaris_nd_get("ip_forwarding"); } int ipforward_on (void) { (void) solaris_nd_set("ip_forwarding", 1); return ipforward(); } int ipforward_off (void) { (void) solaris_nd_set("ip_forwarding", 0); return ipforward(); } #ifdef HAVE_IPV6 int ipforward_ipv6(void) { return solaris_nd_get("ip6_forwarding"); } int ipforward_ipv6_on (void) { (void) solaris_nd_set("ip6_forwarding", 1); return ipforward_ipv6(); } int ipforward_ipv6_off (void) { (void) solaris_nd_set("ip6_forwarding", 0); return ipforward_ipv6(); } #endif /* HAVE_IPV6 */ quagga-1.2.4/zebra/ipforward_sysctl.c000066400000000000000000000104601325323223500176310ustar00rootroot00000000000000/* 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 #include "privs.h" #include "zebra/ipforward.h" #include "log.h" #define MIB_SIZ 4 extern struct zebra_privs_t zserv_privs; /* IPv4 forwarding control MIB. */ int mib[MIB_SIZ] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_FORWARDING }; int ipforward (void) { size_t 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 (void) { size_t len; int ipforwarding = 1; len = sizeof ipforwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("Can't set ipforwarding on"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ipforwarding; } int ipforward_off (void) { size_t len; int ipforwarding = 0; len = sizeof ipforwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("Can't set ipforwarding on"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ipforwarding; } #ifdef HAVE_IPV6 /* IPv6 forwarding control MIB. */ int mib_ipv6[MIB_SIZ] = { CTL_NET, PF_INET6, #if defined(KAME) IPPROTO_IPV6, IPV6CTL_FORWARDING #else /* NOT KAME */ IPPROTO_IP, IP6CTL_FORWARDING #endif /* KAME */ }; int ipforward_ipv6 (void) { size_t len; int ip6forwarding = 0; len = sizeof ip6forwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } int ipforward_ipv6_on (void) { size_t len; int ip6forwarding = 1; len = sizeof ip6forwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } int ipforward_ipv6_off (void) { size_t len; int ip6forwarding = 0; len = sizeof ip6forwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } #endif /* HAVE_IPV6 */ quagga-1.2.4/zebra/irdp.h000066400000000000000000000115271325323223500152030ustar00rootroot00000000000000/* 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 #include "lib/vty.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; struct list *AdvPrefList; }; struct Adv { struct in_addr ip; int pref; }; extern void irdp_init(void); extern int irdp_sock_init(void); extern void irdp_finish(void); extern void irdp_config_write (struct vty *, struct interface *); extern int irdp_send_thread(struct thread *t_advert); extern void irdp_advert_off(struct interface *ifp); extern void process_solicit (struct interface *ifp); extern int irdp_read_raw(struct thread *r); extern void send_packet(struct interface *ifp, struct stream *s, u_int32_t dst, struct prefix *p, u_int32_t ttl); #endif /* _IRDP_H */ quagga-1.2.4/zebra/irdp_interface.c000066400000000000000000000426311325323223500172160ustar00rootroot00000000000000/* * * 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 zebra_t zebrad; extern int irdp_sock; static const 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; } static struct prefix * irdp_get_prefix(struct interface *ifp) { struct listnode *node; struct connected *ifc; if (ifp->connected) for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) return ifc->address; return NULL; } /* Join to the add/leave multicast group. */ static int if_group (struct interface *ifp, int sock, u_int32_t group, int add_leave) { struct ip_mreq m; struct prefix *p; int ret; char b1[INET_ADDRSTRLEN]; memset (&m, 0, 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), safe_strerror (errno)); return ret; } static int if_add_group (struct interface *ifp) { struct zebra_if *zi= ifp->info; struct irdp_interface *irdp = &zi->irdp; int ret; char b1[INET_ADDRSTRLEN]; ret = if_group (ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_ADD_MEMBERSHIP); if (ret < 0) { return ret; } if(irdp->flags & IF_DEBUG_MISC ) zlog_debug("IRDP: Adding group %s for %s", inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1), ifp->name); return 0; } static int if_drop_group (struct interface *ifp) { struct zebra_if *zi= ifp->info; struct irdp_interface *irdp = &zi->irdp; int ret; char b1[INET_ADDRSTRLEN]; ret = if_group (ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_DROP_MEMBERSHIP); if (ret < 0) return ret; if(irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: Leaving group %s for %s", inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1), ifp->name); return 0; } static 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; } static struct Adv *Adv_new (void) { return XCALLOC (MTYPE_TMP, sizeof (struct Adv)); } static void Adv_free (struct Adv *adv) { XFREE (MTYPE_TMP, adv); } static void irdp_if_start(struct interface *ifp, int multicast, int set_defaults) { struct zebra_if *zi= ifp->info; struct irdp_interface *irdp = &zi->irdp; struct listnode *node; struct connected *ifc; u_int32_t timer, seed; if (irdp->flags & IF_ACTIVE ) { zlog_warn("IRDP: Interface is already active %s", ifp->name); return; } if ((irdp_sock < 0) && ((irdp_sock = irdp_sock_init()) < 0)) { zlog_warn("IRDP: Cannot activate interface %s (cannot create " "IRDP socket)", 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", 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", 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 (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) { seed = ifc->address->u.prefix4.s_addr; break; } srandom(seed); timer = (random () % IRDP_DEFAULT_INTERVAL) + 1; irdp->AdvPrefList = list_new(); irdp->AdvPrefList->del = (void (*)(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_debug("IRDP: Init timer for %s set to %u", ifp->name, timer); irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer); } static 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", 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; } static 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", 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); } static 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", 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; struct listnode *node; char b1[INET_ADDRSTRLEN]; 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 (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv)) 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 (no_ip_irdp, no_ip_irdp_cmd, "no ip irdp", NO_STR 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 (no_ip_irdp_shutdown, no_ip_irdp_shutdown_cmd, "no ip irdp shutdown", NO_STR 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( (unsigned) 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 <= (unsigned) 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 needs to be fixed for negative ranages... * "ip irdp preference <-2147483648-2147483647>", * Be positive for now. :-) */ DEFUN (ip_irdp_preference, ip_irdp_preference_cmd, "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") { struct 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 (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv)) 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 (no_ip_irdp_address_preference, no_ip_irdp_address_preference_cmd, "no ip irdp address A.B.C.D preference <0-2147483647>", NO_STR IP_STR "Alter ICMP Router discovery preference this interface\n" "Removes IRDP non-default preference\n" "Select IRDP address\n" "Old preference level\n") { struct listnode *node, *nnode; struct in_addr ip; 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; for (ALL_LIST_ELEMENTS (irdp->AdvPrefList, node, nnode, adv)) { 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_init () { install_element (INTERFACE_NODE, &ip_irdp_broadcast_cmd); install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd); install_element (INTERFACE_NODE, &no_ip_irdp_cmd); install_element (INTERFACE_NODE, &ip_irdp_shutdown_cmd); install_element (INTERFACE_NODE, &no_ip_irdp_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, &no_ip_irdp_address_preference_cmd); 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 */ quagga-1.2.4/zebra/irdp_main.c000066400000000000000000000174641325323223500162100ustar00rootroot00000000000000/* * * 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 "sockopt.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 "privs.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 "checksum.h" #include "if.h" #include "sockunion.h" #include "log.h" /* GLOBAL VARS */ extern struct zebra_privs_t zserv_privs; /* Master of threads. */ extern struct zebra_t zebrad; struct thread *t_irdp_raw; /* Timer interval of irdp. */ int irdp_timer_interval = IRDP_DEFAULT_INTERVAL; int irdp_sock_init (void) { int ret, i; int save_errno; int sock; if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("irdp_sock_init: could not raise privs, %s", safe_strerror (errno) ); sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); save_errno = errno; if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("irdp_sock_init: could not lower privs, %s", safe_strerror (errno) ); if (sock < 0) { zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno)); return sock; }; i = 1; ret = setsockopt (sock, IPPROTO_IP, IP_TTL, (void *) &i, sizeof (i)); if (ret < 0) { zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno)); close(sock); return ret; }; ret = setsockopt_ifindex (AF_INET, sock, 1); if (ret < 0) { zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno)); close(sock); return ret; }; t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock); return sock; } static int get_pref(struct irdp_interface *irdp, struct prefix *p) { struct listnode *node; struct Adv *adv; /* Use default preference or use the override pref */ if( irdp->AdvPrefList == NULL ) return irdp->Preference; for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv)) if( p->u.prefix4.s_addr == adv->ip.s_addr ) return adv->pref; return irdp->Preference; } /* Make ICMP Router Advertisement Message. */ static 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; } static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; char buf[PREFIX_STRLEN]; 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_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d", ifp->name, prefix2str(p, buf, sizeof buf), irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime, get_pref(irdp, p)); send_packet (ifp, s, dst, p, ttl); } static 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); stream_free (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; struct listnode *node, *nnode; struct connected *ifc; irdp->flags &= ~IF_SOLICIT; if(ifp->connected) for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc)) { p = ifc->address; if (p->family != AF_INET) continue; 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_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer); irdp->t_advertise = thread_add_timer(zebrad.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; struct listnode *node, *nnode; 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 (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc)) { 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(zebrad.master, irdp_send_thread, ifp, timer); } void irdp_finish() { struct listnode *node, *nnode; struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; zlog_info("IRDP: Received shutdown notification."); for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { 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); } } } #endif /* HAVE_IRDP */ quagga-1.2.4/zebra/irdp_packet.c000066400000000000000000000212011325323223500165130ustar00rootroot00000000000000/* * * 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 "checksum.h" #include "sockunion.h" #include "log.h" #include "sockopt.h" /* GLOBAL VARS */ int irdp_sock = -1; extern struct zebra_t zebrad; extern struct thread *t_irdp_raw; static 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, iplen, datalen; 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 << 2; sockopt_iphdrincl_swab_systoh (ip); iplen = ip->ip_len; datalen = len - ip_hlen; src = ip->ip_src; if (len != iplen) { zlog_err ("IRDP: RX length doesn't match IP length"); return; } if (iplen < ICMP_MINLEN) { zlog_err ("IRDP: RX ICMP packet too short from %s\n", inet_ntoa (src)); return; } /* XXX: RAW doesn't receive link-layer, surely? ??? */ /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen + len of IP-header) 14+20 */ if (iplen > IRDP_RX_BUF-34) { zlog_err ("IRDP: RX ICMP packet too long from %s\n", inet_ntoa (src)); return; } icmp = (struct icmphdr *) (p+ip_hlen); /* check icmp checksum */ if (in_cksum (icmp, datalen) != icmp->checksum) { zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored", inet_ntoa (src)); return; } /* Handle just only IRDP */ if (!(icmp->type == ICMP_ROUTERADVERT || icmp->type == ICMP_ROUTERSOLICIT)) 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 (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST) && (irdp->flags & IF_BROADCAST)) || (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP && !(irdp->flags & IF_BROADCAST))) { 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_debug ("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)); } } static int irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex) { struct msghdr msg; struct iovec iov; char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )]; 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", safe_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; } *ifindex = getsockopt_ifindex (AF_INET, &msg); 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 = 0; int irdp_sock = THREAD_FD (r); t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock); ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF, &ifindex); if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret); ifp = if_lookup_by_index(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_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name); return 0; } if(irdp->flags & IF_DEBUG_PACKET) { int i; zlog_debug("IRDP: RX (idx %d) ", ifindex); for(i=0; i < ret; i++) zlog_debug( "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 + sizeof (struct ip)); /* Merge IP header with icmp packet */ assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip))); stream_get(icmp, s, stream_get_endp(s)); /* icmp->checksum is already calculated */ ip->ip_len = sizeof(struct ip) + stream_get_endp(s); on = 1; if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, (char *) &on, sizeof(on)) < 0) zlog_warn("sendto %s", safe_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", safe_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", safe_strerror (errno)); } memset(&sockdst,0,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; sockopt_iphdrincl_swab_htosys (ip); if (sendmsg(irdp_sock, msg, 0) < 0) { zlog_warn("sendto %s", safe_strerror (errno)); } /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */ } #endif /* HAVE_IRDP */ quagga-1.2.4/zebra/kernel_netlink.c000066400000000000000000000015241325323223500172400ustar00rootroot00000000000000/* 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. */ quagga-1.2.4/zebra/kernel_null.c000066400000000000000000000040171325323223500165460ustar00rootroot00000000000000/* NULL kernel methods for testing. */ /* * Copyright (C) 2006 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "zebra/zserv.h" #include "zebra/rt.h" #include "zebra/redistribute.h" #include "zebra/connected.h" #include "zebra/rib.h" int kernel_route_rib (struct prefix *a, struct rib *old, struct rib *new) { return 0; } int kernel_add_route (struct prefix_ipv4 *a, struct in_addr *b, int c, int d) { return 0; } int kernel_address_add_ipv4 (struct interface *a, struct connected *b) { zlog_debug ("%s", __func__); SET_FLAG (b->conf, ZEBRA_IFC_REAL); connected_add_ipv4 (a, 0, &b->address->u.prefix4, b->address->prefixlen, (b->destination ? &b->destination->u.prefix4 : NULL), NULL); return 0; } int kernel_address_delete_ipv4 (struct interface *a, struct connected *b) { zlog_debug ("%s", __func__); connected_delete_ipv4 (a, 0, &b->address->u.prefix4, b->address->prefixlen, (b->destination ? &b->destination->u.prefix4 : NULL)); return 0; } void kernel_init (struct zebra_vrf *zvrf) { return; } void kernel_terminate (struct zebra_vrf *zvrf) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak route_read = kernel_init #else void route_read (struct zebra_vrf *zvrf) { return; } #endif quagga-1.2.4/zebra/kernel_socket.c000066400000000000000000001200671325323223500170700ustar00rootroot00000000000000/* 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 #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 "privs.h" #include "vrf.h" #include "zebra/interface.h" #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/kernel_socket.h" #include "zebra/rib.h" extern struct zebra_privs_t zserv_privs; extern struct zebra_t zebrad; /* * Historically, the BSD routing socket has aligned data following a * struct sockaddr to sizeof(long), which was 4 bytes on some * platforms, and 8 bytes on others. NetBSD 6 changed the routing * socket to align to sizeof(uint64_t), which is 8 bytes. OS X * appears to align to sizeof(int), which is 4 bytes. * * Alignment of zero-sized sockaddrs is nonsensical, but historically * BSD defines RT_ROUNDUP(0) to be the alignment interval (rather than * 0). We follow this practice without questioning it, but it is a * bug if quagga calls ROUNDUP with 0. */ /* * Because of these varying conventions, the only sane approach is for * the header to define some flavor of ROUNDUP macro. */ #if defined(SA_SIZE) /* SAROUNDUP is the only thing we need, and SA_SIZE provides that */ #define SAROUNDUP(a) SA_SIZE(a) #else /* !SA_SIZE */ #if defined(RT_ROUNDUP) #define ROUNDUP(a) RT_ROUNDUP(a) #endif /* defined(RT_ROUNDUP) */ #if defined(SUNOS_5) /* Solaris has struct sockaddr_in[6] definitions at 16 / 32 bytes size, * so the whole concept doesn't really apply. */ #define ROUNDUP(a) (a) #endif /* * If ROUNDUP has not yet been defined in terms of platform-provided * defines, attempt to cope with heuristics. */ #if !defined(ROUNDUP) /* * It's a bug for a platform not to define rounding/alignment for * sockaddrs on the routing socket. This warning really is * intentional, to provoke filing bug reports with operating systems * that don't define RT_ROUNDUP or equivalent. */ #warning "net/route.h does not define RT_ROUNDUP; making unwarranted assumptions!" /* OS X (Xcode as of 2014-12) is known not to define RT_ROUNDUP */ #ifdef __APPLE__ #define ROUNDUP_TYPE int #else #define ROUNDUP_TYPE long #endif #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(ROUNDUP_TYPE) - 1))) : sizeof(ROUNDUP_TYPE)) #endif /* defined(ROUNDUP) */ /* * Given a pointer (sockaddr or void *), return the number of bytes * taken up by the sockaddr and any padding needed for alignment. */ #if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) #define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len) #elif defined(HAVE_IPV6) /* * One would hope all fixed-size structure definitions are aligned, * but round them up nonetheless. */ #define SAROUNDUP(X) \ (((struct sockaddr *)(X))->sa_family == AF_INET ? \ ROUNDUP(sizeof(struct sockaddr_in)):\ (((struct sockaddr *)(X))->sa_family == AF_INET6 ? \ ROUNDUP(sizeof(struct sockaddr_in6)) : \ (((struct sockaddr *)(X))->sa_family == AF_LINK ? \ ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr)))) #else /* HAVE_IPV6 */ #define SAROUNDUP(X) \ (((struct sockaddr *)(X))->sa_family == AF_INET ? \ ROUNDUP(sizeof(struct sockaddr_in)):\ (((struct sockaddr *)(X))->sa_family == AF_LINK ? \ ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr))) #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ #endif /* !SA_SIZE */ /* * We use a call to an inline function to copy (PNT) to (DEST) * 1. Calculating the length of the copy requires an #ifdef to determine * if sa_len is a field and can't be used directly inside a #define * 2. So the compiler doesn't complain when DEST is NULL, which is only true * when we are skipping the copy and incrementing to the next SA */ static inline void rta_copy (union sockunion *dest, caddr_t src) { int len; if (!dest) return; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN len = (((struct sockaddr *)src)->sa_len > sizeof (*dest)) ? sizeof (*dest) : ((struct sockaddr *)src)->sa_len ; #else len = (SAROUNDUP (src) > sizeof (*dest)) ? sizeof (*dest) : SAROUNDUP (src) ; #endif memcpy (dest, src, len); } #define RTA_ADDR_GET(DEST, RTA, RTMADDRS, PNT) \ if ((RTMADDRS) & (RTA)) \ { \ int len = SAROUNDUP ((PNT)); \ if (af_check (((struct sockaddr *)(PNT))->sa_family)) \ rta_copy((DEST), (PNT)); \ (PNT) += len; \ } #define RTA_ATTR_GET(DEST, RTA, RTMADDRS, PNT) \ if ((RTMADDRS) & (RTA)) \ { \ int len = SAROUNDUP ((PNT)); \ rta_copy((DEST), (PNT)); \ (PNT) += len; \ } #define RTA_NAME_GET(DEST, RTA, RTMADDRS, PNT, LEN) \ if ((RTMADDRS) & (RTA)) \ { \ u_char *pdest = (u_char *) (DEST); \ int len = SAROUNDUP ((PNT)); \ struct sockaddr_dl *sdl = (struct sockaddr_dl *)(PNT); \ if (IS_ZEBRA_DEBUG_KERNEL) \ zlog_debug ("%s: RTA_SDL_GET nlen %d, alen %d", \ __func__, sdl->sdl_nlen, sdl->sdl_alen); \ if ( ((DEST) != NULL) && (sdl->sdl_family == AF_LINK) \ && (sdl->sdl_nlen < IFNAMSIZ) && (sdl->sdl_nlen <= len) ) \ { \ memcpy (pdest, sdl->sdl_data, sdl->sdl_nlen); \ pdest[sdl->sdl_nlen] = '\0'; \ (LEN) = sdl->sdl_nlen; \ } \ (PNT) += len; \ } \ else \ { \ (LEN) = 0; \ } /* Routing socket message types. */ const 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"}, #ifdef OLDADD {RTM_OLDADD, "RTM_OLDADD"}, #endif /* RTM_OLDADD */ #ifdef RTM_OLDDEL {RTM_OLDDEL, "RTM_OLDDEL"}, #endif /* 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} }; static const 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 */ #ifdef RTF_CLONING {RTF_CLONING, "CLONING"}, #endif /* RTF_CLONING */ #ifdef RTF_XRESOLVE {RTF_XRESOLVE, "XRESOLVE"}, #endif /* RTF_XRESOLVE */ #ifdef RTF_LLINFO {RTF_LLINFO, "LLINFO"}, #endif /* RTF_LLINFO */ {RTF_STATIC, "STATIC"}, {RTF_BLACKHOLE, "BLACKHOLE"}, #ifdef RTF_PRIVATE {RTF_PRIVATE, "PRIVATE"}, #endif /* RTF_PRIVATE */ {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 */ #ifdef RTF_MULTIRT {RTF_MULTIRT, "MULTIRT"}, #endif /* RTF_MULTIRT */ #ifdef RTF_SETSRC {RTF_SETSRC, "SETSRC"}, #endif /* RTF_SETSRC */ {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 inline 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. */ static void rtm_flag_dump (int flag) { const 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_debug ("Kernel: %s", buf); } #ifdef RTM_IFANNOUNCE /* Interface adding function */ static int ifan_read (struct if_announcemsghdr *ifan) { struct interface *ifp; ifp = if_lookup_by_index (ifan->ifan_index); if (ifp) assert ( (ifp->ifindex == ifan->ifan_index) || (ifp->ifindex == IFINDEX_INTERNAL) ); if ( (ifp == NULL) || ((ifp->ifindex == IFINDEX_INTERNAL) && (ifan->ifan_what == IFAN_ARRIVAL)) ) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: creating interface for ifindex %d, name %s", __func__, ifan->ifan_index, ifan->ifan_name); /* Create Interface */ ifp = if_get_by_name_len(ifan->ifan_name, strnlen(ifan->ifan_name, sizeof(ifan->ifan_name))); ifp->ifindex = ifan->ifan_index; if_get_metric (ifp); if_add_update (ifp); } else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) if_delete_update (ifp); if_get_flags (ifp); if_get_mtu (ifp); if_get_metric (ifp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: interface %s index %d", __func__, ifan->ifan_name, ifan->ifan_index); return 0; } #endif /* RTM_IFANNOUNCE */ #ifdef HAVE_BSD_IFI_LINK_STATE /* BSD link detect translation */ static void bsd_linkdetect_translate (struct if_msghdr *ifm) { if ((ifm->ifm_data.ifi_link_state >= LINK_STATE_UP) || (ifm->ifm_data.ifi_link_state == LINK_STATE_UNKNOWN)) SET_FLAG(ifm->ifm_flags, IFF_RUNNING); else UNSET_FLAG(ifm->ifm_flags, IFF_RUNNING); } #endif /* HAVE_BSD_IFI_LINK_STATE */ static enum zebra_link_type sdl_to_zebra_link_type (unsigned int sdlt) { switch (sdlt) { case IFT_ETHER: return ZEBRA_LLT_ETHER; case IFT_X25: return ZEBRA_LLT_X25; case IFT_FDDI: return ZEBRA_LLT_FDDI; case IFT_PPP: return ZEBRA_LLT_PPP; case IFT_LOOP: return ZEBRA_LLT_LOOPBACK; case IFT_SLIP: return ZEBRA_LLT_SLIP; case IFT_ARCNET: return ZEBRA_LLT_ARCNET; case IFT_ATM: return ZEBRA_LLT_ATM; case IFT_LOCALTALK: return ZEBRA_LLT_LOCALTLK; case IFT_HIPPI: return ZEBRA_LLT_HIPPI; #ifdef IFT_IEEE1394 case IFT_IEEE1394: return ZEBRA_LLT_IEEE1394; #endif default: return ZEBRA_LLT_UNKNOWN; } } /* * Handle struct if_msghdr obtained from reading routing socket or * sysctl (from interface_list). There may or may not be sockaddrs * present after the header. */ int ifm_read (struct if_msghdr *ifm) { struct interface *ifp = NULL; struct sockaddr_dl *sdl; char ifname[IFNAMSIZ]; short ifnlen = 0; caddr_t cp; /* terminate ifname at head (for strnlen) and tail (for safety) */ ifname[IFNAMSIZ - 1] = '\0'; /* paranoia: sanity check structure */ if (ifm->ifm_msglen < sizeof(struct if_msghdr)) { zlog_err ("ifm_read: ifm->ifm_msglen %d too short\n", ifm->ifm_msglen); return -1; } /* * Check for a sockaddr_dl following the message. First, point to * where a socakddr might be if one follows the message. */ cp = (void *)(ifm + 1); #ifdef SUNOS_5 /* * XXX This behavior should be narrowed to only the kernel versions * for which the structures returned do not match the headers. * * if_msghdr_t on 64 bit kernels in Solaris 9 and earlier versions * is 12 bytes larger than the 32 bit version. */ if (((struct sockaddr *) cp)->sa_family == AF_UNSPEC) cp = cp + 12; #endif RTA_ADDR_GET (NULL, RTA_DST, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp); RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp); sdl = (struct sockaddr_dl *)cp; RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen); RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_BRD, ifm->ifm_addrs, cp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: sdl ifname %s", __func__, (ifnlen ? ifname : "(nil)")); /* * Look up on ifindex first, because ifindices are the primary handle for * interfaces across the user/kernel boundary, for most systems. (Some * messages, such as up/down status changes on NetBSD, do not include a * sockaddr_dl). */ if ( (ifp = if_lookup_by_index (ifm->ifm_index)) != NULL ) { /* we have an ifp, verify that the name matches as some systems, * eg Solaris, have a 1:many association of ifindex:ifname * if they dont match, we dont have the correct ifp and should * set it back to NULL to let next check do lookup by name */ if (ifnlen && (strncmp (ifp->name, ifname, IFNAMSIZ) != 0) ) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: ifp name %s doesn't match sdl name %s", __func__, ifp->name, ifname); ifp = NULL; } } /* * If we dont have an ifp, try looking up by name. Particularly as some * systems (Solaris) have a 1:many mapping of ifindex:ifname - the ifname * is therefore our unique handle to that interface. * * Interfaces specified in the configuration file for which the ifindex * has not been determined will have ifindex == IFINDEX_INTERNAL, and such * interfaces are found by this search, and then their ifindex values can * be filled in. */ if ( (ifp == NULL) && ifnlen) ifp = if_lookup_by_name (ifname); /* * If ifp still does not exist or has an invalid index (IFINDEX_INTERNAL), * create or fill in an interface. */ if ((ifp == NULL) || (ifp->ifindex == IFINDEX_INTERNAL)) { /* * To create or fill in an interface, a sockaddr_dl (via * RTA_IFP) is required. */ if (!ifnlen) { zlog_warn ("Interface index %d (new) missing ifname\n", ifm->ifm_index); return -1; } #ifndef RTM_IFANNOUNCE /* Down->Down interface should be ignored here. * See further comment below. */ if (!CHECK_FLAG (ifm->ifm_flags, IFF_UP)) return 0; #endif /* !RTM_IFANNOUNCE */ if (ifp == NULL) { /* Interface that zebra was not previously aware of, so create. */ ifp = if_create (ifname, ifnlen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: creating ifp for ifindex %d", __func__, ifm->ifm_index); } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: updated/created ifp, ifname %s, ifindex %d", __func__, ifp->name, ifp->ifindex); /* * Fill in newly created interface structure, or larval * structure with ifindex IFINDEX_INTERNAL. */ ifp->ifindex = ifm->ifm_index; #ifdef HAVE_BSD_IFI_LINK_STATE /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); #endif /* HAVE_BSD_IFI_LINK_STATE */ if_flags_update (ifp, ifm->ifm_flags); #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else if_get_mtu (ifp); #endif /* __bsdi__ */ if_get_metric (ifp); /* * XXX sockaddr_dl contents can be larger than the structure * definition. There are 2 big families here: * - BSD has sdl_len + sdl_data[16] + overruns sdl_data * we MUST use sdl_len here or we'll truncate data. * - Solaris has no sdl_len, but sdl_data[244] * presumably, it's not going to run past that, so sizeof() * is fine here. * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid */ ifp->ll_type = ZEBRA_LLT_UNKNOWN; ifp->hw_addr_len = 0; if (ifnlen) { #ifdef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN memcpy (&((struct zebra_if *)ifp->info)->sdl, sdl, sdl->sdl_len); #else memcpy (&((struct zebra_if *)ifp->info)->sdl, sdl, sizeof (struct sockaddr_dl)); #endif /* HAVE_STRUCT_SOCKADDR_DL_SDL_LEN */ ifp->ll_type = sdl_to_zebra_link_type (sdl->sdl_type); if (sdl->sdl_alen <= sizeof(ifp->hw_addr)) { memcpy (ifp->hw_addr, LLADDR(sdl), sdl->sdl_alen); ifp->hw_addr_len = sdl->sdl_alen; } } if_add_update (ifp); } else /* * Interface structure exists. Adjust stored flags from * notification. If interface has up->down or down->up * transition, call state change routines (to adjust routes, * notify routing daemons, etc.). (Other flag changes are stored * but apparently do not trigger action.) */ { if (ifp->ifindex != ifm->ifm_index) { zlog_warn ("%s: index mismatch, ifname %s, ifp index %d, " "ifm index %d", __func__, ifp->name, ifp->ifindex, ifm->ifm_index); return -1; } #ifdef HAVE_BSD_IFI_LINK_STATE /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); #endif /* HAVE_BSD_IFI_LINK_STATE */ /* update flags and handle operative->inoperative transition, if any */ if_flags_update (ifp, ifm->ifm_flags); #ifndef RTM_IFANNOUNCE if (!if_is_up (ifp)) { /* No RTM_IFANNOUNCE on this platform, so we can never * distinguish between ~IFF_UP and delete. We must presume * it has been deleted. * Eg, Solaris will not notify us of unplumb. * * XXX: Fixme - this should be runtime detected * So that a binary compiled on a system with IFANNOUNCE * will still behave correctly if run on a platform without */ if_delete_update (ifp); } #endif /* RTM_IFANNOUNCE */ if (if_is_up (ifp)) { #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else if_get_mtu (ifp); #endif /* __bsdi__ */ if_get_metric (ifp); } } #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data; #endif /* HAVE_NET_RT_IFLIST */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: interface %s index %d", __func__, ifp->name, ifp->ifindex); return 0; } /* Address read from struct ifa_msghdr. */ static void ifam_read_mesg (struct ifa_msghdr *ifm, union sockunion *addr, union sockunion *mask, union sockunion *brd, char *ifname, short *ifnlen) { caddr_t pnt, end; union sockunion dst; union sockunion gateway; pnt = (caddr_t)(ifm + 1); end = ((caddr_t)ifm) + ifm->ifam_msglen; /* Be sure structure is cleared */ memset (mask, 0, sizeof (union sockunion)); memset (addr, 0, sizeof (union sockunion)); memset (brd, 0, sizeof (union sockunion)); memset (&dst, 0, sizeof (union sockunion)); memset (&gateway, 0, sizeof (union sockunion)); /* We fetch each socket variable into sockunion. */ RTA_ADDR_GET (&dst, RTA_DST, ifm->ifam_addrs, pnt); RTA_ADDR_GET (&gateway, RTA_GATEWAY, ifm->ifam_addrs, pnt); RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt); RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt); RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen); RTA_ADDR_GET (addr, RTA_IFA, ifm->ifam_addrs, pnt); RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt); RTA_ADDR_GET (brd, RTA_BRD, ifm->ifam_addrs, pnt); if (IS_ZEBRA_DEBUG_KERNEL) { int family = sockunion_family(addr); switch (family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif { char buf[4][INET6_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, inet_ntop(family,&addr->sin.sin_addr, buf[0],sizeof(buf[0])), ip_masklen(mask->sin.sin_addr), inet_ntop(family,&brd->sin.sin_addr, buf[1],sizeof(buf[1])), inet_ntop(family,&dst.sin.sin_addr, buf[2],sizeof(buf[2])), inet_ntop(family,&gateway.sin.sin_addr, buf[3],sizeof(buf[3]))); } break; default: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs); break; } } /* 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 = NULL; union sockunion addr, mask, brd; char ifname[INTERFACE_NAMSIZ]; short ifnlen = 0; char isalias = 0; int flags = 0; ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0'; /* Allocate and read address information. */ ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen); if ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL) { zlog_warn ("%s: no interface for ifname %s, index %d", __func__, ifname, ifam->ifam_index); return -1; } if (ifnlen && strncmp (ifp->name, ifname, INTERFACE_NAMSIZ)) isalias = 1; /* N.B. The info in ifa_msghdr does not tell us whether the RTA_BRD field contains a broadcast address or a peer address, so we are forced to rely upon the interface type. */ if (if_is_pointopoint(ifp)) SET_FLAG(flags, ZEBRA_IFA_PEER); #if 0 /* it might seem cute to grab the interface metric here, however * we're processing an address update message, and so some systems * (e.g. FBSD) dont bother to fill in ifam_metric. Disabled, but left * in deliberately, as comment. */ ifp->metric = ifam->ifam_metric; #endif /* Add connected address. */ switch (sockunion_family (&addr)) { case AF_INET: if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr, (isalias ? ifname : NULL)); else connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr); 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, flags, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr, (isalias ? ifname : NULL)); else connected_delete_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr); break; #endif /* HAVE_IPV6 */ default: /* Unsupported family silently ignore... */ break; } /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); #ifdef SUNOS_5 /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. * See comments for SUNOS_5 in interface.c::if_flags_mangle. * * Here we take care of case where the real IFF_UP was previously * unset (as kept in struct zebra_if.primary_state) and the mangled * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned * to unset due to the lost non-primary address having DELADDR'd. * * we must delete the interface, because in between here and next * event for this interface-name the administrator could unplumb * and replumb the interface. */ if (!if_is_up (ifp)) if_delete_update (ifp); #endif /* SUNOS_5 */ return 0; } /* Interface function for reading kernel routing table information. */ static int rtm_read_mesg (struct rt_msghdr *rtm, union sockunion *dest, union sockunion *mask, union sockunion *gate, char *ifname, short *ifnlen) { 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); /* 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. */ RTA_ADDR_GET (dest, RTA_DST, rtm->rtm_addrs, pnt); RTA_ADDR_GET (gate, RTA_GATEWAY, rtm->rtm_addrs, pnt); RTA_ATTR_GET (mask, RTA_NETMASK, rtm->rtm_addrs, pnt); RTA_ADDR_GET (NULL, RTA_GENMASK, rtm->rtm_addrs, pnt); RTA_NAME_GET (ifname, RTA_IFP, rtm->rtm_addrs, pnt, *ifnlen); RTA_ADDR_GET (NULL, RTA_IFA, rtm->rtm_addrs, pnt); RTA_ADDR_GET (NULL, RTA_AUTHOR, rtm->rtm_addrs, pnt); RTA_ADDR_GET (NULL, RTA_BRD, rtm->rtm_addrs, pnt); /* 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; char ifname[INTERFACE_NAMSIZ + 1]; short ifnlen = 0; zebra_flags = 0; /* Read destination and netmask and gateway from rtm message structure. */ flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen); if (!(flags & RTF_DONE)) return; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: got rtm of type %d (%s)", __func__, rtm->rtm_type, lookup (rtm_type_str, rtm->rtm_type)); #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 || rtm->rtm_type == RTM_CHANGE) && ! (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); /* This is a reject or blackhole route */ if (flags & RTF_REJECT) SET_FLAG (zebra_flags, ZEBRA_FLAG_REJECT); if (flags & RTF_BLACKHOLE) SET_FLAG (zebra_flags, ZEBRA_FLAG_BLACKHOLE); 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); /* Catch self originated messages and match them against our current RIB. * At the same time, ignore unconfirmed messages, they should be tracked * by rtm_write() and kernel_rtm_ipv4(). */ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) { char buf[PREFIX_STRLEN], gate_buf[INET_ADDRSTRLEN]; int ret; if (! IS_ZEBRA_DEBUG_RIB) return; ret = rib_lookup_ipv4_route (&p, &gate, VRF_DEFAULT); prefix2str (&p, buf, sizeof(buf)); switch (rtm->rtm_type) { case RTM_ADD: case RTM_GET: case RTM_CHANGE: /* The kernel notifies us about a new route in FIB created by us. Do we have a correspondent entry in our RIB? */ switch (ret) { case ZEBRA_RIB_NOTFOUND: zlog_debug ("%s: %s %s: desync: RR isn't yet in RIB, while already in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: inet_ntop (AF_INET, &gate.sin.sin_addr, gate_buf, INET_ADDRSTRLEN); zlog_debug ("%s: %s %s: desync: RR is in RIB, but gate differs (ours is %s)", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, gate_buf); break; case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); rib_lookup_and_dump (&p); return; break; } break; case RTM_DELETE: /* The kernel notifies us about a route deleted by us. Do we still have it in the RIB? Do we have anything instead? */ switch (ret) { case ZEBRA_RIB_FOUND_EXACT: zlog_debug ("%s: %s %s: desync: RR is still in RIB, while already not in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: zlog_debug ("%s: %s %s: desync: RR is still in RIB, plus gate differs", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf); rib_lookup_and_dump (&p); return; break; } break; default: zlog_debug ("%s: %s: warning: loopback RTM of type %s received", __func__, buf, lookup (rtm_type_str, rtm->rtm_type)); } return; } /* Change, delete the old prefix, we have no further information * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, NULL, 0, VRF_DEFAULT, SAFI_UNICAST); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, NULL, 0, VRF_DEFAULT, 0, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, VRF_DEFAULT, SAFI_UNICAST); } #ifdef HAVE_IPV6 if (dest.sa.sa_family == AF_INET6) { /* One day we might have a debug section here like one in the * IPv4 case above. Just ignore own messages at the moment. */ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) return; struct prefix_ipv6 p; ifindex_t 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 */ /* CHANGE: delete the old prefix, we have no further information * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, NULL, 0, VRF_DEFAULT, SAFI_UNICAST); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, VRF_DEFAULT, RT_TABLE_MAIN, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, VRF_DEFAULT, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ } /* Interface function for the kernel routing table updates. Support * for RTM_CHANGE will be needed. * Exported only for rt_socket.c */ 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; /* 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; 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 || message == RTM_CHANGE)) msg.rtm.rtm_flags |= RTF_GATEWAY; /* When RTF_CLONING is unavailable on BSD, should we set some * other flag instead? */ #ifdef RTF_CLONING if (! gate && (message == RTM_ADD || message == RTM_CHANGE) && ifp && (ifp->flags & IFF_POINTOPOINT) == 0) msg.rtm.rtm_flags |= RTF_CLONING; #endif /* RTF_CLONING */ /* If no protocol specific gateway is specified, use link address for gateway. */ if (! gate) { if (!ifp) { char dest_buf[INET_ADDRSTRLEN] = "NULL", mask_buf[INET_ADDRSTRLEN] = "255.255.255.255"; if (dest) inet_ntop (AF_INET, &dest->sin.sin_addr, dest_buf, INET_ADDRSTRLEN); if (mask) inet_ntop (AF_INET, &mask->sin.sin_addr, mask_buf, INET_ADDRSTRLEN); zlog_warn ("%s: %s/%s: gate == NULL and no gateway found for ifindex %d", __func__, dest_buf, mask_buf, index); return -1; } gate = (union sockunion *) &((struct zebra_if *)ifp->info)->sdl; } if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; else if (message == RTM_ADD || message == RTM_CHANGE) 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; if (zebra_flags & ZEBRA_FLAG_REJECT) msg.rtm.rtm_flags |= RTF_REJECT; #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = SAROUNDUP (X); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += 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; if (errno == ESRCH) return ZEBRA_ERR_RTNOEXIST; zlog_warn ("%s: write : %s (%d)", __func__, safe_strerror (errno), errno); return ZEBRA_ERR_KERNEL; } return ZEBRA_ERR_NOERROR; } #include "thread.h" #include "zebra/zserv.h" /* For debug purpose. */ static void rtmsg_debug (struct rt_msghdr *rtm) { zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, lookup (rtm_type_str, rtm->rtm_type)); rtm_flag_dump (rtm->rtm_flags); zlog_debug ("Kernel: message seq %d", rtm->rtm_seq); zlog_debug ("Kernel: pid %lld, rtm_addrs 0x%x", (long long)rtm->rtm_pid, rtm->rtm_addrs); } /* 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. */ static int kernel_read (struct thread *thread) { int sock; int nbytes; struct rt_msghdr *rtm; /* * This must be big enough for any message the kernel might send. * Rather than determining how many sockaddrs of what size might be * in each particular message, just use RTAX_MAX of sockaddr_storage * for each. Note that the sockaddrs must be after each message * definition, or rather after whichever happens to be the largest, * since the buffer needs to be big enough for a message and the * sockaddrs together. */ union { /* Routing information. */ struct { struct rt_msghdr rtm; struct sockaddr_storage addr[RTAX_MAX]; } r; /* Interface information. */ struct { struct if_msghdr ifm; struct sockaddr_storage addr[RTAX_MAX]; } im; /* Interface address information. */ struct { struct ifa_msghdr ifa; struct sockaddr_storage addr[RTAX_MAX]; } ia; #ifdef RTM_IFANNOUNCE /* Interface arrival/departure */ struct { struct if_announcemsghdr ifan; struct sockaddr_storage 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", safe_strerror (errno)); return 0; } thread_add_read (zebrad.master, kernel_read, NULL, sock); if (IS_ZEBRA_DEBUG_KERNEL) rtmsg_debug (&buf.r.rtm); rtm = &buf.r.rtm; /* * Ensure that we didn't drop any data, so that processing routines * can assume they have the whole message. */ if (rtm->rtm_msglen != nbytes) { zlog_warn ("kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n", rtm->rtm_msglen, nbytes, rtm->rtm_type); return -1; } switch (rtm->rtm_type) { case RTM_ADD: case RTM_DELETE: case RTM_CHANGE: 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: if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Unprocessed RTM_type: %d", rtm->rtm_type); break; } return 0; } /* Make routing socket. */ static void routing_socket (struct zebra_vrf *zvrf) { if (zvrf->vrf_id != VRF_DEFAULT) return; if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("routing_socket: Can't raise privileges"); routing_sock = socket (AF_ROUTE, SOCK_RAW, 0); if (routing_sock < 0) { if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("routing_socket: Can't lower privileges"); zlog_warn ("Can't init kernel routing socket"); return; } /* XXX: Socket should be NONBLOCK, however as we currently * discard failed writes, this will lead to inconsistencies. * For now, socket must be blocking. */ /*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) zlog_warn ("Can't set O_NONBLOCK to routing socket");*/ if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("routing_socket: Can't lower privileges"); /* kernel_read needs rewrite. */ thread_add_read (zebrad.master, kernel_read, NULL, routing_sock); } /* Exported interface function. This function simply calls routing_socket (). */ void kernel_init (struct zebra_vrf *zvrf) { routing_socket (zvrf); } void kernel_terminate (struct zebra_vrf *zvrf) { return; } quagga-1.2.4/zebra/kernel_socket.h000066400000000000000000000023431325323223500170710ustar00rootroot00000000000000/* * Exported kernel_socket functions, exported only for convenience of * sysctl methods. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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_KERNEL_SOCKET_H #define __ZEBRA_KERNEL_SOCKET_H extern void rtm_read (struct rt_msghdr *); extern int ifam_read (struct ifa_msghdr *); extern int ifm_read (struct if_msghdr *); extern int rtm_write (int, union sockunion *, union sockunion *, union sockunion *, unsigned int, int, int); extern const struct message rtm_type_str[]; #endif /* __ZEBRA_KERNEL_SOCKET_H */ quagga-1.2.4/zebra/main.c000066400000000000000000000266401325323223500151660ustar00rootroot00000000000000/* 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 #include "getopt.h" #include "command.h" #include "thread.h" #include "filter.h" #include "memory.h" #include "prefix.h" #include "log.h" #include "plist.h" #include "privs.h" #include "sigevent.h" #include "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/router-id.h" #include "zebra/irdp.h" #include "zebra/rtadv.h" #include "zebra/zebra_fpm.h" /* Zebra instance */ struct zebra_t zebrad = { .rtm_table_default = 0, }; /* process id. */ pid_t pid; /* Pacify zclient.o in libzebra, which expects this variable. */ struct thread_master *master; /* Route retain mode flag. */ int retain_mode = 0; /* Don't delete kernel route. */ int keep_kernel_mode = 0; #ifdef HAVE_NETLINK /* Receive buffer size for netlink socket */ u_int32_t nl_rcvbufsize = 0; #endif /* HAVE_NETLINK */ /* Command line options. */ struct option longopts[] = { { "batch", no_argument, NULL, 'b'}, { "daemon", no_argument, NULL, 'd'}, { "keep_kernel", no_argument, NULL, 'k'}, { "fpm_format", required_argument, NULL, 'F'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "dryrun", no_argument, NULL, 'C'}, #ifdef HAVE_NETLINK { "nl-bufsize", required_argument, NULL, 's'}, #endif /* HAVE_NETLINK */ { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { 0 } }; zebra_capabilities_t _caps_p [] = { ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, }; /* zebra privileges to run with */ struct zebra_privs_t zserv_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), .cap_num_i = 0 }; /* Default configuration file path. */ char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE; /* Process ID saved for use by init system */ const 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"\ "-F, --fpm_format Set fpm format to 'netlink' or 'protobuf'\n"\ "-i, --pid_file Set process identifier file name\n"\ "-z, --socket Set path of zebra socket\n"\ "-k, --keep_kernel Don't delete old routes which installed by "\ "zebra.\n"\ "-C, --dryrun Check configuration for validity and exit\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"\ "-u, --user User to run as\n"\ "-g, --group Group to run as\n", progname); #ifdef HAVE_NETLINK printf ("-s, --nl-bufsize Set netlink receive buffer size\n"); #endif /* HAVE_NETLINK */ printf ("-v, --version Print program version\n"\ "-h, --help Display this help and exit\n"\ "\n"\ "Report bugs to %s\n", ZEBRA_BUG_ADDRESS); } exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog_info ("SIGHUP received"); /* Reload of config file. */ ; } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); if (!retain_mode) rib_close (); #ifdef HAVE_IRDP irdp_finish(); #endif exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } struct quagga_signal_t zebra_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* Callback upon creating a new VRF. */ static int zebra_vrf_new (vrf_id_t vrf_id, void **info) { struct zebra_vrf *zvrf = *info; if (! zvrf) { zvrf = zebra_vrf_alloc (vrf_id); *info = (void *)zvrf; router_id_init (zvrf); } return 0; } /* Callback upon enabling a VRF. */ static int zebra_vrf_enable (vrf_id_t vrf_id, void **info) { struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info); assert (zvrf); #if defined (HAVE_RTADV) rtadv_init (zvrf); #endif kernel_init (zvrf); interface_list (zvrf); route_read (zvrf); return 0; } /* Callback upon disabling a VRF. */ static int zebra_vrf_disable (vrf_id_t vrf_id, void **info) { struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info); struct listnode *list_node; struct interface *ifp; assert (zvrf); rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), list_node, ifp)) { int operative = if_is_operative (ifp); UNSET_FLAG (ifp->flags, IFF_UP); if (operative) if_down (ifp); } #if defined (HAVE_RTADV) rtadv_terminate (zvrf); #endif kernel_terminate (zvrf); list_delete_all_node (zvrf->rid_all_sorted_list); list_delete_all_node (zvrf->rid_lo_sorted_list); return 0; } /* Zebra VRF initialization. */ static void zebra_vrf_init (void) { vrf_add_hook (VRF_NEW_HOOK, zebra_vrf_new); vrf_add_hook (VRF_ENABLE_HOOK, zebra_vrf_enable); vrf_add_hook (VRF_DISABLE_HOOK, zebra_vrf_disable); vrf_init (); } /* Main startup routine. */ int main (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = ZEBRA_VTY_PORT; int dryrun = 0; int batch_mode = 0; int daemon_mode = 0; char *config_file = NULL; char *progname; char *zserv_path = NULL; char *fpm_format = NULL; /* Set umask before anything for security */ umask (0027); /* preserve my name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog (progname, ZLOG_ZEBRA, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); while (1) { int opt; #ifdef HAVE_NETLINK opt = getopt_long (argc, argv, "bdkf:F:i:z:hA:P:ru:g:vs:C", longopts, 0); #else opt = getopt_long (argc, argv, "bdkf:F:i:z:hA:P:ru:g:vC", longopts, 0); #endif /* HAVE_NETLINK */ 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 'C': dryrun = 1; break; case 'f': config_file = optarg; break; case 'F': fpm_format = optarg; break; case 'A': vty_addr = optarg; break; case 'i': pid_file = optarg; break; case 'z': zserv_path = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure, and zebra not listening on zebra port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = ZEBRA_VTY_PORT; break; case 'r': retain_mode = 1; break; #ifdef HAVE_NETLINK case 's': nl_rcvbufsize = atoi (optarg); break; #endif /* HAVE_NETLINK */ case 'u': zserv_privs.user = optarg; break; case 'g': zserv_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Make master thread emulator. */ zebrad.master = thread_master_create (); /* privs initialise */ zprivs_init (&zserv_privs); /* Vty related initialize. */ signal_init (zebrad.master, array_size(zebra_signals), zebra_signals); cmd_init (1); vty_init (zebrad.master); memory_init (); /* Zebra related initialize. */ zebra_init (); rib_init (); zebra_if_init (); zebra_debug_init (); router_id_cmd_init (); zebra_vty_init (); access_list_init (); prefix_list_init (); #if defined (HAVE_RTADV) rtadv_cmd_init (); #endif #ifdef HAVE_IRDP irdp_init(); #endif /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ /* Initialize VRF module, and make kernel routing socket. */ zebra_vrf_init (); #ifdef HAVE_SNMP zebra_snmp_init (); #endif /* HAVE_SNMP */ #ifdef HAVE_FPM zfpm_init (zebrad.master, 1, 0, fpm_format); #else zfpm_init (zebrad.master, 0, 0, fpm_format); #endif /* Process the configuration file. Among other configuration * directives we can meet those installing static routes. Such * requests will not be executed immediately, but queued in * zebra->ribq structure until we enter the main execution loop. * The notifications from kernel will show originating PID equal * to that after daemon() completes (if ever called). */ vty_read_config (config_file, config_default); /* Don't start execution if we are in dry-run mode */ if (dryrun) return(0); /* Count up events for interfaces */ if_startup_count_up (); /* Clean up rib. */ rib_weed_tables (); /* Exit when zebra is working in batch mode. */ if (batch_mode) exit (0); /* Daemonize. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("Zebra daemon failed: %s", strerror(errno)); exit (1); } /* Output pid of zebra. */ pid_output (pid_file); /* After we have successfully acquired the pidfile, we can be sure * about being the only copy of zebra process, which is submitting * changes to the FIB. * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, * we have to have route_read() called before. */ if (! keep_kernel_mode) rib_sweep_route (); /* Needed for BSD routing socket. */ pid = getpid (); /* This must be done only after locking pidfile (bug #403). */ zebra_zserv_socket_init (zserv_path); /* Make vty server socket. */ vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH); /* Print banner. */ zlog_notice ("Zebra %s starting: vty@%d", QUAGGA_VERSION, vty_port); thread_main (zebrad.master); return 0; } quagga-1.2.4/zebra/misc_null.c000066400000000000000000000032471325323223500162250ustar00rootroot00000000000000/* * Copyright (C) 2006 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "zebra/rtadv.h" #include "zebra/irdp.h" #include "zebra/interface.h" #include "zebra/zebra_fpm.h" #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA void _quagga_noop (void); void _quagga_noop (void) { return; } #pragma weak rtadv_config_write = _quagga_noop #pragma weak irdp_config_write = _quagga_noop #ifdef HAVE_NET_RT_IFLIST #pragma weak ifstat_update_sysctl = _quagga_noop #endif #ifdef HAVE_PROC_NET_DEV #pragma weak ifstat_update_proc = _quagga_noop #endif #else void rtadv_config_write (struct vty *vty, struct interface *ifp) { return; } void irdp_config_write (struct vty *vty, struct interface *ifp) { return; } #ifdef HAVE_PROC_NET_DEV void ifstat_update_proc (void) { return; } #endif #ifdef HAVE_NET_RT_IFLIST void ifstat_update_sysctl (void) { return; } #endif #endif void zfpm_trigger_update (struct route_node *rn, const char *reason) { return; } quagga-1.2.4/zebra/redistribute.c000066400000000000000000000272131325323223500167440ustar00rootroot00000000000000/* 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 "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/router-id.h" /* master zebra server structure */ extern struct zebra_t zebrad; 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) || IPV4_LINKLOCAL(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; } static void zebra_redistribute_default (struct zserv *client, vrf_id_t vrf_id) { 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 = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (table) { rn = route_node_lookup (table, (struct prefix *)&p); if (rn) { RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->distance != DISTANCE_INFINITY) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, 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 = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (table) { rn = route_node_lookup (table, (struct prefix *)&p6); if (rn) { RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->distance != DISTANCE_INFINITY) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); route_unlock_node (rn); } } #endif /* HAVE_IPV6 */ } /* Redistribute routes. */ static void zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id) { struct rib *newrib; struct route_table *table; struct route_node *rn; table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("%s: checking: selected=%d, type=%d, distance=%d, zebra_check_addr=%d", __func__, CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED), newrib->type, newrib->distance, zebra_check_addr (&rn->p)); if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->type == type && newrib->distance != DISTANCE_INFINITY && zebra_check_addr (&rn->p)) { client->redist_v4_add_cnt++; zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); } } #ifdef HAVE_IPV6 table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->type == type && newrib->distance != DISTANCE_INFINITY && zebra_check_addr (&rn->p)) { client->redist_v6_add_cnt++; zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); } #endif /* HAVE_IPV6 */ } void redistribute_add (struct prefix *p, struct rib *rib, struct rib *rib_old) { struct listnode *node, *nnode; struct zserv *client; for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { if ((is_default (p) && vrf_bitmap_check (client->redist_default, rib->vrf_id)) || vrf_bitmap_check (client->redist[rib->type], rib->vrf_id)) { if (p->family == AF_INET) { client->redist_v4_add_cnt++; zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); } if (p->family == AF_INET6) { client->redist_v6_add_cnt++; zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); } } else if (rib_old && vrf_bitmap_check (client->redist[rib_old->type], rib_old->vrf_id)) { /* redistribute_add has implicit withdraw semantics, so there * may be an old route already redistributed that is being updated. * * However, if the new route is of a type that is /not/ redistributed * to the client, then we must ensure the old route is explicitly * withdrawn. */ if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib_old); if (p->family == AF_INET6) zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, rib_old); } } } void redistribute_delete (struct prefix *p, struct rib *rib) { struct listnode *node, *nnode; struct zserv *client; /* Add DISTANCE_INFINITY check. */ if (rib->distance == DISTANCE_INFINITY) return; for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { if ((is_default (p) && vrf_bitmap_check (client->redist_default, rib->vrf_id)) || vrf_bitmap_check (client->redist[rib->type], rib->vrf_id)) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, rib); #endif /* HAVE_IPV6 */ } } } void zebra_redistribute_add (int command, struct zserv *client, int length, vrf_id_t vrf_id) { int type; type = stream_getc (client->ibuf); if (type == 0 || type >= ZEBRA_ROUTE_MAX) return; if (! vrf_bitmap_check (client->redist[type], vrf_id)) { vrf_bitmap_set (client->redist[type], vrf_id); zebra_redistribute (client, type, vrf_id); } } void zebra_redistribute_delete (int command, struct zserv *client, int length, vrf_id_t vrf_id) { int type; type = stream_getc (client->ibuf); if (type == 0 || type >= ZEBRA_ROUTE_MAX) return; vrf_bitmap_unset (client->redist[type], vrf_id); } void zebra_redistribute_default_add (int command, struct zserv *client, int length, vrf_id_t vrf_id) { vrf_bitmap_set (client->redist_default, vrf_id); zebra_redistribute_default (client, vrf_id); } void zebra_redistribute_default_delete (int command, struct zserv *client, int length, vrf_id_t vrf_id) { vrf_bitmap_unset (client->redist_default, vrf_id); } /* Interface up information. */ void zebra_interface_up_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) { zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); zsend_interface_link_params (client, ifp); } } /* Interface down information. */ void zebra_interface_down_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp); } } /* Interface information update. */ void zebra_interface_add_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADD %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) { client->ifadd_cnt++; zsend_interface_add (client, ifp); zsend_interface_link_params (client, ifp); } } void zebra_interface_delete_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DELETE %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) { client->ifdel_cnt++; zsend_interface_delete (client, ifp); } } /* Interface address addition. */ void zebra_interface_address_add_update (struct interface *ifp, struct connected *ifc) { struct listnode *node, *nnode; struct zserv *client; struct prefix *p; if (IS_ZEBRA_DEBUG_EVENT) { char buf[PREFIX_STRLEN]; p = ifc->address; zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s on %s", prefix2str (p, buf, sizeof(buf)), ifc->ifp->name); } if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) zlog_warn("WARNING: advertising address to clients that is not yet usable."); router_id_add_address(ifc); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) { client->connected_rt_add_cnt++; zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc); } } /* Interface address deletion. */ void zebra_interface_address_delete_update (struct interface *ifp, struct connected *ifc) { struct listnode *node, *nnode; struct zserv *client; struct prefix *p; if (IS_ZEBRA_DEBUG_EVENT) { char buf[PREFIX_STRLEN]; p = ifc->address; zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s on %s", prefix2str (p, buf, sizeof(buf)), ifc->ifp->name); } router_id_del_address(ifc); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) { client->connected_rt_del_cnt++; zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); } } /* Interface parameters update */ void zebra_interface_parameters_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) zsend_interface_link_params (client, ifp); } quagga-1.2.4/zebra/redistribute.h000066400000000000000000000040001325323223500167360ustar00rootroot00000000000000/* * 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" #include "zserv.h" extern void zebra_redistribute_add (int, struct zserv *, int, vrf_id_t); extern void zebra_redistribute_delete (int, struct zserv *, int, vrf_id_t); extern void zebra_redistribute_default_add (int, struct zserv *, int, vrf_id_t); extern void zebra_redistribute_default_delete (int, struct zserv *, int, vrf_id_t); extern void redistribute_add (struct prefix *, struct rib *new, struct rib *old); extern void redistribute_delete (struct prefix *, struct rib *); extern void zebra_interface_up_update (struct interface *); extern void zebra_interface_down_update (struct interface *); extern void zebra_interface_add_update (struct interface *); extern void zebra_interface_delete_update (struct interface *); extern void zebra_interface_address_add_update (struct interface *, struct connected *); extern void zebra_interface_address_delete_update (struct interface *, struct connected *c); extern void zebra_interface_parameters_update (struct interface *); extern int zebra_check_addr (struct prefix *); extern int is_default (struct prefix *); #endif /* _ZEBRA_REDISTRIBUTE_H */ quagga-1.2.4/zebra/redistribute_null.c000066400000000000000000000054061325323223500177760ustar00rootroot00000000000000/* * Copyright (C) 2006 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" void zebra_redistribute_add (int a, struct zserv *b, int c, vrf_id_t vrf_id) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak zebra_redistribute_delete = zebra_redistribute_add #pragma weak zebra_redistribute_default_add = zebra_redistribute_add #pragma weak zebra_redistribute_default_delete = zebra_redistribute_add #else void zebra_redistribute_delete (int a, struct zserv *b, int c, vrf_id_t vrf_id) { return; } void zebra_redistribute_default_add (int a, struct zserv *b, int c, vrf_id_t vrf_id) { return; } void zebra_redistribute_default_delete (int a, struct zserv *b, int c, vrf_id_t vrf_id) { return; } #endif void redistribute_add (struct prefix *a, struct rib *b, struct rib *c) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak redistribute_delete = redistribute_add #else void redistribute_delete (struct prefix *a, struct rib *b) { return; } #endif void zebra_interface_up_update (struct interface *a) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak zebra_interface_down_update = zebra_interface_up_update #pragma weak zebra_interface_add_update = zebra_interface_up_update #pragma weak zebra_interface_delete_update = zebra_interface_up_update #else void zebra_interface_down_update (struct interface *a) { return; } void zebra_interface_add_update (struct interface *a) { return; } void zebra_interface_delete_update (struct interface *a) { return; } #endif void zebra_interface_address_add_update (struct interface *a, struct connected *b) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak zebra_interface_address_delete_update = zebra_interface_address_add_update #else void zebra_interface_address_delete_update (struct interface *a, struct connected *b) { return; } #endif /* Interface parameters update */ void zebra_interface_parameters_update (struct interface *ifp) { return; }; quagga-1.2.4/zebra/rib.h000066400000000000000000000366401325323223500150240ustar00rootroot00000000000000/* * 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 #include "zebra.h" #include "linklist.h" #include "prefix.h" #include "table.h" #include "queue.h" #include "nexthop.h" #define DISTANCE_INFINITY 255 struct rib { /* Link list. */ struct rib *next; struct rib *prev; /* Nexthop structure */ struct nexthop *nexthop; /* Refrence count. */ unsigned long refcnt; /* Tag */ route_tag_t tag; /* Uptime. */ time_t uptime; /* Type fo this route. */ int type; /* VRF identifier. */ vrf_id_t vrf_id; /* Which routing table */ int table; /* Metric */ u_int32_t metric; /* MTU */ u_int32_t mtu; u_int32_t nexthop_mtu; /* Distance. */ u_char distance; /* Flags of this route. * This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed * to clients via Zserv */ u_char flags; /* RIB internal status */ u_char status; #define RIB_ENTRY_REMOVED (1 << 0) #define RIB_ENTRY_CHANGED (1 << 1) #define RIB_ENTRY_SELECTED_FIB (1 << 2) /* Nexthop information. */ u_char nexthop_num; u_char nexthop_active_num; u_char nexthop_fib_num; }; /* meta-queue structure: * sub-queue 0: connected, kernel * sub-queue 1: static * sub-queue 2: RIP, RIPng, OSPF, OSPF6, IS-IS * sub-queue 3: iBGP, eBGP * sub-queue 4: any other origin (if any) */ #define MQ_SIZE 5 struct meta_queue { struct list *subq[MQ_SIZE]; u_int32_t size; /* sum of lengths of all subqueues */ }; /* * Structure that represents a single destination (prefix). */ typedef struct rib_dest_t_ { /* * Back pointer to the route node for this destination. This helps * us get to the prefix that this structure is for. */ struct route_node *rnode; /* * Doubly-linked list of routes for this prefix. */ struct rib *routes; /* * Flags, see below. */ u_int32_t flags; /* * Linkage to put dest on the FPM processing queue. */ TAILQ_ENTRY(rib_dest_t_) fpm_q_entries; } rib_dest_t; #define RIB_ROUTE_QUEUED(x) (1 << (x)) /* * The maximum qindex that can be used. */ #define ZEBRA_MAX_QINDEX (MQ_SIZE - 1) /* * This flag indicates that a given prefix has been 'advertised' to * the FPM to be installed in the forwarding plane. */ #define RIB_DEST_SENT_TO_FPM (1 << (ZEBRA_MAX_QINDEX + 1)) /* * This flag is set when we need to send an update to the FPM about a * dest. */ #define RIB_DEST_UPDATE_FPM (1 << (ZEBRA_MAX_QINDEX + 2)) /* * Macro to iterate over each route for a destination (prefix). */ #define RIB_DEST_FOREACH_ROUTE(dest, rib) \ for ((rib) = (dest) ? (dest)->routes : NULL; (rib); (rib) = (rib)->next) /* * Same as above, but allows the current node to be unlinked. */ #define RIB_DEST_FOREACH_ROUTE_SAFE(dest, rib, next) \ for ((rib) = (dest) ? (dest)->routes : NULL; \ (rib) && ((next) = (rib)->next, 1); \ (rib) = (next)) #define RNODE_FOREACH_RIB(rn, rib) \ RIB_DEST_FOREACH_ROUTE (rib_dest_from_rnode (rn), rib) #define RNODE_FOREACH_RIB_SAFE(rn, rib, next) \ RIB_DEST_FOREACH_ROUTE_SAFE (rib_dest_from_rnode (rn), rib, next) /* Static route information. */ struct static_route { /* For linked list. */ struct static_route *prev; struct static_route *next; /* VRF identifier. */ vrf_id_t vrf_id; /* Administrative distance. */ u_char distance; /* Tag */ route_tag_t tag; /* 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 #define STATIC_IPV6_GATEWAY 4 #define STATIC_IPV6_GATEWAY_IFNAME 5 #define STATIC_IPV6_IFNAME 6 /* Nexthop value. */ union g_addr addr; char *ifname; /* bit flags */ u_char flags; /* see ZEBRA_FLAG_REJECT ZEBRA_FLAG_BLACKHOLE */ }; /* The following for loop allows to iterate over the nexthop * structure of routes. * * We have to maintain quite a bit of state: * * nexthop: The pointer to the current nexthop, either in the * top-level chain or in the resolved chain of ni. * tnexthop: The pointer to the current nexthop in the top-level * nexthop chain. * recursing: Information if nh currently is in the top-level chain * (0) or in a resolved chain (1). * * Initialization: Set `nexthop' and `tnexthop' to the head of the * top-level chain. As nexthop is in the top level chain, set recursing * to 0. * * Iteration check: Check that the `nexthop' pointer is not NULL. * * Iteration step: This is the tricky part. Check if `nexthop' has * NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' is in * the top level chain and has at least one nexthop attached to * `nexthop->resolved'. As we want to descend into `nexthop->resolved', * set `recursing' to 1 and set `nexthop' to `nexthop->resolved'. * `tnexthop' is left alone in that case so we can remember which nexthop * in the top level chain we are currently handling. * * If NEXTHOP_FLAG_RECURSIVE is not set, `nexthop' will progress in its * current chain. If we are recursing, `nexthop' will be set to * `nexthop->next' and `tnexthop' will be left alone. If we are not * recursing, both `tnexthop' and `nexthop' will be set to `nexthop->next' * as we are progressing in the top level chain. * If we encounter `nexthop->next == NULL', we will clear the `recursing' * flag as we arived either at the end of the resolved chain or at the end * of the top level chain. In both cases, we set `tnexthop' and `nexthop' * to `tnexthop->next', progressing to the next position in the top-level * chain and possibly to its end marked by NULL. */ #define ALL_NEXTHOPS_RO(head, nexthop, tnexthop, recursing) \ (tnexthop) = (nexthop) = (head), (recursing) = 0; \ (nexthop); \ (nexthop) = CHECK_FLAG((nexthop)->flags, NEXTHOP_FLAG_RECURSIVE) \ ? (((recursing) = 1), (nexthop)->resolved) \ : ((nexthop)->next ? ((recursing) ? (nexthop)->next \ : ((tnexthop) = (nexthop)->next)) \ : (((recursing) = 0),((tnexthop) = (tnexthop)->next))) /* Structure holding nexthop & VRF identifier, * used for applying the route-map. */ struct nexthop_vrfid { struct nexthop *nexthop; vrf_id_t vrf_id; }; #if defined (HAVE_RTADV) /* Structure which hold status of router advertisement. */ struct rtadv { int sock; int adv_if_count; int adv_msec_if_count; struct thread *ra_read; struct thread *ra_timer; }; #endif /* HAVE_RTADV */ #ifdef HAVE_NETLINK /* Socket interface to kernel */ struct nlsock { int sock; int seq; struct sockaddr_nl snl; const char *name; }; #endif /* Routing table instance. */ struct zebra_vrf { /* Identifier. */ vrf_id_t vrf_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]; #ifdef HAVE_NETLINK struct nlsock netlink; /* kernel messages */ struct nlsock netlink_cmd; /* command channel */ struct thread *t_netlink; #endif /* 2nd pointer type used primarily to quell a warning on * ALL_LIST_ELEMENTS_RO */ struct list _rid_all_sorted_list; struct list _rid_lo_sorted_list; struct list *rid_all_sorted_list; struct list *rid_lo_sorted_list; struct prefix rid_user_assigned; #if defined (HAVE_RTADV) struct rtadv rtadv; #endif /* HAVE_RTADV */ /* Recursive Nexthop table */ struct route_table *rnh_table[AFI_MAX]; }; /* * rib_table_info_t * * Structure that is hung off of a route_table that holds information about * the table. */ typedef struct rib_table_info_t_ { /* * Back pointer to zebra_vrf. */ struct zebra_vrf *zvrf; afi_t afi; safi_t safi; } rib_table_info_t; typedef enum { RIB_TABLES_ITER_S_INIT, RIB_TABLES_ITER_S_ITERATING, RIB_TABLES_ITER_S_DONE } rib_tables_iter_state_t; /* * Structure that holds state for iterating over all tables in the * Routing Information Base. */ typedef struct rib_tables_iter_t_ { vrf_id_t vrf_id; int afi_safi_ix; rib_tables_iter_state_t state; } rib_tables_iter_t; /* RPF lookup behaviour */ enum multicast_mode { MCAST_NO_CONFIG = 0, /* MIX_MRIB_FIRST, but no show in config write */ MCAST_MRIB_ONLY, /* MRIB only */ MCAST_URIB_ONLY, /* URIB only */ MCAST_MIX_MRIB_FIRST, /* MRIB, if nothing at all then URIB */ MCAST_MIX_DISTANCE, /* MRIB & URIB, lower distance wins */ MCAST_MIX_PFXLEN, /* MRIB & URIB, longer prefix wins */ /* on equal value, MRIB wins for last 2 */ }; extern void multicast_mode_ipv4_set (enum multicast_mode mode); extern enum multicast_mode multicast_mode_ipv4_get (void); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern struct nexthop *rib_nexthop_ifindex_add (struct rib *, ifindex_t); extern struct nexthop *rib_nexthop_ifname_add (struct rib *, char *); extern struct nexthop *rib_nexthop_blackhole_add (struct rib *); extern struct nexthop *rib_nexthop_ipv4_add (struct rib *, struct in_addr *, struct in_addr *); extern struct nexthop *rib_nexthop_ipv4_ifindex_add (struct rib *, struct in_addr *, struct in_addr *, ifindex_t); extern void rib_nexthop_add (struct rib *rib, struct nexthop *nexthop); extern int nexthop_has_fib_child(struct nexthop *); extern void rib_lookup_and_dump (struct prefix_ipv4 *); #define rib_dump(prefix ,rib) _rib_dump(__func__, prefix, rib) extern void _rib_dump (const char *, union prefix46constptr, const struct rib *); extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *, vrf_id_t); #define ZEBRA_RIB_LOOKUP_ERROR -1 #define ZEBRA_RIB_FOUND_EXACT 0 #define ZEBRA_RIB_FOUND_NOGATE 1 #define ZEBRA_RIB_FOUND_CONNECTED 2 #define ZEBRA_RIB_NOTFOUND 3 extern struct nexthop *rib_nexthop_ipv6_add (struct rib *, struct in6_addr *); extern struct nexthop *rib_nexthop_ipv6_ifindex_add (struct rib *, struct in6_addr *, ifindex_t); extern struct zebra_vrf *zebra_vrf_lookup (vrf_id_t vrf_id); extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t); extern struct route_table *zebra_vrf_table (afi_t, safi_t, vrf_id_t); extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t); /* NOTE: * All rib_add_ipv[46]* functions will not just add prefix into RIB, but * also implicitly withdraw equal prefix of same type. */ extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, ifindex_t ifindex, vrf_id_t vrf_id, int table_id, u_int32_t, u_int32_t, u_char, safi_t); extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *, safi_t); extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, ifindex_t ifindex, vrf_id_t, safi_t safi); extern struct rib *rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, struct route_node **rn_out, vrf_id_t); extern struct rib *rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, vrf_id_t); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *, vrf_id_t); extern void rib_update (vrf_id_t); extern void rib_weed_tables (void); extern void rib_sweep_route (void); extern void rib_close_table (struct route_table *); extern void rib_close (void); extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto); extern int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, const char *ifname, u_char flags, route_tag_t, u_char distance, vrf_id_t vrf_id); extern int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, const char *ifname, route_tag_t tag, u_char distance, vrf_id_t vrf_id); extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id, int table_id, u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi); extern int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id, safi_t safi); extern struct rib *rib_lookup_ipv6 (struct in6_addr *, vrf_id_t); extern struct rib *rib_match_ipv6 (struct in6_addr *, vrf_id_t); extern struct route_table *rib_table_ipv6; extern int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char flags, route_tag_t, u_char distance, vrf_id_t vrf_id); extern int rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t); extern int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, route_tag_t, u_char distance, vrf_id_t vrf_id); extern int rib_gc_dest (struct route_node *rn); extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter); /* * Inline functions. */ /* * rib_table_info */ static inline rib_table_info_t * rib_table_info (struct route_table *table) { return (rib_table_info_t *) table->info; } /* * rib_dest_from_rnode */ static inline rib_dest_t * rib_dest_from_rnode (struct route_node *rn) { return (rib_dest_t *) rn->info; } /* * rnode_to_ribs * * Returns a pointer to the list of routes corresponding to the given * route_node. */ static inline struct rib * rnode_to_ribs (struct route_node *rn) { rib_dest_t *dest; dest = rib_dest_from_rnode (rn); if (!dest) return NULL; return dest->routes; } /* * rib_dest_prefix */ static inline struct prefix * rib_dest_prefix (rib_dest_t *dest) { return &dest->rnode->p; } /* * rib_dest_af * * Returns the address family that the destination is for. */ static inline u_char rib_dest_af (rib_dest_t *dest) { return dest->rnode->p.family; } /* * rib_dest_table */ static inline struct route_table * rib_dest_table (rib_dest_t *dest) { return dest->rnode->table; } /* * rib_dest_vrf */ static inline struct zebra_vrf * rib_dest_vrf (rib_dest_t *dest) { return rib_table_info (rib_dest_table (dest))->zvrf; } /* * rib_tables_iter_init */ static inline void rib_tables_iter_init (rib_tables_iter_t *iter) { memset (iter, 0, sizeof (*iter)); iter->state = RIB_TABLES_ITER_S_INIT; } /* * rib_tables_iter_started * * Returns TRUE if this iterator has started iterating over the set of * tables. */ static inline int rib_tables_iter_started (rib_tables_iter_t *iter) { return iter->state != RIB_TABLES_ITER_S_INIT; } /* * rib_tables_iter_cleanup */ static inline void rib_tables_iter_cleanup (rib_tables_iter_t *iter) { iter->state = RIB_TABLES_ITER_S_DONE; } #endif /*_ZEBRA_RIB_H */ quagga-1.2.4/zebra/router-id.c000066400000000000000000000170251325323223500161510ustar00rootroot00000000000000/* * Router ID for zebra daemon. * * Copyright (C) 2004 James R. Leu * * This file is part of Quagga routing suite. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "stream.h" #include "command.h" #include "memory.h" #include "ioctl.h" #include "connected.h" #include "network.h" #include "log.h" #include "table.h" #include "rib.h" #include "vrf.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" /* master zebra server structure */ extern struct zebra_t zebrad; static struct connected * router_id_find_node (struct list *l, struct connected *ifc) { struct listnode *node; struct connected *c; for (ALL_LIST_ELEMENTS_RO (l, node, c)) if (prefix_same (ifc->address, c->address)) return c; return NULL; } static int router_id_bad_address (struct connected *ifc) { if (ifc->address->family != AF_INET) return 1; /* non-redistributable addresses shouldn't be used for RIDs either */ if (!zebra_check_addr (ifc->address)) return 1; return 0; } void router_id_get (struct prefix *p, vrf_id_t vrf_id) { struct listnode *node; struct connected *c; struct zebra_vrf *zvrf = vrf_info_get (vrf_id); p->u.prefix4.s_addr = 0; p->family = AF_INET; p->prefixlen = 32; if (zvrf->rid_user_assigned.u.prefix4.s_addr) p->u.prefix4.s_addr = zvrf->rid_user_assigned.u.prefix4.s_addr; else if (!list_isempty (zvrf->rid_lo_sorted_list)) { node = listtail (zvrf->rid_lo_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } else if (!list_isempty (zvrf->rid_all_sorted_list)) { node = listtail (zvrf->rid_all_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } } static void router_id_set (struct prefix *p, vrf_id_t vrf_id) { struct prefix p2; struct listnode *node; struct zserv *client; struct zebra_vrf *zvrf; if (p->u.prefix4.s_addr == 0) /* unset */ { zvrf = vrf_info_lookup (vrf_id); if (! zvrf) return; } else /* set */ zvrf = vrf_info_get (vrf_id); zvrf->rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr; router_id_get (&p2, vrf_id); for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &p2, vrf_id); } void router_id_add_address (struct connected *ifc) { struct list *l = NULL; struct listnode *node; struct prefix before; struct prefix after; struct zserv *client; struct zebra_vrf *zvrf = vrf_info_get (ifc->ifp->vrf_id); if (router_id_bad_address (ifc)) return; router_id_get (&before, zvrf->vrf_id); if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) l = zvrf->rid_lo_sorted_list; else l = zvrf->rid_all_sorted_list; if (!router_id_find_node (l, ifc)) listnode_add_sort (l, ifc); router_id_get (&after, zvrf->vrf_id); if (prefix_same (&before, &after)) return; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &after, zvrf->vrf_id); } void router_id_del_address (struct connected *ifc) { struct connected *c; struct list *l; struct prefix after; struct prefix before; struct listnode *node; struct zserv *client; struct zebra_vrf *zvrf = vrf_info_get (ifc->ifp->vrf_id); if (router_id_bad_address (ifc)) return; router_id_get (&before, zvrf->vrf_id); if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) l = zvrf->rid_lo_sorted_list; else l = zvrf->rid_all_sorted_list; if ((c = router_id_find_node (l, ifc))) listnode_delete (l, c); router_id_get (&after, zvrf->vrf_id); if (prefix_same (&before, &after)) return; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &after, zvrf->vrf_id); } void router_id_write (struct vty *vty) { struct zebra_vrf *zvrf; vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) if (zvrf->rid_user_assigned.u.prefix4.s_addr) { if (zvrf->vrf_id == VRF_DEFAULT) vty_out (vty, "router-id %s%s", inet_ntoa (zvrf->rid_user_assigned.u.prefix4), VTY_NEWLINE); else vty_out (vty, "router-id %s vrf %u%s", inet_ntoa (zvrf->rid_user_assigned.u.prefix4), zvrf->vrf_id, VTY_NEWLINE); } } DEFUN (router_id, router_id_cmd, "router-id A.B.C.D", "Manually set the router-id\n" "IP address to use for router-id\n") { struct prefix rid; vrf_id_t vrf_id = VRF_DEFAULT; rid.u.prefix4.s_addr = inet_addr (argv[0]); if (!rid.u.prefix4.s_addr) return CMD_WARNING; rid.prefixlen = 32; rid.family = AF_INET; if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); router_id_set (&rid, vrf_id); return CMD_SUCCESS; } ALIAS (router_id, router_id_vrf_cmd, "router-id A.B.C.D " VRF_CMD_STR, "Manually set the router-id\n" "IP address to use for router-id\n" VRF_CMD_HELP_STR) DEFUN (no_router_id, no_router_id_cmd, "no router-id", NO_STR "Remove the manually configured router-id\n") { struct prefix rid; vrf_id_t vrf_id = VRF_DEFAULT; rid.u.prefix4.s_addr = 0; rid.prefixlen = 0; rid.family = AF_INET; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); router_id_set (&rid, vrf_id); return CMD_SUCCESS; } ALIAS (no_router_id, no_router_id_vrf_cmd, "no router-id " VRF_CMD_STR, NO_STR "Remove the manually configured router-id\n" VRF_CMD_HELP_STR) static int router_id_cmp (void *a, void *b) { const struct connected *ifa = (const struct connected *)a; const struct connected *ifb = (const struct connected *)b; return IPV4_ADDR_CMP(&ifa->address->u.prefix4.s_addr,&ifb->address->u.prefix4.s_addr); } void router_id_cmd_init (void) { install_element (CONFIG_NODE, &router_id_cmd); install_element (CONFIG_NODE, &no_router_id_cmd); install_element (CONFIG_NODE, &router_id_vrf_cmd); install_element (CONFIG_NODE, &no_router_id_vrf_cmd); } void router_id_init (struct zebra_vrf *zvrf) { zvrf->rid_all_sorted_list = &zvrf->_rid_all_sorted_list; zvrf->rid_lo_sorted_list = &zvrf->_rid_lo_sorted_list; memset (zvrf->rid_all_sorted_list, 0, sizeof (zvrf->_rid_all_sorted_list)); memset (zvrf->rid_lo_sorted_list, 0, sizeof (zvrf->_rid_lo_sorted_list)); memset (&zvrf->rid_user_assigned, 0, sizeof (zvrf->rid_user_assigned)); zvrf->rid_all_sorted_list->cmp = router_id_cmp; zvrf->rid_lo_sorted_list->cmp = router_id_cmp; zvrf->rid_user_assigned.family = AF_INET; zvrf->rid_user_assigned.prefixlen = 32; } quagga-1.2.4/zebra/router-id.h000066400000000000000000000024031325323223500161500ustar00rootroot00000000000000/* * Router ID for zebra daemon. * * Copyright (C) 2004 James R. Leu * * This file is part of Quagga routing suite. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 _ROUTER_ID_H_ #define _ROUTER_ID_H_ #include #include "memory.h" #include "prefix.h" #include "zclient.h" #include "if.h" extern void router_id_add_address(struct connected *); extern void router_id_del_address(struct connected *); extern void router_id_init(struct zebra_vrf *); extern void router_id_cmd_init(void); extern void router_id_write(struct vty *); extern void router_id_get(struct prefix *, vrf_id_t); #endif quagga-1.2.4/zebra/rt.h000066400000000000000000000024101325323223500146610ustar00rootroot00000000000000/* * 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 #include "prefix.h" #include "if.h" #include "zebra/rib.h" extern int kernel_route_rib (struct prefix *, struct rib *, struct rib *); extern int kernel_add_route (struct prefix_ipv4 *, struct in_addr *, int, int); extern int kernel_address_add_ipv4 (struct interface *, struct connected *); extern int kernel_address_delete_ipv4 (struct interface *, struct connected *); #endif /* _ZEBRA_RT_H */ quagga-1.2.4/zebra/rt_netlink.c000066400000000000000000001640141325323223500164110ustar00rootroot00000000000000/* 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 #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 "memory.h" #include "rib.h" #include "thread.h" #include "privs.h" #include "vrf.h" #include "nexthop.h" #include "zebra/zserv.h" #include "zebra/rt.h" #include "zebra/redistribute.h" #include "zebra/interface.h" #include "zebra/debug.h" #include "rt_netlink.h" static const 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 struct zebra_t zebrad; extern struct zebra_privs_t zserv_privs; extern u_int32_t nl_rcvbufsize; static struct { char *p; size_t size; } nl_rcvbuf; /* Note: on netlink systems, there should be a 1-to-1 mapping between interface names and ifindex values. */ static void set_ifindex(struct interface *ifp, ifindex_t ifi_index) { struct interface *oifp; if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp)) { if (ifi_index == IFINDEX_INTERNAL) zlog_err("Netlink is setting interface %s ifindex to reserved " "internal value %u", ifp->name, ifi_index); else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("interface index %d was renamed from %s to %s", ifi_index, oifp->name, ifp->name); if (if_is_up(oifp)) zlog_err("interface rename detected on up interface: index %d " "was renamed from %s to %s, results are uncertain!", ifi_index, oifp->name, ifp->name); if_delete_update(oifp); } } ifp->ifindex = ifi_index; } #ifndef SO_RCVBUFFORCE #define SO_RCVBUFFORCE (33) #endif static int netlink_recvbuf (struct nlsock *nl, uint32_t newsize) { u_int32_t oldsize; socklen_t newlen = sizeof(newsize); socklen_t oldlen = sizeof(oldsize); int ret; ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name, safe_strerror (errno)); return -1; } /* Try force option (linux >= 2.6.14) and fall back to normal set */ if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("routing_socket: Can't raise privileges"); ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize, sizeof(nl_rcvbufsize)); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("routing_socket: Can't lower privileges"); if (ret < 0) ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize, sizeof(nl_rcvbufsize)); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name, safe_strerror (errno)); return -1; } ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name, safe_strerror (errno)); return -1; } zlog (NULL, LOG_INFO, "Setting netlink socket receive buffer size: %u -> %u", oldsize, newsize); return 0; } /* Make socket for Linux netlink interface. */ static int netlink_socket (struct nlsock *nl, unsigned long groups, vrf_id_t vrf_id) { int ret; struct sockaddr_nl snl; int sock; int namelen; int save_errno; if (zserv_privs.change (ZPRIVS_RAISE)) { zlog (NULL, LOG_ERR, "Can't raise privileges"); return -1; } sock = vrf_socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, vrf_id); if (sock < 0) { zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name, safe_strerror (errno)); 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); save_errno = errno; if (zserv_privs.change (ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s", nl->name, snl.nl_groups, safe_strerror (save_errno)); close (sock); return -1; } /* multiple netlink sockets will have different nl_pid */ namelen = sizeof snl; ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen); if (ret < 0 || namelen != sizeof snl) { zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name, safe_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; int save_errno; 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; memset (&req, 0, sizeof req); 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 = nl->snl.nl_pid; req.nlh.nlmsg_seq = ++nl->seq; req.g.rtgen_family = family; /* linux appears to check capabilities on every message * have to raise caps for every message sent */ if (zserv_privs.change (ZPRIVS_RAISE)) { zlog (NULL, LOG_ERR, "Can't raise privileges"); return -1; } ret = sendto (nl->sock, (void *) &req, sizeof req, 0, (struct sockaddr *) &snl, sizeof snl); save_errno = errno; if (zserv_privs.change (ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); if (ret < 0) { zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, safe_strerror (save_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 *, vrf_id_t), struct nlsock *nl, struct zebra_vrf *zvrf) { int status; int ret = 0; int error; while (1) { struct iovec iov = { .iov_base = nl_rcvbuf.p, .iov_len = nl_rcvbuf.size, }; struct sockaddr_nl snl; struct msghdr msg = { .msg_name = (void *) &snl, .msg_namelen = sizeof snl, .msg_iov = &iov, .msg_iovlen = 1 }; 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: %s", nl->name, safe_strerror(errno)); 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 *) nl_rcvbuf.p; NLMSG_OK (h, (unsigned int) 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); int errnum = err->error; int msg_type = err->msg.nlmsg_type; /* If the error field is zero, then this is an ACK */ if (err->error == 0) { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u", __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; } /* Deal with errors that occur because of races in link handling */ if (nl == &zvrf->netlink_cmd && ((msg_type == RTM_DELROUTE && (-errnum == ENODEV || -errnum == ESRCH)) || (msg_type == RTM_NEWROUTE && -errnum == EEXIST))) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u", nl->name, safe_strerror (-errnum), lookup (nlmsg_str, msg_type), msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); return 0; } zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u", nl->name, safe_strerror (-errnum), lookup (nlmsg_str, msg_type), msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); return -1; } /* OK we got netlink message. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u", nl->name, lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type, h->nlmsg_seq, h->nlmsg_pid); /* skip unsolicited messages originating from command socket * linux sets the originators port-id for {NEW|DEL}ADDR messages, * so this has to be checked here. */ if (nl != &zvrf->netlink_cmd && h->nlmsg_pid == zvrf->netlink_cmd.snl.nl_pid && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_parse_info: %s packet comes from %s", zvrf->netlink_cmd.name, nl->name); continue; } error = (*filter) (&snl, h, zvrf->vrf_id); 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); zlog (NULL, LOG_ERR, "Must restart with larger --nl-bufsize value!"); 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); } } /* Utility function to parse hardware link-layer address and update ifp */ static void netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp) { int i; 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; } } } static enum zebra_link_type netlink_to_zebra_link_type (unsigned int hwt) { switch (hwt) { case ARPHRD_ETHER: return ZEBRA_LLT_ETHER; case ARPHRD_EETHER: return ZEBRA_LLT_EETHER; case ARPHRD_AX25: return ZEBRA_LLT_AX25; case ARPHRD_PRONET: return ZEBRA_LLT_PRONET; case ARPHRD_IEEE802: return ZEBRA_LLT_IEEE802; case ARPHRD_ARCNET: return ZEBRA_LLT_ARCNET; case ARPHRD_APPLETLK: return ZEBRA_LLT_APPLETLK; case ARPHRD_DLCI: return ZEBRA_LLT_DLCI; case ARPHRD_ATM: return ZEBRA_LLT_ATM; case ARPHRD_METRICOM: return ZEBRA_LLT_METRICOM; case ARPHRD_IEEE1394: return ZEBRA_LLT_IEEE1394; case ARPHRD_EUI64: return ZEBRA_LLT_EUI64; case ARPHRD_INFINIBAND: return ZEBRA_LLT_INFINIBAND; case ARPHRD_SLIP: return ZEBRA_LLT_SLIP; case ARPHRD_CSLIP: return ZEBRA_LLT_CSLIP; case ARPHRD_SLIP6: return ZEBRA_LLT_SLIP6; case ARPHRD_CSLIP6: return ZEBRA_LLT_CSLIP6; case ARPHRD_RSRVD: return ZEBRA_LLT_RSRVD; case ARPHRD_ADAPT: return ZEBRA_LLT_ADAPT; case ARPHRD_ROSE: return ZEBRA_LLT_ROSE; case ARPHRD_X25: return ZEBRA_LLT_X25; case ARPHRD_PPP: return ZEBRA_LLT_PPP; case ARPHRD_CISCO: return ZEBRA_LLT_CHDLC; case ARPHRD_LAPB: return ZEBRA_LLT_LAPB; case ARPHRD_RAWHDLC: return ZEBRA_LLT_RAWHDLC; case ARPHRD_TUNNEL: return ZEBRA_LLT_IPIP; case ARPHRD_TUNNEL6: return ZEBRA_LLT_IPIP6; case ARPHRD_FRAD: return ZEBRA_LLT_FRAD; case ARPHRD_SKIP: return ZEBRA_LLT_SKIP; case ARPHRD_LOOPBACK: return ZEBRA_LLT_LOOPBACK; case ARPHRD_LOCALTLK: return ZEBRA_LLT_LOCALTLK; case ARPHRD_FDDI: return ZEBRA_LLT_FDDI; case ARPHRD_SIT: return ZEBRA_LLT_SIT; case ARPHRD_IPDDP: return ZEBRA_LLT_IPDDP; case ARPHRD_IPGRE: return ZEBRA_LLT_IPGRE; case ARPHRD_PIMREG: return ZEBRA_LLT_PIMREG; case ARPHRD_HIPPI: return ZEBRA_LLT_HIPPI; case ARPHRD_ECONET: return ZEBRA_LLT_ECONET; case ARPHRD_IRDA: return ZEBRA_LLT_IRDA; case ARPHRD_FCPP: return ZEBRA_LLT_FCPP; case ARPHRD_FCAL: return ZEBRA_LLT_FCAL; case ARPHRD_FCPL: return ZEBRA_LLT_FCPL; case ARPHRD_FCFABRIC: return ZEBRA_LLT_FCFABRIC; case ARPHRD_IEEE802_TR: return ZEBRA_LLT_IEEE802_TR; case ARPHRD_IEEE80211: return ZEBRA_LLT_IEEE80211; case ARPHRD_IEEE802154: return ZEBRA_LLT_IEEE802154; #ifdef ARPHRD_IP6GRE case ARPHRD_IP6GRE: return ZEBRA_LLT_IP6GRE; #endif #ifdef ARPHRD_IEEE802154_PHY case ARPHRD_IEEE802154_PHY: return ZEBRA_LLT_IEEE802154_PHY; #endif default: return ZEBRA_LLT_UNKNOWN; } } /* Called from interface_lookup_netlink(). This function is only used during bootstrap. */ static int netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h, vrf_id_t vrf_id) { 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) 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); #ifdef IFLA_WIRELESS /* check for wireless messages to ignore */ if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__); return 0; } #endif /* IFLA_WIRELESS */ if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *) RTA_DATA (tb[IFLA_IFNAME]); /* Add interface. */ ifp = if_get_by_name_vrf (name, vrf_id); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 0; /* Hardware type and address. */ ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type); netlink_interface_update_hw_addr (tb, ifp); if_add_update (ifp); return 0; } /* Lookup interface IPv4/IPv6 address. */ static int netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h, vrf_id_t vrf_id) { int len; struct ifaddrmsg *ifa; struct rtattr *tb[IFA_MAX + 1]; struct interface *ifp; void *addr; void *broad; 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_vrf (ifa->ifa_index, vrf_id); if (ifp == NULL) { zlog_err ("netlink_interface_addr can't find interface by index %d vrf %u", ifa->ifa_index, vrf_id); return -1; } if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ { char buf[BUFSIZ]; zlog_debug ("netlink_interface_addr %s %s vrf %u:", lookup (nlmsg_str, h->nlmsg_type), ifp->name, vrf_id); if (tb[IFA_LOCAL]) zlog_debug (" IFA_LOCAL %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_ADDRESS]) zlog_debug (" IFA_ADDRESS %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_BROADCAST]) zlog_debug (" IFA_BROADCAST %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL]))) zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL])); if (tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]); zlog_debug (" IFA_CACHEINFO pref %d, valid %d", ci->ifa_prefered, ci->ifa_valid); } } /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */ if (tb[IFA_LOCAL] == NULL) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; /* local interface address */ addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); /* is there a peer address? */ if (tb[IFA_ADDRESS] && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS]))) { broad = RTA_DATA(tb[IFA_ADDRESS]); SET_FLAG (flags, ZEBRA_IFA_PEER); } else /* seeking a broadcast address */ broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL); /* addr is primary key, SOL if we don't have one */ if (addr == NULL) { zlog_debug ("%s: NULL address", __func__); return -1; } /* 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); } #ifdef HAVE_IPV6 if (ifa->ifa_family == AF_INET6) { if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv6 (ifp, flags, (struct in6_addr *) addr, ifa->ifa_prefixlen, (struct in6_addr *) broad, label); 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. */ static int netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h, vrf_id_t vrf_id) { int len; struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; u_char flags = 0; char anyaddr[16] = { 0 }; int index; int table; u_int32_t mtu = 0; void *dest; void *gate; void *src; 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 != zebrad.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; src = 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_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); if (tb[RTA_METRICS]) { struct rtattr *mxrta[RTAX_MAX+1]; memset (mxrta, 0, sizeof mxrta); netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), RTA_PAYLOAD(tb[RTA_METRICS])); if (mxrta[RTAX_MTU]) mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); } 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 (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, vrf_id, table, 0, mtu, 0, SAFI_UNICAST); else { /* This is a multipath route */ struct rib *rib; struct rtnexthop *rtnh = (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); rib->type = ZEBRA_ROUTE_KERNEL; rib->distance = 0; rib->flags = flags; rib->metric = 0; rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); for (;;) { if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) break; index = rtnh->rtnh_ifindex; gate = 0; if (rtnh->rtnh_len > sizeof (*rtnh)) { memset (tb, 0, sizeof (tb)); netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), rtnh->rtnh_len - sizeof (*rtnh)); if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); } if (gate) { if (index) rib_nexthop_ipv4_ifindex_add (rib, gate, src, index); else rib_nexthop_ipv4_add (rib, gate, src); } else rib_nexthop_ifindex_add (rib, index); len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } if (rib->nexthop_num == 0) XFREE (MTYPE_RIB, rib); else rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST); } } #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, vrf_id, table, 0, mtu, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ return 0; } static const 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. */ static int netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, vrf_id_t vrf_id) { int len; struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; u_char zebra_flags = 0; char anyaddr[16] = { 0 }; int index; int table; u_int32_t mtu = 0; void *dest; void *gate; void *src; 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 vrf %u\n", h->nlmsg_type, vrf_id); return 0; } /* Connected route. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s %s %s proto %s vrf %u", 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), vrf_id); if (rtm->rtm_type != RTN_UNICAST) { return 0; } table = rtm->rtm_table; if (table != RT_TABLE_MAIN && table != zebrad.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_protocol == RTPROT_ZEBRA) SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE); if (rtm->rtm_src_len != 0) { zlog_warn ("netlink_route_change(): no src len, vrf %u", vrf_id); return 0; } index = 0; dest = NULL; gate = NULL; src = 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 (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); if (h->nlmsg_type == RTM_NEWROUTE) { if (tb[RTA_METRICS]) { struct rtattr *mxrta[RTAX_MAX+1]; memset (mxrta, 0, sizeof mxrta); netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), RTA_PAYLOAD(tb[RTA_METRICS])); if (mxrta[RTAX_MTU]) mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); } } 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) { char buf[PREFIX_STRLEN]; zlog_debug ("%s %s vrf %u", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", prefix2str (&p, buf, sizeof(buf)), vrf_id); } if (h->nlmsg_type == RTM_NEWROUTE) { if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id, table, 0, mtu, 0, SAFI_UNICAST); else { /* This is a multipath route */ struct rib *rib; struct rtnexthop *rtnh = (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); rib->type = ZEBRA_ROUTE_KERNEL; rib->distance = 0; rib->flags = 0; rib->metric = 0; rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); for (;;) { if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) break; index = rtnh->rtnh_ifindex; gate = 0; if (rtnh->rtnh_len > sizeof (*rtnh)) { memset (tb, 0, sizeof (tb)); netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), rtnh->rtnh_len - sizeof (*rtnh)); if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); } if (gate) { if (index) rib_nexthop_ipv4_ifindex_add (rib, gate, src, index); else rib_nexthop_ipv4_add (rib, gate, src); } else rib_nexthop_ifindex_add (rib, index); len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } if (rib->nexthop_num == 0) XFREE (MTYPE_RIB, rib); else rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST); } } else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate, index, vrf_id, SAFI_UNICAST); } #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; if (IS_ZEBRA_DEBUG_KERNEL) { char buf[PREFIX_STRLEN]; zlog_debug ("%s %s vrf %u", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", prefix2str (&p, buf, sizeof(buf)), vrf_id); } if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table, 0, mtu, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate, index, vrf_id, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ return 0; } static int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h, vrf_id_t vrf_id) { 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 vrf %u\n", h->nlmsg_type, vrf_id); 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); #ifdef IFLA_WIRELESS /* check for wireless messages to ignore */ if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: ignoring IFLA_WIRELESS message, vrf %u", __func__, vrf_id); return 0; } #endif /* IFLA_WIRELESS */ 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_vrf (name, vrf_id); if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { if (ifp == NULL) ifp = if_get_by_name_vrf (name, vrf_id); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 0; netlink_interface_update_hw_addr (tb, ifp); /* If new link is added. */ if_add_update (ifp); } else { /* Interface status change. */ set_ifindex(ifp, ifi->ifi_index); ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 0; netlink_interface_update_hw_addr (tb, ifp); if (if_is_operative (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (!if_is_operative (ifp)) if_down (ifp); else /* Must notify client daemons of new interface status. */ zebra_interface_up_update (ifp); } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (if_is_operative (ifp)) if_up (ifp); } } } else { /* RTM_DELLINK. */ ifp = if_lookup_by_name_vrf (name, vrf_id); if (ifp == NULL) { zlog_warn ("interface %s vrf %u is deleted but can't find", name, vrf_id); return 0; } if_delete_update (ifp); } return 0; } static int netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h, vrf_id_t vrf_id) { /* JF: Ignore messages that aren't from the kernel */ if ( snl->nl_pid != 0 ) { zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid ); return 0; } switch (h->nlmsg_type) { case RTM_NEWROUTE: return netlink_route_change (snl, h, vrf_id); break; case RTM_DELROUTE: return netlink_route_change (snl, h, vrf_id); break; case RTM_NEWLINK: return netlink_link_change (snl, h, vrf_id); break; case RTM_DELLINK: return netlink_link_change (snl, h, vrf_id); break; case RTM_NEWADDR: return netlink_interface_addr (snl, h, vrf_id); break; case RTM_DELADDR: return netlink_interface_addr (snl, h, vrf_id); break; default: zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type, vrf_id); break; } return 0; } /* Interface lookup by netlink socket. */ int interface_lookup_netlink (struct zebra_vrf *zvrf) { int ret; /* Get interface information. */ ret = netlink_request (AF_PACKET, RTM_GETLINK, &zvrf->netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; /* Get IPv4 address of the interfaces. */ ret = netlink_request (AF_INET, RTM_GETADDR, &zvrf->netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; #ifdef HAVE_IPV6 /* Get IPv6 address of the interfaces. */ ret = netlink_request (AF_INET6, RTM_GETADDR, &zvrf->netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf); 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 (struct zebra_vrf *zvrf) { int ret; /* Get IPv4 routing table. */ ret = netlink_request (AF_INET, RTM_GETROUTE, &zvrf->netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; #ifdef HAVE_IPV6 /* Get IPv6 routing table. */ ret = netlink_request (AF_INET6, RTM_GETROUTE, &zvrf->netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf); if (ret < 0) return ret; #endif /* HAVE_IPV6 */ return 0; } /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ int addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, size_t alen) { size_t 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, size_t maxlen, int type, void *data, size_t alen) { size_t 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, size_t maxlen, int type, int data) { size_t 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, vrf_id_t vrf_id) { zlog_warn ("netlink_talk: ignoring message type 0x%04x vrf %u", h->nlmsg_type, vrf_id); return 0; } /* sendmsg() to netlink socket then recvmsg(). */ static int netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_vrf *zvrf) { int status; struct sockaddr_nl snl; struct iovec iov = { .iov_base = (void *) n, .iov_len = n->nlmsg_len }; struct msghdr msg = { .msg_name = (void *) &snl, .msg_namelen = sizeof snl, .msg_iov = &iov, .msg_iovlen = 1, }; int save_errno; memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; n->nlmsg_seq = ++nl->seq; /* Request an acknowledgement by setting NLM_F_ACK */ n->nlmsg_flags |= NLM_F_ACK; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name, lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type, n->nlmsg_seq); /* Send message to netlink interface. */ if (zserv_privs.change (ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); status = sendmsg (nl->sock, &msg, 0); save_errno = errno; if (zserv_privs.change (ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); if (status < 0) { zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s", safe_strerror (save_errno)); return -1; } /* * Get reply from netlink socket. * The reply should either be an acknowlegement or an error. */ return netlink_parse_info (netlink_talk_filter, nl, zvrf); } /* This function takes a nexthop as argument and adds * the appropriate netlink attributes to an existing * netlink message. * * @param routedesc: Human readable description of route type * (direct/recursive, single-/multipath) * @param bytelen: Length of addresses in bytes. * @param nexthop: Nexthop information * @param nlmsg: nlmsghdr structure to fill in. * @param req_size: The size allocated for the message. */ static void _netlink_route_build_singlepath( const char *routedesc, int bytelen, struct nexthop *nexthop, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, size_t req_size) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtmsg->rtm_flags |= RTNH_F_ONLINK; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); if (nexthop->src.ipv4.s_addr) addattr_l (nlmsg, req_size, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", routedesc, inet_ntoa (nexthop->gate.ipv4), nexthop->ifindex); } #ifdef HAVE_IPV6 if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", routedesc, inet6_ntoa (nexthop->gate.ipv6), nexthop->ifindex); } #endif /* HAVE_IPV6 */ if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); if (nexthop->src.ipv4.s_addr) addattr_l (nlmsg, req_size, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); } if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) { addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); } } /* This function takes a nexthop as argument and * appends to the given rtattr/rtnexthop pair the * representation of the nexthop. If the nexthop * defines a preferred source, the src parameter * will be modified to point to that src, otherwise * it will be kept unmodified. * * @param routedesc: Human readable description of route type * (direct/recursive, single-/multipath) * @param bytelen: Length of addresses in bytes. * @param nexthop: Nexthop information * @param rta: rtnetlink attribute structure * @param rtnh: pointer to an rtnetlink nexthop structure * @param src: pointer pointing to a location where * the prefsrc should be stored. */ static void _netlink_route_build_multipath( const char *routedesc, int bytelen, struct nexthop *nexthop, struct rtattr *rta, struct rtnexthop *rtnh, union g_addr **src ) { 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_ONLINK)) rtnh->rtnh_flags |= RTNH_F_ONLINK; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; if (nexthop->src.ipv4.s_addr) *src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", routedesc, inet_ntoa (nexthop->gate.ipv4), nexthop->ifindex); } #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, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", routedesc, inet6_ntoa (nexthop->gate.ipv6), nexthop->ifindex); } #endif /* HAVE_IPV6 */ /* ifindex */ if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) { rtnh->rtnh_ifindex = nexthop->ifindex; if (nexthop->src.ipv4.s_addr) *src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { rtnh->rtnh_ifindex = nexthop->ifindex; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); } else { rtnh->rtnh_ifindex = 0; } } /* Log debug information for netlink_route_multipath * if debug logging is enabled. * * @param cmd: Netlink command which is to be processed * @param p: Prefix for which the change is due * @param nexthop: Nexthop which is currently processed * @param routedesc: Semantic annotation for nexthop * (recursive, multipath, etc.) * @param family: Address family which the change concerns */ static void _netlink_route_debug( int cmd, struct prefix *p, struct nexthop *nexthop, const char *routedesc, int family, struct zebra_vrf *zvrf) { if (IS_ZEBRA_DEBUG_KERNEL) { char buf[PREFIX_STRLEN]; zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s", routedesc, lookup (nlmsg_str, cmd), prefix2str (p, buf, sizeof(buf)), zvrf->vrf_id, nexthop_type_to_str (nexthop->type)); } } /* Routing table change via netlink interface. */ static int netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib) { int bytelen; struct sockaddr_nl snl; struct nexthop *nexthop = NULL, *tnexthop; int recursing; int nexthop_num; int discard; int family = PREFIX_FAMILY(p); const char *routedesc; struct { struct nlmsghdr n; struct rtmsg r; char buf[NL_PKT_BUF_SIZE]; } req; struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id); memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | 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; req.r.rtm_protocol = RTPROT_ZEBRA; req.r.rtm_scope = RT_SCOPE_LINK; if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) discard = 1; else discard = 0; if (cmd == RTM_NEWROUTE) { if (discard) { if (rib->flags & ZEBRA_FLAG_BLACKHOLE) req.r.rtm_type = RTN_BLACKHOLE; else if (rib->flags & ZEBRA_FLAG_REJECT) req.r.rtm_type = RTN_UNREACHABLE; else assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */ } 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, NL_DEFAULT_ROUTE_METRIC); if (rib->mtu || rib->nexthop_mtu) { char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *) buf; u_int32_t mtu = rib->mtu; if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu)) mtu = rib->nexthop_mtu; rta->rta_type = RTA_METRICS; rta->rta_len = RTA_LENGTH(0); rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu); addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta), RTA_PAYLOAD (rta)); } if (discard) { if (cmd == RTM_NEWROUTE) for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { /* We shouldn't encounter recursive nexthops on discard routes, * but it is probably better to handle that case correctly anyway. */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } goto skip; } /* Count overall nexthops so we can decide whether to use singlepath * or multipath case. */ nexthop_num = 0; for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) continue; if (nexthop->type != NEXTHOP_TYPE_IFINDEX && nexthop->type != NEXTHOP_TYPE_IFNAME) req.r.rtm_scope = RT_SCOPE_UNIVERSE; nexthop_num++; } /* Singlepath case. */ if (nexthop_num == 1 || MULTIPATH_NUM == 1) { nexthop_num = 0; for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { routedesc = recursing ? "recursive, 1 hop" : "single hop"; _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf); _netlink_route_build_singlepath(routedesc, bytelen, nexthop, &req.n, &req.r, sizeof req); if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); nexthop_num++; break; } } } else { char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *) buf; struct rtnexthop *rtnh; union g_addr *src = NULL; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH (0); rtnh = RTA_DATA (rta); nexthop_num = 0; for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (nexthop_num >= MULTIPATH_NUM) break; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { routedesc = recursing ? "recursive, multihop" : "multihop"; nexthop_num++; _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf); _netlink_route_build_multipath(routedesc, bytelen, nexthop, rta, rtnh, &src); rtnh = RTNH_NEXT (rtnh); if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } } if (src) addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen); if (rta->rta_len > RTA_LENGTH (0)) addattr_l (&req.n, NL_PKT_BUF_SIZE, 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_debug ("netlink_route_multipath(): No useful nexthop."); return 0; } skip: /* Destination netlink address. */ memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; /* Talk to netlink socket. */ return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf); } int kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) { if (!old && new) return netlink_route_multipath (RTM_NEWROUTE, p, new); if (old && !new) return netlink_route_multipath (RTM_DELROUTE, p, old); /* Replace, can be done atomically if metric does not change; * netlink uses [prefix, tos, priority] to identify prefix. * Now metric is not sent to kernel, so we can just do atomic replace. */ return netlink_route_multipath (RTM_NEWROUTE, p, new); } /* Interface address modification. */ static 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[NL_PKT_BUF_SIZE]; } req; struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); p = ifc->address; memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); 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 (!CONNECTED_PEER(ifc) && 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, &zvrf->netlink_cmd, zvrf); } 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); } extern struct thread_master *master; /* Kernel route reflection. */ static int kernel_read (struct thread *thread) { struct zebra_vrf *zvrf = (struct zebra_vrf *)THREAD_ARG (thread); netlink_parse_info (netlink_information_fetch, &zvrf->netlink, zvrf); zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf, zvrf->netlink.sock); return 0; } /* Filter out messages from self that occur on listener socket, caused by our actions on the command socket */ static void netlink_install_filter (int sock, __u32 pid) { struct sock_filter filter[] = { /* 0: ldh [4] */ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)), /* 1: jeq 0x18 jt 3 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0), /* 2: jeq 0x19 jt 3 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3), /* 3: ldw [12] */ BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)), /* 4: jeq XX jt 5 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1), /* 5: ret 0 (skip) */ BPF_STMT(BPF_RET|BPF_K, 0), /* 6: ret 0xffff (keep) */ BPF_STMT(BPF_RET|BPF_K, 0xffff), }; struct sock_fprog prog = { .len = array_size(filter), .filter = filter, }; if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno)); } /* Exported interface function. This function simply calls netlink_socket (). */ void kernel_init (struct zebra_vrf *zvrf) { 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 (&zvrf->netlink, groups, zvrf->vrf_id); netlink_socket (&zvrf->netlink_cmd, 0, zvrf->vrf_id); /* Register kernel socket. */ if (zvrf->netlink.sock > 0) { size_t bufsize = MAX(nl_rcvbufsize, 2 * sysconf(_SC_PAGESIZE)); /* Only want non-blocking on the netlink event socket */ if (fcntl (zvrf->netlink.sock, F_SETFL, O_NONBLOCK) < 0) zlog_err ("Can't set %s socket flags: %s", zvrf->netlink.name, safe_strerror (errno)); /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) netlink_recvbuf (&zvrf->netlink, nl_rcvbufsize); nl_rcvbuf.p = XMALLOC (MTYPE_NETLINK_RCVBUF, bufsize); nl_rcvbuf.size = bufsize; netlink_install_filter (zvrf->netlink.sock, zvrf->netlink_cmd.snl.nl_pid); zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf, zvrf->netlink.sock); } } void kernel_terminate (struct zebra_vrf *zvrf) { THREAD_READ_OFF (zvrf->t_netlink); if (zvrf->netlink.sock >= 0) { close (zvrf->netlink.sock); zvrf->netlink.sock = -1; } if (zvrf->netlink_cmd.sock >= 0) { close (zvrf->netlink_cmd.sock); zvrf->netlink_cmd.sock = -1; } } /* * nl_msg_type_to_str */ const char * nl_msg_type_to_str (uint16_t msg_type) { return lookup (nlmsg_str, msg_type); } /* * nl_rtproto_to_str */ const char * nl_rtproto_to_str (u_char rtproto) { return lookup (rtproto_str, rtproto); } quagga-1.2.4/zebra/rt_netlink.h000066400000000000000000000030431325323223500164100ustar00rootroot00000000000000/* Header file exported by rt_netlink.c to zebra. * 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_RT_NETLINK_H #define _ZEBRA_RT_NETLINK_H #ifdef HAVE_NETLINK #define NL_PKT_BUF_SIZE 8192 #define NL_DEFAULT_ROUTE_METRIC 20 extern int addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data); extern int addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, size_t alen); extern int rta_addattr_l (struct rtattr *rta, size_t maxlen, int type, void *data, size_t alen); extern const char * nl_msg_type_to_str (uint16_t msg_type); extern const char * nl_rtproto_to_str (u_char rtproto); extern int interface_lookup_netlink (struct zebra_vrf *zvrf); extern int netlink_route_read (struct zebra_vrf *zvrf); #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_RT_NETLINK_H */ quagga-1.2.4/zebra/rt_socket.c000066400000000000000000000254101325323223500162310ustar00rootroot00000000000000/* * 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 "privs.h" #include "zebra/debug.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" extern struct zebra_privs_t zserv_privs; /* kernel socket export */ extern int rtm_write (int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, unsigned int index, int zebra_flags, int metric); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN /* Adjust netmask socket length. Return value is a adjusted sin_len value. */ static 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; } #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib) { struct sockaddr_in *mask = NULL; struct sockaddr_in sin_dest, sin_mask, sin_gate; struct nexthop *nexthop, *tnexthop; int recursing; int nexthop_num = 0; ifindex_t ifindex = 0; int gate = 0; int error; char prefix_buf[PREFIX_STRLEN]; if (IS_ZEBRA_DEBUG_RIB) prefix2str (p, prefix_buf, sizeof(prefix_buf)); memset (&sin_dest, 0, sizeof (struct sockaddr_in)); sin_dest.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_dest.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_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_STRUCT_SOCKADDR_IN_SIN_LEN sin_gate.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Make gateway. */ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; gate = 0; char gate_buf[INET_ADDRSTRLEN] = "NULL"; /* * XXX We need to refrain from kernel operations in some cases, * but this if statement seems overly cautious - what about * other than ADD and DELETE? */ if ((cmd == RTM_ADD && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELETE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) )) { 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 (gate && p->prefixlen == 32) mask = NULL; else { masklen2ip (p->prefixlen, &sin_mask.sin_addr); sin_mask.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_mask.sin_len = sin_masklen (sin_mask.sin_addr); #endif /* HAVE_STRUCT_SOCKADDR_IN_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 (IS_ZEBRA_DEBUG_RIB) { if (!gate) { zlog_debug ("%s: %s: attention! gate not found for rib %p", __func__, prefix_buf, rib); rib_dump (p, rib); } else inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN); } switch (error) { /* We only flag nexthops as being in FIB if rtm_write() did its work. */ case ZEBRA_ERR_NOERROR: nexthop_num++; if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s: successfully did NH %s", __func__, prefix_buf, gate_buf); if (cmd == RTM_ADD) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); break; /* The only valid case for this error is kernel's failure to install * a multipath route, which is common for FreeBSD. This should be * ignored silently, but logged as an error otherwise. */ case ZEBRA_ERR_RTEXIST: if (cmd != RTM_ADD) zlog_err ("%s: rtm_write() returned %d for command %d", __func__, error, cmd); continue; break; /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't * normal to get any other messages in ANY case. */ case ZEBRA_ERR_RTNOEXIST: case ZEBRA_ERR_RTUNREACH: default: zlog_err ("%s: %s: rtm_write() unexpectedly returned %d for command %s", __func__, prefix2str(p, prefix_buf, sizeof(prefix_buf)), error, lookup (rtm_type_str, cmd)); break; } } /* if (cmd and flags make sense) */ else if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: odd command %s for flags %d", __func__, lookup (rtm_type_str, cmd), nexthop->flags); } /* for (ALL_NEXTHOPS_RO(...))*/ /* If there was no useful nexthop, then complain. */ if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, rib); return 0; /*XXX*/ } #ifdef HAVE_IPV6 #ifdef SIN6_LEN /* Calculate sin6_len value for netmask socket value. */ static int sin6_masklen (struct in6_addr mask) { struct sockaddr_in6 sin6; char *p, *lim; int len; if (IN6_IS_ADDR_UNSPECIFIED (&mask)) return sizeof (long); 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; } #endif /* SIN6_LEN */ /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv6 (int cmd, struct prefix *p, struct rib *rib) { struct sockaddr_in6 *mask; struct sockaddr_in6 sin_dest, sin_mask, sin_gate; struct nexthop *nexthop, *tnexthop; int recursing; int nexthop_num = 0; ifindex_t 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_STRUCT_SOCKADDR_IN_SIN_LEN sin_gate.sin6_len = sizeof (struct sockaddr_in6); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Make gateway. */ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; 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 (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 (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_INET6; #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(): nexthop %d add error=%d.", nexthop_num, error); } #else (void)error; #endif nexthop_num++; } /* If there is no useful nexthop then return. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("kernel_rtm_ipv6(): No useful nexthop."); return 0; } return 0; /*XXX*/ } #endif static int kernel_rtm (int cmd, struct prefix *p, struct rib *rib) { switch (PREFIX_FAMILY(p)) { case AF_INET: return kernel_rtm_ipv4 (cmd, p, rib); case AF_INET6: return kernel_rtm_ipv6 (cmd, p, rib); } return 0; } int kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new) { int route = 0; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (old) route |= kernel_rtm (RTM_DELETE, p, old); if (new) route |= kernel_rtm (RTM_ADD, p, new); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } quagga-1.2.4/zebra/rtadv.c000066400000000000000000001445451325323223500153670ustar00rootroot00000000000000/* Router advertisement * Copyright (C) 2005 6WIND * 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 "privs.h" #include "vrf.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/debug.h" #include "zebra/rib.h" #include "zebra/zserv.h" extern struct zebra_privs_t zserv_privs; #if defined (HAVE_IPV6) && defined (HAVE_RTADV) #ifdef OPEN_BSD #include #endif /* 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" extern struct zebra_t zebrad; enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_TIMER_MSEC, RTADV_READ}; static void rtadv_event (struct zebra_vrf *, enum rtadv_event, int); static int if_join_all_router (int, struct interface *); static int if_leave_all_router (int, struct interface *); static int rtadv_recv_packet (int sock, u_char *buf, int buflen, struct sockaddr_in6 *from, ifindex_t *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 = ZCMSG_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) { int *hoptr = (int *) CMSG_DATA (cmsgptr); *hoplimit = *hoptr; } } return ret; } #define RTADV_MSG_SIZE 4096 /* Send router advertisement packet. */ static 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_STRUCT_SOCKADDR_DL struct sockaddr_dl *sdl; #endif /* HAVE_STRUCT_SOCKADDR_DL */ static void *adata = NULL; unsigned char buf[RTADV_MSG_SIZE]; struct nd_router_advert *rtadv; int ret; int len = 0; struct zebra_if *zif; struct rtadv_prefix *rprefix; u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; struct listnode *node; u_int16_t pkt_RouterLifetime; /* * Allocate control message bufffer. This is dynamic because * CMSG_SPACE is not guaranteed not to call a function. Note that * the size will be different on different architectures due to * differing alignment rules. */ if (adata == NULL) { /* XXX Free on shutdown. */ adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo))); if (adata == NULL) zlog_err("rtadv_send_packet: can't malloc control data\n"); } /* Logging of packet. */ if (IS_ZEBRA_DEBUG_PACKET) zlog_debug ("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); IPV6_ADDR_COPY (&addr.sin6_addr, all_nodes_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; /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */ rtadv->nd_ra_flags_reserved = zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference; rtadv->nd_ra_flags_reserved <<= 3; 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; if (zif->rtadv.AdvHomeAgentFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT; /* Note that according to Neighbor Discovery (RFC 4861 [18]), * AdvDefaultLifetime is by default based on the value of * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime * field of Router Advertisements. Given that this field is expressed * in seconds, a small MaxRtrAdvInterval value can result in a zero * value for this field. To prevent this, routers SHOULD keep * AdvDefaultLifetime in at least one second, even if the use of * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */ pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ? zif->rtadv.AdvDefaultLifetime : MAX (1, 0.003 * zif->rtadv.MaxRtrAdvInterval); rtadv->nd_ra_router_lifetime = htons (pkt_RouterLifetime); rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime); rtadv->nd_ra_retransmit = htonl (0); len = sizeof (struct nd_router_advert); /* If both the Home Agent Preference and Home Agent Lifetime are set to * their default values specified above, this option SHOULD NOT be * included in the Router Advertisement messages sent by this home * agent. -- RFC6275, 7.4 */ if ( zif->rtadv.AdvHomeAgentFlag && (zif->rtadv.HomeAgentPreference || zif->rtadv.HomeAgentLifetime != -1) ) { struct nd_opt_homeagent_info *ndopt_hai = (struct nd_opt_homeagent_info *)(buf + len); ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION; ndopt_hai->nd_opt_hai_len = 1; ndopt_hai->nd_opt_hai_reserved = 0; ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference); /* 16-bit unsigned integer. The lifetime associated with the home * agent in units of seconds. The default value is the same as the * Router Lifetime, as specified in the main body of the Router * Advertisement. The maximum value corresponds to 18.2 hours. A * value of 0 MUST NOT be used. -- RFC6275, 7.5 */ ndopt_hai->nd_opt_hai_lifetime = htons ( zif->rtadv.HomeAgentLifetime != -1 ? zif->rtadv.HomeAgentLifetime : MAX (1, pkt_RouterLifetime) /* 0 is OK for RL, but not for HAL*/ ); len += sizeof(struct nd_opt_homeagent_info); } if (zif->rtadv.AdvIntervalOption) { struct nd_opt_adv_interval *ndopt_adv = (struct nd_opt_adv_interval *)(buf + len); ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL; ndopt_adv->nd_opt_ai_len = 1; ndopt_adv->nd_opt_ai_reserved = 0; ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval); len += sizeof(struct nd_opt_adv_interval); } /* Fill in prefix. */ for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) { struct nd_opt_prefix_info *pinfo; 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; if (rprefix->AdvRouterAddressFlag) pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR; pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime); pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime); pinfo->nd_opt_pi_reserved2 = 0; IPV6_ADDR_COPY (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.prefix); #ifdef DEBUG { u_char buf[INET6_ADDRSTRLEN]; zlog_debug ("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. */ if (ifp->hw_addr_len != 0) { buf[len++] = ND_OPT_SOURCE_LINKADDR; /* Option length should be rounded up to next octet if the link address does not end on an octet boundary. */ buf[len++] = (ifp->hw_addr_len + 9) >> 3; memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len); len += ifp->hw_addr_len; /* Pad option to end on an octet boundary. */ memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7); len += -(ifp->hw_addr_len + 2) & 0x7; } /* MTU */ if (zif->rtadv.AdvLinkMTU) { struct nd_opt_mtu * opt = (struct nd_opt_mtu *) (buf + len); opt->nd_opt_mtu_type = ND_OPT_MTU; opt->nd_opt_mtu_len = 1; opt->nd_opt_mtu_reserved = 0; opt->nd_opt_mtu_mtu = htonl (zif->rtadv.AdvLinkMTU); len += sizeof (struct nd_opt_mtu); } 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)); msg.msg_flags = 0; iov.iov_base = buf; iov.iov_len = len; cmsgptr = ZCMSG_FIRSTHDR(&msg); 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 (sock, &msg, 0); if (ret < 0) { zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n", errno, safe_strerror(errno)); } } static int rtadv_timer (struct thread *thread) { struct zebra_vrf *zvrf = THREAD_ARG (thread); struct listnode *node, *nnode; struct interface *ifp; struct zebra_if *zif; int period; zvrf->rtadv.ra_timer = NULL; if (zvrf->rtadv.adv_msec_if_count == 0) { period = 1000; /* 1 s */ rtadv_event (zvrf, RTADV_TIMER, 1 /* 1 s */); } else { period = 10; /* 10 ms */ rtadv_event (zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */); } for (ALL_LIST_ELEMENTS (vrf_iflist (zvrf->vrf_id), node, nnode, ifp)) { if (if_is_loopback (ifp) || ! if_is_operative (ifp)) continue; zif = ifp->info; if (zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvIntervalTimer -= period; if (zif->rtadv.AdvIntervalTimer <= 0) { /* FIXME: using MaxRtrAdvInterval each time isn't what section 6.2.4 of RFC4861 tells to do. */ zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; rtadv_send_packet (zvrf->rtadv.sock, ifp); } } } return 0; } static void rtadv_process_solicit (struct interface *ifp) { struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); zlog_info ("Router solicitation received on %s vrf %u", ifp->name, zvrf->vrf_id); rtadv_send_packet (zvrf->rtadv.sock, ifp); } static void rtadv_process_advert (void) { zlog_info ("Router advertisement received"); } static void rtadv_process_packet (u_char *buf, unsigned int len, ifindex_t ifindex, int hoplimit, vrf_id_t vrf_id) { struct icmp6_hdr *icmph; struct interface *ifp; struct zebra_if *zif; /* Interface search. */ ifp = if_lookup_by_index_vrf (ifindex, vrf_id); if (ifp == NULL) { zlog_warn ("Unknown interface index: %d, vrf %u", ifindex, vrf_id); 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; } static int rtadv_read (struct thread *thread) { int sock; int len; u_char buf[RTADV_MSG_SIZE]; struct sockaddr_in6 from; ifindex_t ifindex = 0; int hoplimit = -1; struct zebra_vrf *zvrf = THREAD_ARG (thread); sock = THREAD_FD (thread); zvrf->rtadv.ra_read = NULL; /* Register myself. */ rtadv_event (zvrf, RTADV_READ, sock); len = rtadv_recv_packet (sock, buf, sizeof (buf), &from, &ifindex, &hoplimit); if (len < 0) { zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno)); return len; } rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id); return 0; } static int rtadv_make_socket (vrf_id_t vrf_id) { int sock; int ret; struct icmp6_filter filter; if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("rtadv_make_socket: could not raise privs, %s", safe_strerror (errno) ); sock = vrf_socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, vrf_id); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("rtadv_make_socket: could not lower privs, %s", safe_strerror (errno) ); /* When we can't make ICMPV6 socket simply back. Router advertisement feature will not be supported. */ if (sock < 0) { close (sock); return -1; } ret = setsockopt_ipv6_pktinfo (sock, 1); if (ret < 0) { close (sock); return ret; } ret = setsockopt_ipv6_multicast_loop (sock, 0); if (ret < 0) { close (sock); return ret; } ret = setsockopt_ipv6_unicast_hops (sock, 255); if (ret < 0) { close (sock); return ret; } ret = setsockopt_ipv6_multicast_hops (sock, 255); if (ret < 0) { close (sock); return ret; } ret = setsockopt_ipv6_hoplimit (sock, 1); if (ret < 0) { close (sock); 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", safe_strerror (errno)); return ret; } return sock; } static struct rtadv_prefix * rtadv_prefix_new (void) { return XCALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix)); } static void rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix) { XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix); } static struct rtadv_prefix * rtadv_prefix_lookup (struct list *rplist, struct prefix_ipv6 *p) { struct listnode *node; struct rtadv_prefix *rprefix; for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix)) if (prefix_same ((struct prefix *) &rprefix->prefix, (struct prefix *) p)) return rprefix; return NULL; } static struct rtadv_prefix * rtadv_prefix_get (struct list *rplist, struct prefix_ipv6 *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_ipv6)); listnode_add (rplist, rprefix); return rprefix; } static 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; rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag; } static 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", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Suppress Router Advertisement\n") { struct interface *ifp; struct zebra_if *zif; struct zebra_vrf *zvrf; ifp = vty->index; zif = ifp->info; zvrf = vrf_info_lookup (ifp->vrf_id); 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; zvrf->rtadv.adv_if_count--; if_leave_all_router (zvrf->rtadv.sock, ifp); if (zvrf->rtadv.adv_if_count == 0) rtadv_event (zvrf, RTADV_STOP, 0); } return CMD_SUCCESS; } DEFUN (no_ipv6_nd_suppress_ra, no_ipv6_nd_suppress_ra_cmd, "no ipv6 nd suppress-ra", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Suppress Router Advertisement\n") { struct interface *ifp; struct zebra_if *zif; struct zebra_vrf *zvrf; ifp = vty->index; zif = ifp->info; zvrf = vrf_info_lookup (ifp->vrf_id); 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; zvrf->rtadv.adv_if_count++; if_join_all_router (zvrf->rtadv.sock, ifp); if (zvrf->rtadv.adv_if_count == 1) rtadv_event (zvrf, RTADV_START, zvrf->rtadv.sock); } return CMD_SUCCESS; } DEFUN (ipv6_nd_ra_interval_msec, ipv6_nd_ra_interval_msec_cmd, "ipv6 nd ra-interval msec <70-1800000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") { unsigned interval; struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000); if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) { vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE); return CMD_WARNING; } if (zif->rtadv.MaxRtrAdvInterval % 1000) zvrf->rtadv.adv_msec_if_count--; if (interval % 1000) zvrf->rtadv.adv_msec_if_count++; zif->rtadv.MaxRtrAdvInterval = interval; zif->rtadv.MinRtrAdvInterval = 0.33 * interval; zif->rtadv.AdvIntervalTimer = 0; return CMD_SUCCESS; } DEFUN (ipv6_nd_ra_interval, ipv6_nd_ra_interval_cmd, "ipv6 nd ra-interval <1-1800>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in seconds\n") { unsigned interval; struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id); VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800); if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) { vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE); return CMD_WARNING; } if (zif->rtadv.MaxRtrAdvInterval % 1000) zvrf->rtadv.adv_msec_if_count--; /* convert to milliseconds */ interval = interval * 1000; 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 "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n") { struct interface *ifp; struct zebra_if *zif; struct zebra_vrf *zvrf; ifp = (struct interface *) vty->index; zif = ifp->info; zvrf = vrf_info_lookup (ifp->vrf_id); if (zif->rtadv.MaxRtrAdvInterval % 1000) zvrf->rtadv.adv_msec_if_count--; 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; } ALIAS (no_ipv6_nd_ra_interval, no_ipv6_nd_ra_interval_val_cmd, "no ipv6 nd ra-interval <1-1800>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n") ALIAS (no_ipv6_nd_ra_interval, no_ipv6_nd_ra_interval_msec_val_cmd, "no ipv6 nd ra-interval msec <1-1800000>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") DEFUN (ipv6_nd_ra_lifetime, ipv6_nd_ra_lifetime_cmd, "ipv6 nd ra-lifetime <0-9000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" "Router lifetime in seconds (0 stands for a non-default gw)\n") { int lifetime; struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; VTY_GET_INTEGER_RANGE ("router lifetime", lifetime, argv[0], 0, 9000); /* 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. -- RFC4861, 6.2.1 */ if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) { vty_out (vty, "This ra-lifetime would conflict with configured ra-interval%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 "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvDefaultLifetime = -1; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_ra_lifetime, no_ipv6_nd_ra_lifetime_val_cmd, "no ipv6 nd ra-lifetime <0-9000>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" "Router lifetime in seconds (0 stands for a non-default gw)\n") DEFUN (ipv6_nd_reachable_time, ipv6_nd_reachable_time_cmd, "ipv6 nd reachable-time <1-3600000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("reachable time", zif->rtadv.AdvReachableTime, argv[0], 1, RTADV_MAX_REACHABLE_TIME); return CMD_SUCCESS; } DEFUN (no_ipv6_nd_reachable_time, no_ipv6_nd_reachable_time_cmd, "no ipv6 nd reachable-time", NO_STR "Interface IPv6 config commands\n" "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; } ALIAS (no_ipv6_nd_reachable_time, no_ipv6_nd_reachable_time_val_cmd, "no ipv6 nd reachable-time <1-3600000>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") DEFUN (ipv6_nd_homeagent_preference, ipv6_nd_homeagent_preference_cmd, "ipv6 nd home-agent-preference <0-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" "preference value (default is 0, least preferred)\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("home agent preference", zif->rtadv.HomeAgentPreference, argv[0], 0, 65535); return CMD_SUCCESS; } DEFUN (no_ipv6_nd_homeagent_preference, no_ipv6_nd_homeagent_preference_cmd, "no ipv6 nd home-agent-preference", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.HomeAgentPreference = 0; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_homeagent_preference, no_ipv6_nd_homeagent_preference_val_cmd, "no ipv6 nd home-agent-preference <0-65535>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" "preference value (default is 0, least preferred)\n") DEFUN (ipv6_nd_homeagent_lifetime, ipv6_nd_homeagent_lifetime_cmd, "ipv6 nd home-agent-lifetime <0-65520>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("home agent lifetime", zif->rtadv.HomeAgentLifetime, argv[0], 0, RTADV_MAX_HALIFETIME); return CMD_SUCCESS; } DEFUN (no_ipv6_nd_homeagent_lifetime, no_ipv6_nd_homeagent_lifetime_cmd, "no ipv6 nd home-agent-lifetime", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.HomeAgentLifetime = -1; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_homeagent_lifetime, no_ipv6_nd_homeagent_lifetime_val_cmd, "no ipv6 nd home-agent-lifetime <0-65520>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") DEFUN (ipv6_nd_managed_config_flag, ipv6_nd_managed_config_flag_cmd, "ipv6 nd managed-config-flag", "Interface IPv6 config commands\n" "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 "Interface IPv6 config commands\n" "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_homeagent_config_flag, ipv6_nd_homeagent_config_flag_cmd, "ipv6 nd home-agent-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent configuration flag\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvHomeAgentFlag = 1; return CMD_SUCCESS; } DEFUN (no_ipv6_nd_homeagent_config_flag, no_ipv6_nd_homeagent_config_flag_cmd, "no ipv6 nd home-agent-config-flag", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent configuration flag\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvHomeAgentFlag = 0; return CMD_SUCCESS; } DEFUN (ipv6_nd_adv_interval_config_option, ipv6_nd_adv_interval_config_option_cmd, "ipv6 nd adv-interval-option", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertisement Interval Option\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvIntervalOption = 1; return CMD_SUCCESS; } DEFUN (no_ipv6_nd_adv_interval_config_option, no_ipv6_nd_adv_interval_config_option_cmd, "no ipv6 nd adv-interval-option", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertisement Interval Option\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvIntervalOption = 0; return CMD_SUCCESS; } DEFUN (ipv6_nd_other_config_flag, ipv6_nd_other_config_flag_cmd, "ipv6 nd other-config-flag", "Interface IPv6 config commands\n" "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 "Interface IPv6 config commands\n" "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, ipv6_nd_prefix_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n" "Set Router Address flag\n") { int i; int ret; int cursor = 1; 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], &rp.prefix); if (!ret) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */ rp.AdvOnLinkFlag = 1; rp.AdvAutonomousFlag = 1; rp.AdvRouterAddressFlag = 0; rp.AdvValidLifetime = RTADV_VALID_LIFETIME; rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; if (argc > 1) { if ((isdigit((unsigned char)argv[1][0])) || strncmp (argv[1], "i", 1) == 0) { if ( strncmp (argv[1], "i", 1) == 0) rp.AdvValidLifetime = UINT32_MAX; else rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1], (char **)NULL, 10); if ( strncmp (argv[2], "i", 1) == 0) rp.AdvPreferredLifetime = UINT32_MAX; else rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2], (char **)NULL, 10); if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) { vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE); return CMD_WARNING; } cursor = cursor + 2; } if (argc > cursor) { for (i = cursor; i < argc; i++) { if (strncmp (argv[i], "of", 2) == 0) rp.AdvOnLinkFlag = 0; if (strncmp (argv[i], "no", 2) == 0) rp.AdvAutonomousFlag = 0; if (strncmp (argv[i], "ro", 2) == 0) rp.AdvRouterAddressFlag = 1; } } } rtadv_prefix_set (zebra_if, &rp); return CMD_SUCCESS; } ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_nortaddr_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_rev_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_rev_rtaddr_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n" "Set Router Address flag\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_noauto_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_offlink_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_rtaddr_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Set Router Address flag\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_cmd, "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_rev_cmd, "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_noauto_cmd, "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for autoconfiguration\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_offlink_cmd, "ipv6 nd prefix X:X::X:X/M (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for onlink determination\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_rtaddr_cmd, "ipv6 nd prefix X:X::X:X/M (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Set Router Address flag\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_prefix_cmd, "ipv6 nd prefix X:X::X:X/M", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n") DEFUN (no_ipv6_nd_prefix, no_ipv6_nd_prefix_cmd, "no ipv6 nd prefix IPV6PREFIX", NO_STR "Interface IPv6 config commands\n" "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], &rp.prefix); if (!ret) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */ 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; } DEFUN (ipv6_nd_router_preference, ipv6_nd_router_preference_cmd, "ipv6 nd router-preference (high|medium|low)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n" "High default router preference\n" "Low default router preference\n" "Medium default router preference (default)\n") { struct interface *ifp; struct zebra_if *zif; int i = 0; ifp = (struct interface *) vty->index; zif = ifp->info; while (0 != rtadv_pref_strs[i]) { if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0) { zif->rtadv.DefaultPreference = i; return CMD_SUCCESS; } i++; } return CMD_ERR_NO_MATCH; } DEFUN (no_ipv6_nd_router_preference, no_ipv6_nd_router_preference_cmd, "no ipv6 nd router-preference", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */ return CMD_SUCCESS; } ALIAS (no_ipv6_nd_router_preference, no_ipv6_nd_router_preference_val_cmd, "no ipv6 nd router-preference (high|medium|low)", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n" "High default router preference\n" "Low default router preference\n" "Medium default router preference (default)\n") DEFUN (ipv6_nd_mtu, ipv6_nd_mtu_cmd, "ipv6 nd mtu <1-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n" "MTU in bytes\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("MTU", zif->rtadv.AdvLinkMTU, argv[0], 1, 65535); return CMD_SUCCESS; } DEFUN (no_ipv6_nd_mtu, no_ipv6_nd_mtu_cmd, "no ipv6 nd mtu", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; zif->rtadv.AdvLinkMTU = 0; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_mtu, no_ipv6_nd_mtu_val_cmd, "no ipv6 nd mtu <1-65535>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n" "MTU in bytes\n") /* Write configuration about router advertisement. */ void rtadv_config_write (struct vty *vty, struct interface *ifp) { struct zebra_if *zif; struct listnode *node; struct rtadv_prefix *rprefix; char buf[PREFIX_STRLEN]; int interval; zif = ifp->info; if (! if_is_loopback (ifp)) { if (zif->rtadv.AdvSendAdvertisements) vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE); } interval = zif->rtadv.MaxRtrAdvInterval; if (interval % 1000) vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval, VTY_NEWLINE); else if (interval != RTADV_MAX_RTR_ADV_INTERVAL) vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000, VTY_NEWLINE); if (zif->rtadv.AdvIntervalOption) vty_out (vty, " ipv6 nd adv-interval-option%s", VTY_NEWLINE); if (zif->rtadv.AdvDefaultLifetime != -1) vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime, VTY_NEWLINE); if (zif->rtadv.HomeAgentPreference) vty_out (vty, " ipv6 nd home-agent-preference %u%s", zif->rtadv.HomeAgentPreference, VTY_NEWLINE); if (zif->rtadv.HomeAgentLifetime != -1) vty_out (vty, " ipv6 nd home-agent-lifetime %u%s", zif->rtadv.HomeAgentLifetime, VTY_NEWLINE); if (zif->rtadv.AdvHomeAgentFlag) vty_out (vty, " ipv6 nd home-agent-config-flag%s", 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); if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM) vty_out (vty, " ipv6 nd router-preference %s%s", rtadv_pref_strs[zif->rtadv.DefaultPreference], VTY_NEWLINE); if (zif->rtadv.AdvLinkMTU) vty_out (vty, " ipv6 nd mtu %d%s", zif->rtadv.AdvLinkMTU, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) { vty_out (vty, " ipv6 nd prefix %s", prefix2str (&rprefix->prefix, buf, sizeof(buf))); if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) || (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME)) { if (rprefix->AdvValidLifetime == UINT32_MAX) vty_out (vty, " infinite"); else vty_out (vty, " %u", rprefix->AdvValidLifetime); if (rprefix->AdvPreferredLifetime == UINT32_MAX) vty_out (vty, " infinite"); else vty_out (vty, " %u", rprefix->AdvPreferredLifetime); } if (!rprefix->AdvOnLinkFlag) vty_out (vty, " off-link"); if (!rprefix->AdvAutonomousFlag) vty_out (vty, " no-autoconfig"); if (rprefix->AdvRouterAddressFlag) vty_out (vty, " router-address"); vty_out (vty, "%s", VTY_NEWLINE); } } static void rtadv_event (struct zebra_vrf *zvrf, enum rtadv_event event, int val) { struct rtadv *rtadv = &zvrf->rtadv; switch (event) { case RTADV_START: if (! rtadv->ra_read) rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val); if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer, zvrf, 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 (zebrad.master, rtadv_timer, zvrf, val); break; case RTADV_TIMER_MSEC: if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer, zvrf, val); break; case RTADV_READ: if (! rtadv->ra_read) rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val); break; default: break; } return; } void rtadv_init (struct zebra_vrf *zvrf) { zvrf->rtadv.sock = rtadv_make_socket (zvrf->vrf_id); } void rtadv_terminate (struct zebra_vrf *zvrf) { rtadv_event (zvrf, RTADV_STOP, 0); if (zvrf->rtadv.sock >= 0) { close (zvrf->rtadv.sock); zvrf->rtadv.sock = -1; } zvrf->rtadv.adv_if_count = 0; zvrf->rtadv.adv_msec_if_count = 0; } void rtadv_cmd_init (void) { 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_ra_interval_cmd); install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_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_homeagent_config_flag_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd); install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd); } static 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", safe_strerror (errno)); zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name); return 0; } static 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", safe_strerror (errno)); zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name); return 0; } #else void rtadv_init (struct zebra_vrf *zvrf) { /* Empty.*/; } void rtadv_terminate (struct zebra_vrf *zvrf) { /* Empty.*/; } void rtadv_cmd_init (void) { /* Empty.*/; } #endif /* HAVE_RTADV && HAVE_IPV6 */ quagga-1.2.4/zebra/rtadv.h000066400000000000000000000064251325323223500153660ustar00rootroot00000000000000/* Router advertisement * Copyright (C) 2005 6WIND * 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 #include "vty.h" #include "zebra/interface.h" /* NB: RTADV is defined in zebra/interface.h above */ #if defined (HAVE_RTADV) /* Router advertisement prefix. */ struct rtadv_prefix { /* Prefix to be advertised. */ struct prefix_ipv6 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; /* The value to be placed in the Router Address Flag [RFC6275 7.2]. */ int AdvRouterAddressFlag; #ifndef ND_OPT_PI_FLAG_RADDR #define ND_OPT_PI_FLAG_RADDR 0x20 #endif }; extern void rtadv_config_write (struct vty *, struct interface *); /* RFC4584 Extension to Sockets API for Mobile IPv6 */ #ifndef ND_OPT_ADV_INTERVAL #define ND_OPT_ADV_INTERVAL 7 /* Adv Interval Option */ #endif #ifndef ND_OPT_HA_INFORMATION #define ND_OPT_HA_INFORMATION 8 /* HA Information Option */ #endif #ifndef HAVE_STRUCT_ND_OPT_ADV_INTERVAL struct nd_opt_adv_interval { /* Advertisement interval option */ uint8_t nd_opt_ai_type; uint8_t nd_opt_ai_len; uint16_t nd_opt_ai_reserved; uint32_t nd_opt_ai_interval; } __attribute__((__packed__)); #else #ifndef HAVE_STRUCT_ND_OPT_ADV_INTERVAL_ND_OPT_AI_TYPE /* fields may have to be renamed */ #define nd_opt_ai_type nd_opt_adv_interval_type #define nd_opt_ai_len nd_opt_adv_interval_len #define nd_opt_ai_reserved nd_opt_adv_interval_reserved #define nd_opt_ai_interval nd_opt_adv_interval_ival #endif #endif #ifndef HAVE_STRUCT_ND_OPT_HOMEAGENT_INFO struct nd_opt_homeagent_info { /* Home Agent info */ u_int8_t nd_opt_hai_type; u_int8_t nd_opt_hai_len; u_int16_t nd_opt_hai_reserved; u_int16_t nd_opt_hai_preference; u_int16_t nd_opt_hai_lifetime; } __attribute__((__packed__)); #endif extern const char *rtadv_pref_strs[]; #endif /* HAVE_RTADV */ extern void rtadv_init (struct zebra_vrf *); extern void rtadv_terminate (struct zebra_vrf *); extern void rtadv_cmd_init (void); #endif /* _ZEBRA_RTADV_H */ quagga-1.2.4/zebra/rtread_getmsg.c000066400000000000000000000144171325323223500170700ustar00rootroot00000000000000/* * 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 "vrf.h" #include "vty.h" #include "zebra/rib.h" #include "zebra/zserv.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 static 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, NULL, 0, VRF_DEFAULT, RT_TABLE_MAIN, 0, 0, 0, SAFI_UNICAST); } void route_read (struct zebra_vrf *zvrf) { 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 (zvrf->vrf_id != VRF_DEFAULT) { return; } if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) { zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE, safe_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", safe_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", safe_strerror (errno)); goto exit; } /* This is normal loop termination */ if (retval == 0 && (size_t)msgdata.len >= sizeof (struct T_optmgmt_ack) && TLIack->PRIM_type == T_OPTMGMT_ACK && TLIack->MGMT_flags == T_SUCCESS && MIB2hdr->len == 0) break; if ((size_t)msgdata.len >= sizeof (struct T_error_ack) && TLIerr->PRIM_type == T_ERROR_ACK) { zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s", safe_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 || (size_t)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", safe_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); } quagga-1.2.4/zebra/rtread_netlink.c000066400000000000000000000017411325323223500172420ustar00rootroot00000000000000/* * 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 #include "zebra/zserv.h" #include "rt_netlink.h" void route_read (struct zebra_vrf *zvrf) { netlink_route_read (zvrf); } quagga-1.2.4/zebra/rtread_sysctl.c000066400000000000000000000040771325323223500171240ustar00rootroot00000000000000/* * 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" #include "vrf.h" #include "zebra/zserv.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" /* Kernel routing table read up by sysctl function. */ void route_read (struct zebra_vrf *zvrf) { caddr_t buf, end, ref; size_t bufsiz; struct rt_msghdr *rtm; #define MIBSIZ 6 int mib[MIBSIZ] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 }; if (zvrf->vrf_id != VRF_DEFAULT) return; /* Get buffer size. */ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { zlog_warn ("sysctl fail: %s", safe_strerror (errno)); return; } /* 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", safe_strerror (errno)); return; } for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) { rtm = (struct rt_msghdr *) buf; /* We must set RTF_DONE here, so rtm_read() doesn't ignore the message. */ SET_FLAG (rtm->rtm_flags, RTF_DONE); rtm_read (rtm); } /* Free buffer. */ XFREE (MTYPE_TMP, ref); return; } quagga-1.2.4/zebra/test_main.c000066400000000000000000000205231325323223500162170ustar00rootroot00000000000000/* main routine. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "getopt.h" #include "command.h" #include "thread.h" #include "filter.h" #include "memory.h" #include "prefix.h" #include "log.h" #include "privs.h" #include "sigevent.h" #include "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/router-id.h" #include "zebra/interface.h" /* Zebra instance */ struct zebra_t zebrad = { .rtm_table_default = 0, }; /* process id. */ pid_t pid; /* zebra_rib's workqueue hold time. Private export for use by test code only */ extern int rib_process_hold_time; /* Pacify zclient.o in libzebra, which expects this variable. */ struct thread_master *master; /* Command line options. */ struct option longopts[] = { { "batch", no_argument, NULL, 'b'}, { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "version", no_argument, NULL, 'v'}, { "rib_hold", required_argument, NULL, 'r'}, { 0 } }; zebra_capabilities_t _caps_p [] = { ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, }; /* Default configuration file path. */ char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE; /* Process ID saved for use by init system */ const 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"\ "-A, --vty_addr Set vty's bind address\n"\ "-P, --vty_port Set vty's port number\n"\ "-r, --rib_hold Set rib-queue hold time\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); } static ifindex_t test_ifindex = 0; /* testrib commands */ DEFUN (test_interface_state, test_interface_state_cmd, "state (up|down)", "configure interface\n" "up\n" "down\n") { struct interface *ifp; if (argc < 1) return CMD_WARNING; ifp = vty->index; if (ifp->ifindex == IFINDEX_INTERNAL) { ifp->ifindex = ++test_ifindex; ifp->mtu = 1500; ifp->flags = IFF_BROADCAST|IFF_MULTICAST; } switch (argv[0][0]) { case 'u': SET_FLAG (ifp->flags, IFF_UP); if_add_update (ifp); printf ("up\n"); break; case 'd': UNSET_FLAG (ifp->flags, IFF_UP); if_delete_update (ifp); printf ("down\n"); break; default: return CMD_WARNING; } return CMD_SUCCESS; } static void test_cmd_init (void) { install_element (INTERFACE_NODE, &test_interface_state_cmd); } /* SIGHUP handler. */ static void sighup (void) { zlog_info ("SIGHUP received"); /* Reload of config file. */ ; } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } struct quagga_signal_t zebra_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* Callback upon creating a new VRF. */ static int zebra_vrf_new (vrf_id_t vrf_id, void **info) { struct zebra_vrf *zvrf = *info; if (! zvrf) { zvrf = zebra_vrf_alloc (vrf_id); *info = (void *)zvrf; } return 0; } /* Callback upon enabling a VRF. */ static int zebra_vrf_enable (vrf_id_t vrf_id, void **info) { struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info); assert (zvrf); kernel_init (zvrf); route_read (zvrf); return 0; } /* Callback upon disabling a VRF. */ static int zebra_vrf_disable (vrf_id_t vrf_id, void **info) { struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info); struct listnode *list_node; struct interface *ifp; assert (zvrf); rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), list_node, ifp)) { int operative = if_is_operative (ifp); UNSET_FLAG (ifp->flags, IFF_UP); if (operative) if_down (ifp); } kernel_terminate (zvrf); return 0; } /* Zebra VRF initialization. */ static void zebra_vrf_init (void) { vrf_add_hook (VRF_NEW_HOOK, zebra_vrf_new); vrf_add_hook (VRF_ENABLE_HOOK, zebra_vrf_enable); vrf_add_hook (VRF_DISABLE_HOOK, zebra_vrf_disable); vrf_init (); } /* 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; /* Set umask before anything for security */ umask (0027); /* preserve my name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog (progname, ZLOG_ZEBRA, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); while (1) { int opt; opt = getopt_long (argc, argv, "bdf:hA:P:r:v", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'b': batch_mode = 1; case 'd': daemon_mode = 1; break; case 'f': config_file = optarg; break; case 'A': vty_addr = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure, and zebra not listening on zebra port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); break; case 'r': rib_process_hold_time = atoi(optarg); break; case 'v': print_version (progname); exit (0); break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* port and conf file mandatory */ if (!vty_port || !config_file) { fprintf (stderr, "Error: --vty_port and --config_file arguments" " are both required\n"); usage (progname, 1); } /* Make master thread emulator. */ zebrad.master = thread_master_create (); /* Vty related initialize. */ signal_init (zebrad.master, array_size(zebra_signals), zebra_signals); cmd_init (1); vty_init (zebrad.master); memory_init (); zebra_debug_init (); zebra_if_init (); test_cmd_init (); /* Zebra related initialize. */ rib_init (); access_list_init (); /* Make kernel routing socket. */ zebra_vrf_init (); zebra_vty_init(); /* Configuration file read*/ vty_read_config (config_file, config_default); /* Clean up rib. */ rib_weed_tables (); /* Exit when zebra is working in batch mode. */ if (batch_mode) exit (0); /* Daemonize. */ if (daemon_mode && daemon (0, 0) < 0) { perror("daemon start failed"); exit (1); } /* Needed for BSD routing socket. */ pid = getpid (); /* Make vty server socket. */ vty_serv_sock (vty_addr, vty_port, "/tmp/test_zebra"); /* Print banner. */ zlog_notice ("Zebra %s starting: vty@%d", QUAGGA_VERSION, vty_port); thread_main (zebrad.master); /* Not reached... */ return 0; } quagga-1.2.4/zebra/zebra.conf.sample000066400000000000000000000005611325323223500173220ustar00rootroot00000000000000! -*- zebra -*- ! ! zebra sample configuration file ! ! $Id: zebra.conf.sample,v 1.1 2002/12/13 20:15:30 paul 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 quagga-1.2.4/zebra/zebra_fpm.c000066400000000000000000001065201325323223500162030ustar00rootroot00000000000000/* * Main implementation file for interface to Forwarding Plane Manager. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "thread.h" #include "network.h" #include "command.h" #include "zebra/rib.h" #include "fpm/fpm.h" #include "zebra_fpm.h" #include "zebra_fpm_private.h" /* * Interval at which we attempt to connect to the FPM. */ #define ZFPM_CONNECT_RETRY_IVL 5 /* * Sizes of outgoing and incoming stream buffers for writing/reading * FPM messages. */ #define ZFPM_OBUF_SIZE (2 * FPM_MAX_MSG_LEN) #define ZFPM_IBUF_SIZE (FPM_MAX_MSG_LEN) /* * The maximum number of times the FPM socket write callback can call * 'write' before it yields. */ #define ZFPM_MAX_WRITES_PER_RUN 10 /* * Interval over which we collect statistics. */ #define ZFPM_STATS_IVL_SECS 10 /* * Structure that holds state for iterating over all route_node * structures that are candidates for being communicated to the FPM. */ typedef struct zfpm_rnodes_iter_t_ { rib_tables_iter_t tables_iter; route_table_iter_t iter; } zfpm_rnodes_iter_t; /* * Statistics. */ typedef struct zfpm_stats_t_ { unsigned long connect_calls; unsigned long connect_no_sock; unsigned long read_cb_calls; unsigned long write_cb_calls; unsigned long write_calls; unsigned long partial_writes; unsigned long max_writes_hit; unsigned long t_write_yields; unsigned long nop_deletes_skipped; unsigned long route_adds; unsigned long route_dels; unsigned long updates_triggered; unsigned long redundant_triggers; unsigned long non_fpm_table_triggers; unsigned long dests_del_after_update; unsigned long t_conn_down_starts; unsigned long t_conn_down_dests_processed; unsigned long t_conn_down_yields; unsigned long t_conn_down_finishes; unsigned long t_conn_up_starts; unsigned long t_conn_up_dests_processed; unsigned long t_conn_up_yields; unsigned long t_conn_up_aborts; unsigned long t_conn_up_finishes; } zfpm_stats_t; /* * States for the FPM state machine. */ typedef enum { /* * In this state we are not yet ready to connect to the FPM. This * can happen when this module is disabled, or if we're cleaning up * after a connection has gone down. */ ZFPM_STATE_IDLE, /* * Ready to talk to the FPM and periodically trying to connect to * it. */ ZFPM_STATE_ACTIVE, /* * In the middle of bringing up a TCP connection. Specifically, * waiting for a connect() call to complete asynchronously. */ ZFPM_STATE_CONNECTING, /* * TCP connection to the FPM is up. */ ZFPM_STATE_ESTABLISHED } zfpm_state_t; /* * Message format to be used to communicate with the FPM. */ typedef enum { ZFPM_MSG_FORMAT_NONE, ZFPM_MSG_FORMAT_NETLINK, ZFPM_MSG_FORMAT_PROTOBUF, } zfpm_msg_format_e; /* * Globals. */ typedef struct zfpm_glob_t_ { /* * True if the FPM module has been enabled. */ int enabled; /* * Message format to be used to communicate with the fpm. */ zfpm_msg_format_e message_format; struct thread_master *master; zfpm_state_t state; in_addr_t fpm_server; /* * Port on which the FPM is running. */ int fpm_port; /* * List of rib_dest_t structures to be processed */ TAILQ_HEAD (zfpm_dest_q, rib_dest_t_) dest_q; /* * Stream socket to the FPM. */ int sock; /* * Buffers for messages to/from the FPM. */ struct stream *obuf; struct stream *ibuf; /* * Threads for I/O. */ struct thread *t_connect; struct thread *t_write; struct thread *t_read; /* * Thread to clean up after the TCP connection to the FPM goes down * and the state that belongs to it. */ struct thread *t_conn_down; struct { zfpm_rnodes_iter_t iter; } t_conn_down_state; /* * Thread to take actions once the TCP conn to the FPM comes up, and * the state that belongs to it. */ struct thread *t_conn_up; struct { zfpm_rnodes_iter_t iter; } t_conn_up_state; unsigned long connect_calls; time_t last_connect_call_time; /* * Stats from the start of the current statistics interval up to * now. These are the counters we typically update in the code. */ zfpm_stats_t stats; /* * Statistics that were gathered in the last collection interval. */ zfpm_stats_t last_ivl_stats; /* * Cumulative stats from the last clear to the start of the current * statistics interval. */ zfpm_stats_t cumulative_stats; /* * Stats interval timer. */ struct thread *t_stats; /* * If non-zero, the last time when statistics were cleared. */ time_t last_stats_clear_time; } zfpm_glob_t; static zfpm_glob_t zfpm_glob_space; static zfpm_glob_t *zfpm_g = &zfpm_glob_space; static int zfpm_read_cb (struct thread *thread); static int zfpm_write_cb (struct thread *thread); static void zfpm_set_state (zfpm_state_t state, const char *reason); static void zfpm_start_connect_timer (const char *reason); static void zfpm_start_stats_timer (void); /* * zfpm_thread_should_yield */ static inline int zfpm_thread_should_yield (struct thread *t) { return thread_should_yield (t); } /* * zfpm_state_to_str */ static const char * zfpm_state_to_str (zfpm_state_t state) { switch (state) { case ZFPM_STATE_IDLE: return "idle"; case ZFPM_STATE_ACTIVE: return "active"; case ZFPM_STATE_CONNECTING: return "connecting"; case ZFPM_STATE_ESTABLISHED: return "established"; default: return "unknown"; } } /* * zfpm_get_time */ static time_t zfpm_get_time (void) { struct timeval tv; if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0) zlog_warn ("FPM: quagga_gettime failed!!"); return tv.tv_sec; } /* * zfpm_get_elapsed_time * * Returns the time elapsed (in seconds) since the given time. */ static time_t zfpm_get_elapsed_time (time_t reference) { time_t now; now = zfpm_get_time (); if (now < reference) { assert (0); return 0; } return now - reference; } /* * zfpm_is_table_for_fpm * * Returns TRUE if the the given table is to be communicated to the * FPM. */ static inline int zfpm_is_table_for_fpm (struct route_table *table) { rib_table_info_t *info; info = rib_table_info (table); /* * We only send the unicast tables in the main instance to the FPM * at this point. */ if (info->zvrf->vrf_id != 0) return 0; if (info->safi != SAFI_UNICAST) return 0; return 1; } /* * zfpm_rnodes_iter_init */ static inline void zfpm_rnodes_iter_init (zfpm_rnodes_iter_t *iter) { memset (iter, 0, sizeof (*iter)); rib_tables_iter_init (&iter->tables_iter); /* * This is a hack, but it makes implementing 'next' easier by * ensuring that route_table_iter_next() will return NULL the first * time we call it. */ route_table_iter_init (&iter->iter, NULL); route_table_iter_cleanup (&iter->iter); } /* * zfpm_rnodes_iter_next */ static inline struct route_node * zfpm_rnodes_iter_next (zfpm_rnodes_iter_t *iter) { struct route_node *rn; struct route_table *table; while (1) { rn = route_table_iter_next (&iter->iter); if (rn) return rn; /* * We've made our way through this table, go to the next one. */ route_table_iter_cleanup (&iter->iter); while ((table = rib_tables_iter_next (&iter->tables_iter))) { if (zfpm_is_table_for_fpm (table)) break; } if (!table) return NULL; route_table_iter_init (&iter->iter, table); } return NULL; } /* * zfpm_rnodes_iter_pause */ static inline void zfpm_rnodes_iter_pause (zfpm_rnodes_iter_t *iter) { route_table_iter_pause (&iter->iter); } /* * zfpm_rnodes_iter_cleanup */ static inline void zfpm_rnodes_iter_cleanup (zfpm_rnodes_iter_t *iter) { route_table_iter_cleanup (&iter->iter); rib_tables_iter_cleanup (&iter->tables_iter); } /* * zfpm_stats_init * * Initialize a statistics block. */ static inline void zfpm_stats_init (zfpm_stats_t *stats) { memset (stats, 0, sizeof (*stats)); } /* * zfpm_stats_reset */ static inline void zfpm_stats_reset (zfpm_stats_t *stats) { zfpm_stats_init (stats); } /* * zfpm_stats_copy */ static inline void zfpm_stats_copy (const zfpm_stats_t *src, zfpm_stats_t *dest) { memcpy (dest, src, sizeof (*dest)); } /* * zfpm_stats_compose * * Total up the statistics in two stats structures ('s1 and 's2') and * return the result in the third argument, 'result'. Note that the * pointer 'result' may be the same as 's1' or 's2'. * * For simplicity, the implementation below assumes that the stats * structure is composed entirely of counters. This can easily be * changed when necessary. */ static void zfpm_stats_compose (const zfpm_stats_t *s1, const zfpm_stats_t *s2, zfpm_stats_t *result) { const unsigned long *p1, *p2; unsigned long *result_p; int i, num_counters; p1 = (const unsigned long *) s1; p2 = (const unsigned long *) s2; result_p = (unsigned long *) result; num_counters = (sizeof (zfpm_stats_t) / sizeof (unsigned long)); for (i = 0; i < num_counters; i++) { result_p[i] = p1[i] + p2[i]; } } /* * zfpm_read_on */ static inline void zfpm_read_on (void) { assert (!zfpm_g->t_read); assert (zfpm_g->sock >= 0); THREAD_READ_ON (zfpm_g->master, zfpm_g->t_read, zfpm_read_cb, 0, zfpm_g->sock); } /* * zfpm_write_on */ static inline void zfpm_write_on (void) { assert (!zfpm_g->t_write); assert (zfpm_g->sock >= 0); THREAD_WRITE_ON (zfpm_g->master, zfpm_g->t_write, zfpm_write_cb, 0, zfpm_g->sock); } /* * zfpm_read_off */ static inline void zfpm_read_off (void) { THREAD_READ_OFF (zfpm_g->t_read); } /* * zfpm_write_off */ static inline void zfpm_write_off (void) { THREAD_WRITE_OFF (zfpm_g->t_write); } /* * zfpm_conn_up_thread_cb * * Callback for actions to be taken when the connection to the FPM * comes up. */ static int zfpm_conn_up_thread_cb (struct thread *thread) { struct route_node *rnode; zfpm_rnodes_iter_t *iter; rib_dest_t *dest; assert (zfpm_g->t_conn_up); zfpm_g->t_conn_up = NULL; iter = &zfpm_g->t_conn_up_state.iter; if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) { zfpm_debug ("Connection not up anymore, conn_up thread aborting"); zfpm_g->stats.t_conn_up_aborts++; goto done; } while ((rnode = zfpm_rnodes_iter_next (iter))) { dest = rib_dest_from_rnode (rnode); if (dest) { zfpm_g->stats.t_conn_up_dests_processed++; zfpm_trigger_update (rnode, NULL); } /* * Yield if need be. */ if (!zfpm_thread_should_yield (thread)) continue; zfpm_g->stats.t_conn_up_yields++; zfpm_rnodes_iter_pause (iter); zfpm_g->t_conn_up = thread_add_background (zfpm_g->master, zfpm_conn_up_thread_cb, 0, 0); return 0; } zfpm_g->stats.t_conn_up_finishes++; done: zfpm_rnodes_iter_cleanup (iter); return 0; } /* * zfpm_connection_up * * Called when the connection to the FPM comes up. */ static void zfpm_connection_up (const char *detail) { assert (zfpm_g->sock >= 0); zfpm_read_on (); zfpm_write_on (); zfpm_set_state (ZFPM_STATE_ESTABLISHED, detail); /* * Start thread to push existing routes to the FPM. */ assert (!zfpm_g->t_conn_up); zfpm_rnodes_iter_init (&zfpm_g->t_conn_up_state.iter); zfpm_debug ("Starting conn_up thread"); zfpm_g->t_conn_up = thread_add_background (zfpm_g->master, zfpm_conn_up_thread_cb, 0, 0); zfpm_g->stats.t_conn_up_starts++; } /* * zfpm_connect_check * * Check if an asynchronous connect() to the FPM is complete. */ static void zfpm_connect_check () { int status; socklen_t slen; int ret; zfpm_read_off (); zfpm_write_off (); slen = sizeof (status); ret = getsockopt (zfpm_g->sock, SOL_SOCKET, SO_ERROR, (void *) &status, &slen); if (ret >= 0 && status == 0) { zfpm_connection_up ("async connect complete"); return; } /* * getsockopt() failed or indicated an error on the socket. */ close (zfpm_g->sock); zfpm_g->sock = -1; zfpm_start_connect_timer ("getsockopt() after async connect failed"); return; } /* * zfpm_conn_down_thread_cb * * Callback that is invoked to clean up state after the TCP connection * to the FPM goes down. */ static int zfpm_conn_down_thread_cb (struct thread *thread) { struct route_node *rnode; zfpm_rnodes_iter_t *iter; rib_dest_t *dest; assert (zfpm_g->state == ZFPM_STATE_IDLE); assert (zfpm_g->t_conn_down); zfpm_g->t_conn_down = NULL; iter = &zfpm_g->t_conn_down_state.iter; while ((rnode = zfpm_rnodes_iter_next (iter))) { dest = rib_dest_from_rnode (rnode); if (dest) { if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) { TAILQ_REMOVE (&zfpm_g->dest_q, dest, fpm_q_entries); } UNSET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); UNSET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); zfpm_g->stats.t_conn_down_dests_processed++; /* * Check if the dest should be deleted. */ rib_gc_dest(rnode); } /* * Yield if need be. */ if (!zfpm_thread_should_yield (thread)) continue; zfpm_g->stats.t_conn_down_yields++; zfpm_rnodes_iter_pause (iter); zfpm_g->t_conn_down = thread_add_background (zfpm_g->master, zfpm_conn_down_thread_cb, 0, 0); return 0; } zfpm_g->stats.t_conn_down_finishes++; zfpm_rnodes_iter_cleanup (iter); /* * Start the process of connecting to the FPM again. */ zfpm_start_connect_timer ("cleanup complete"); return 0; } /* * zfpm_connection_down * * Called when the connection to the FPM has gone down. */ static void zfpm_connection_down (const char *detail) { if (!detail) detail = "unknown"; assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); zlog_info ("connection to the FPM has gone down: %s", detail); zfpm_read_off (); zfpm_write_off (); stream_reset (zfpm_g->ibuf); stream_reset (zfpm_g->obuf); if (zfpm_g->sock >= 0) { close (zfpm_g->sock); zfpm_g->sock = -1; } /* * Start thread to clean up state after the connection goes down. */ assert (!zfpm_g->t_conn_down); zfpm_debug ("Starting conn_down thread"); zfpm_rnodes_iter_init (&zfpm_g->t_conn_down_state.iter); zfpm_g->t_conn_down = thread_add_background (zfpm_g->master, zfpm_conn_down_thread_cb, 0, 0); zfpm_g->stats.t_conn_down_starts++; zfpm_set_state (ZFPM_STATE_IDLE, detail); } /* * zfpm_read_cb */ static int zfpm_read_cb (struct thread *thread) { size_t already; struct stream *ibuf; uint16_t msg_len; fpm_msg_hdr_t *hdr; zfpm_g->stats.read_cb_calls++; assert (zfpm_g->t_read); zfpm_g->t_read = NULL; /* * Check if async connect is now done. */ if (zfpm_g->state == ZFPM_STATE_CONNECTING) { zfpm_connect_check(); return 0; } assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); assert (zfpm_g->sock >= 0); ibuf = zfpm_g->ibuf; already = stream_get_endp (ibuf); if (already < FPM_MSG_HDR_LEN) { ssize_t nbyte; nbyte = stream_read_try (ibuf, zfpm_g->sock, FPM_MSG_HDR_LEN - already); if (nbyte == 0 || nbyte == -1) { zfpm_connection_down ("closed socket in read"); return 0; } if (nbyte != (ssize_t) (FPM_MSG_HDR_LEN - already)) goto done; already = FPM_MSG_HDR_LEN; } stream_set_getp (ibuf, 0); hdr = (fpm_msg_hdr_t *) stream_pnt (ibuf); if (!fpm_msg_hdr_ok (hdr)) { zfpm_connection_down ("invalid message header"); return 0; } msg_len = fpm_msg_len (hdr); /* * Read out the rest of the packet. */ if (already < msg_len) { ssize_t nbyte; nbyte = stream_read_try (ibuf, zfpm_g->sock, msg_len - already); if (nbyte == 0 || nbyte == -1) { zfpm_connection_down ("failed to read message"); return 0; } if (nbyte != (ssize_t) (msg_len - already)) goto done; } zfpm_debug ("Read out a full fpm message"); /* * Just throw it away for now. */ stream_reset (ibuf); done: zfpm_read_on (); return 0; } /* * zfpm_writes_pending * * Returns TRUE if we may have something to write to the FPM. */ static int zfpm_writes_pending (void) { /* * Check if there is any data in the outbound buffer that has not * been written to the socket yet. */ if (stream_get_endp (zfpm_g->obuf) - stream_get_getp (zfpm_g->obuf)) return 1; /* * Check if there are any prefixes on the outbound queue. */ if (!TAILQ_EMPTY (&zfpm_g->dest_q)) return 1; return 0; } /* * zfpm_encode_route * * Encode a message to the FPM with information about the given route. * * Returns the number of bytes written to the buffer. 0 or a negative * value indicates an error. */ static inline int zfpm_encode_route (rib_dest_t *dest, struct rib *rib, char *in_buf, size_t in_buf_len, fpm_msg_type_e *msg_type) { size_t len; int cmd; len = 0; *msg_type = FPM_MSG_TYPE_NONE; switch (zfpm_g->message_format) { case ZFPM_MSG_FORMAT_PROTOBUF: #ifdef HAVE_PROTOBUF len = zfpm_protobuf_encode_route (dest, rib, (uint8_t *) in_buf, in_buf_len); *msg_type = FPM_MSG_TYPE_PROTOBUF; #endif break; case ZFPM_MSG_FORMAT_NETLINK: #ifdef HAVE_NETLINK *msg_type = FPM_MSG_TYPE_NETLINK; cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE; len = zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len); assert(fpm_msg_align(len) == len); *msg_type = FPM_MSG_TYPE_NETLINK; #endif /* HAVE_NETLINK */ break; default: break; } return len; } /* * zfpm_route_for_update * * Returns the rib that is to be sent to the FPM for a given dest. */ struct rib * zfpm_route_for_update (rib_dest_t *dest) { struct rib *rib; RIB_DEST_FOREACH_ROUTE (dest, rib) { if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; return rib; } /* * We have no route for this destination. */ return NULL; } /* * zfpm_build_updates * * Process the outgoing queue and write messages to the outbound * buffer. */ static void zfpm_build_updates (void) { struct stream *s; rib_dest_t *dest; unsigned char *buf, *data, *buf_end; size_t msg_len; size_t data_len; fpm_msg_hdr_t *hdr; struct rib *rib; int is_add, write_msg; fpm_msg_type_e msg_type; s = zfpm_g->obuf; assert (stream_empty (s)); do { /* * Make sure there is enough space to write another message. */ if (STREAM_WRITEABLE (s) < FPM_MAX_MSG_LEN) break; buf = STREAM_DATA (s) + stream_get_endp (s); buf_end = buf + STREAM_WRITEABLE (s); dest = TAILQ_FIRST (&zfpm_g->dest_q); if (!dest) break; assert (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)); hdr = (fpm_msg_hdr_t *) buf; hdr->version = FPM_PROTO_VERSION; data = fpm_msg_data (hdr); rib = zfpm_route_for_update (dest); is_add = rib ? 1 : 0; write_msg = 1; /* * If this is a route deletion, and we have not sent the route to * the FPM previously, skip it. */ if (!is_add && !CHECK_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM)) { write_msg = 0; zfpm_g->stats.nop_deletes_skipped++; } if (write_msg) { data_len = zfpm_encode_route (dest, rib, (char *) data, buf_end - data, &msg_type); assert (data_len); if (data_len) { hdr->msg_type = msg_type; msg_len = fpm_data_len_to_msg_len (data_len); hdr->msg_len = htons (msg_len); stream_forward_endp (s, msg_len); if (is_add) zfpm_g->stats.route_adds++; else zfpm_g->stats.route_dels++; } } /* * Remove the dest from the queue, and reset the flag. */ UNSET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); TAILQ_REMOVE (&zfpm_g->dest_q, dest, fpm_q_entries); if (is_add) { SET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); } else { UNSET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); } /* * Delete the destination if necessary. */ if (rib_gc_dest (dest->rnode)) zfpm_g->stats.dests_del_after_update++; } while (1); } /* * zfpm_write_cb */ static int zfpm_write_cb (struct thread *thread) { struct stream *s; int num_writes; zfpm_g->stats.write_cb_calls++; assert (zfpm_g->t_write); zfpm_g->t_write = NULL; /* * Check if async connect is now done. */ if (zfpm_g->state == ZFPM_STATE_CONNECTING) { zfpm_connect_check (); return 0; } assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); assert (zfpm_g->sock >= 0); num_writes = 0; do { int bytes_to_write, bytes_written; s = zfpm_g->obuf; /* * If the stream is empty, try fill it up with data. */ if (stream_empty (s)) { zfpm_build_updates (); } bytes_to_write = stream_get_endp (s) - stream_get_getp (s); if (!bytes_to_write) break; bytes_written = write (zfpm_g->sock, STREAM_PNT (s), bytes_to_write); zfpm_g->stats.write_calls++; num_writes++; if (bytes_written < 0) { if (ERRNO_IO_RETRY (errno)) break; zfpm_connection_down ("failed to write to socket"); return 0; } if (bytes_written != bytes_to_write) { /* * Partial write. */ stream_forward_getp (s, bytes_written); zfpm_g->stats.partial_writes++; break; } /* * We've written out the entire contents of the stream. */ stream_reset (s); if (num_writes >= ZFPM_MAX_WRITES_PER_RUN) { zfpm_g->stats.max_writes_hit++; break; } if (zfpm_thread_should_yield (thread)) { zfpm_g->stats.t_write_yields++; break; } } while (1); if (zfpm_writes_pending ()) zfpm_write_on (); return 0; } /* * zfpm_connect_cb */ static int zfpm_connect_cb (struct thread *t) { int sock, ret; struct sockaddr_in serv; assert (zfpm_g->t_connect); zfpm_g->t_connect = NULL; assert (zfpm_g->state == ZFPM_STATE_ACTIVE); sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { zfpm_debug ("Failed to create socket for connect(): %s", strerror(errno)); zfpm_g->stats.connect_no_sock++; return 0; } set_nonblocking(sock); /* Make server socket. */ memset (&serv, 0, sizeof (serv)); serv.sin_family = AF_INET; serv.sin_port = htons (zfpm_g->fpm_port); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN serv.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ if (!zfpm_g->fpm_server) serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); else serv.sin_addr.s_addr = (zfpm_g->fpm_server); /* * Connect to the FPM. */ zfpm_g->connect_calls++; zfpm_g->stats.connect_calls++; zfpm_g->last_connect_call_time = zfpm_get_time (); ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv)); if (ret >= 0) { zfpm_g->sock = sock; zfpm_connection_up ("connect succeeded"); return 1; } if (errno == EINPROGRESS) { zfpm_g->sock = sock; zfpm_read_on (); zfpm_write_on (); zfpm_set_state (ZFPM_STATE_CONNECTING, "async connect in progress"); return 0; } zlog_info ("can't connect to FPM %d: %s", sock, safe_strerror (errno)); close (sock); /* * Restart timer for retrying connection. */ zfpm_start_connect_timer ("connect() failed"); return 0; } /* * zfpm_set_state * * Move state machine into the given state. */ static void zfpm_set_state (zfpm_state_t state, const char *reason) { zfpm_state_t cur_state = zfpm_g->state; if (!reason) reason = "Unknown"; if (state == cur_state) return; zfpm_debug("beginning state transition %s -> %s. Reason: %s", zfpm_state_to_str (cur_state), zfpm_state_to_str (state), reason); switch (state) { case ZFPM_STATE_IDLE: assert (cur_state == ZFPM_STATE_ESTABLISHED); break; case ZFPM_STATE_ACTIVE: assert (cur_state == ZFPM_STATE_IDLE || cur_state == ZFPM_STATE_CONNECTING); assert (zfpm_g->t_connect); break; case ZFPM_STATE_CONNECTING: assert (zfpm_g->sock); assert (cur_state == ZFPM_STATE_ACTIVE); assert (zfpm_g->t_read); assert (zfpm_g->t_write); break; case ZFPM_STATE_ESTABLISHED: assert (cur_state == ZFPM_STATE_ACTIVE || cur_state == ZFPM_STATE_CONNECTING); assert (zfpm_g->sock); assert (zfpm_g->t_read); assert (zfpm_g->t_write); break; } zfpm_g->state = state; } /* * zfpm_calc_connect_delay * * Returns the number of seconds after which we should attempt to * reconnect to the FPM. */ static long zfpm_calc_connect_delay (void) { time_t elapsed; /* * Return 0 if this is our first attempt to connect. */ if (zfpm_g->connect_calls == 0) { return 0; } elapsed = zfpm_get_elapsed_time (zfpm_g->last_connect_call_time); if (elapsed > ZFPM_CONNECT_RETRY_IVL) { return 0; } return ZFPM_CONNECT_RETRY_IVL - elapsed; } /* * zfpm_start_connect_timer */ static void zfpm_start_connect_timer (const char *reason) { long delay_secs; assert (!zfpm_g->t_connect); assert (zfpm_g->sock < 0); assert(zfpm_g->state == ZFPM_STATE_IDLE || zfpm_g->state == ZFPM_STATE_ACTIVE || zfpm_g->state == ZFPM_STATE_CONNECTING); delay_secs = zfpm_calc_connect_delay(); zfpm_debug ("scheduling connect in %ld seconds", delay_secs); THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_connect, zfpm_connect_cb, 0, delay_secs); zfpm_set_state (ZFPM_STATE_ACTIVE, reason); } /* * zfpm_is_enabled * * Returns TRUE if the zebra FPM module has been enabled. */ static inline int zfpm_is_enabled (void) { return zfpm_g->enabled; } /* * zfpm_conn_is_up * * Returns TRUE if the connection to the FPM is up. */ static inline int zfpm_conn_is_up (void) { if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) return 0; assert (zfpm_g->sock >= 0); return 1; } /* * zfpm_trigger_update * * The zebra code invokes this function to indicate that we should * send an update to the FPM about the given route_node. */ void zfpm_trigger_update (struct route_node *rn, const char *reason) { rib_dest_t *dest; char buf[PREFIX_STRLEN]; /* * Ignore if the connection is down. We will update the FPM about * all destinations once the connection comes up. */ if (!zfpm_conn_is_up ()) return; dest = rib_dest_from_rnode (rn); /* * Ignore the trigger if the dest is not in a table that we would * send to the FPM. */ if (!zfpm_is_table_for_fpm (rib_dest_table (dest))) { zfpm_g->stats.non_fpm_table_triggers++; return; } if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) { zfpm_g->stats.redundant_triggers++; return; } if (reason) { zfpm_debug ("%s triggering update to FPM - Reason: %s", prefix2str (&rn->p, buf, sizeof(buf)), reason); } SET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); TAILQ_INSERT_TAIL (&zfpm_g->dest_q, dest, fpm_q_entries); zfpm_g->stats.updates_triggered++; /* * Make sure that writes are enabled. */ if (zfpm_g->t_write) return; zfpm_write_on (); } /* * zfpm_stats_timer_cb */ static int zfpm_stats_timer_cb (struct thread *t) { assert (zfpm_g->t_stats); zfpm_g->t_stats = NULL; /* * Remember the stats collected in the last interval for display * purposes. */ zfpm_stats_copy (&zfpm_g->stats, &zfpm_g->last_ivl_stats); /* * Add the current set of stats into the cumulative statistics. */ zfpm_stats_compose (&zfpm_g->cumulative_stats, &zfpm_g->stats, &zfpm_g->cumulative_stats); /* * Start collecting stats afresh over the next interval. */ zfpm_stats_reset (&zfpm_g->stats); zfpm_start_stats_timer (); return 0; } /* * zfpm_stop_stats_timer */ static void zfpm_stop_stats_timer (void) { if (!zfpm_g->t_stats) return; zfpm_debug ("Stopping existing stats timer"); THREAD_TIMER_OFF (zfpm_g->t_stats); } /* * zfpm_start_stats_timer */ void zfpm_start_stats_timer (void) { assert (!zfpm_g->t_stats); THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_stats, zfpm_stats_timer_cb, 0, ZFPM_STATS_IVL_SECS); } /* * Helper macro for zfpm_show_stats() below. */ #define ZFPM_SHOW_STAT(counter) \ do { \ vty_out (vty, "%-40s %10lu %16lu%s", #counter, total_stats.counter, \ zfpm_g->last_ivl_stats.counter, VTY_NEWLINE); \ } while (0) /* * zfpm_show_stats */ static void zfpm_show_stats (struct vty *vty) { zfpm_stats_t total_stats; time_t elapsed; vty_out (vty, "%s%-40s %10s Last %2d secs%s%s", VTY_NEWLINE, "Counter", "Total", ZFPM_STATS_IVL_SECS, VTY_NEWLINE, VTY_NEWLINE); /* * Compute the total stats up to this instant. */ zfpm_stats_compose (&zfpm_g->cumulative_stats, &zfpm_g->stats, &total_stats); ZFPM_SHOW_STAT (connect_calls); ZFPM_SHOW_STAT (connect_no_sock); ZFPM_SHOW_STAT (read_cb_calls); ZFPM_SHOW_STAT (write_cb_calls); ZFPM_SHOW_STAT (write_calls); ZFPM_SHOW_STAT (partial_writes); ZFPM_SHOW_STAT (max_writes_hit); ZFPM_SHOW_STAT (t_write_yields); ZFPM_SHOW_STAT (nop_deletes_skipped); ZFPM_SHOW_STAT (route_adds); ZFPM_SHOW_STAT (route_dels); ZFPM_SHOW_STAT (updates_triggered); ZFPM_SHOW_STAT (non_fpm_table_triggers); ZFPM_SHOW_STAT (redundant_triggers); ZFPM_SHOW_STAT (dests_del_after_update); ZFPM_SHOW_STAT (t_conn_down_starts); ZFPM_SHOW_STAT (t_conn_down_dests_processed); ZFPM_SHOW_STAT (t_conn_down_yields); ZFPM_SHOW_STAT (t_conn_down_finishes); ZFPM_SHOW_STAT (t_conn_up_starts); ZFPM_SHOW_STAT (t_conn_up_dests_processed); ZFPM_SHOW_STAT (t_conn_up_yields); ZFPM_SHOW_STAT (t_conn_up_aborts); ZFPM_SHOW_STAT (t_conn_up_finishes); if (!zfpm_g->last_stats_clear_time) return; elapsed = zfpm_get_elapsed_time (zfpm_g->last_stats_clear_time); vty_out (vty, "%sStats were cleared %lu seconds ago%s", VTY_NEWLINE, (unsigned long) elapsed, VTY_NEWLINE); } /* * zfpm_clear_stats */ static void zfpm_clear_stats (struct vty *vty) { if (!zfpm_is_enabled ()) { vty_out (vty, "The FPM module is not enabled...%s", VTY_NEWLINE); return; } zfpm_stats_reset (&zfpm_g->stats); zfpm_stats_reset (&zfpm_g->last_ivl_stats); zfpm_stats_reset (&zfpm_g->cumulative_stats); zfpm_stop_stats_timer (); zfpm_start_stats_timer (); zfpm_g->last_stats_clear_time = zfpm_get_time(); vty_out (vty, "Cleared FPM stats%s", VTY_NEWLINE); } /* * show_zebra_fpm_stats */ DEFUN (show_zebra_fpm_stats, show_zebra_fpm_stats_cmd, "show zebra fpm stats", SHOW_STR "Zebra information\n" "Forwarding Path Manager information\n" "Statistics\n") { zfpm_show_stats (vty); return CMD_SUCCESS; } /* * clear_zebra_fpm_stats */ DEFUN (clear_zebra_fpm_stats, clear_zebra_fpm_stats_cmd, "clear zebra fpm stats", CLEAR_STR "Zebra information\n" "Clear Forwarding Path Manager information\n" "Statistics\n") { zfpm_clear_stats (vty); return CMD_SUCCESS; } /* * update fpm connection information */ DEFUN ( fpm_remote_ip, fpm_remote_ip_cmd, "fpm connection ip A.B.C.D port <1-65535>", "fpm connection remote ip and port\n" "Remote fpm server ip A.B.C.D\n" "Enter ip ") { in_addr_t fpm_server; uint32_t port_no; fpm_server = inet_addr (argv[0]); if (fpm_server == INADDR_NONE) return CMD_ERR_INCOMPLETE; port_no = atoi (argv[1]); if (port_no < TCP_MIN_PORT || port_no > TCP_MAX_PORT) return CMD_ERR_INCOMPLETE; zfpm_g->fpm_server = fpm_server; zfpm_g->fpm_port = port_no; return CMD_SUCCESS; } DEFUN ( no_fpm_remote_ip, no_fpm_remote_ip_cmd, "no fpm connection ip A.B.C.D port <1-65535>", "fpm connection remote ip and port\n" "Connection\n" "Remote fpm server ip A.B.C.D\n" "Enter ip ") { if (zfpm_g->fpm_server != inet_addr (argv[0]) || zfpm_g->fpm_port != atoi (argv[1])) return CMD_ERR_NO_MATCH; zfpm_g->fpm_server = FPM_DEFAULT_IP; zfpm_g->fpm_port = FPM_DEFAULT_PORT; return CMD_SUCCESS; } /* * zfpm_init_message_format */ static inline void zfpm_init_message_format (const char *format) { int have_netlink, have_protobuf; have_netlink = have_protobuf = 0; #ifdef HAVE_NETLINK have_netlink = 1; #endif #ifdef HAVE_PROTOBUF have_protobuf = 1; #endif zfpm_g->message_format = ZFPM_MSG_FORMAT_NONE; if (!format) { if (have_netlink) { zfpm_g->message_format = ZFPM_MSG_FORMAT_NETLINK; } else if (have_protobuf) { zfpm_g->message_format = ZFPM_MSG_FORMAT_PROTOBUF; } return; } if (!strcmp ("netlink", format)) { if (!have_netlink) { zlog_err ("FPM netlink message format is not available"); return; } zfpm_g->message_format = ZFPM_MSG_FORMAT_NETLINK; return; } if (!strcmp ("protobuf", format)) { if (!have_protobuf) { zlog_err ("FPM protobuf message format is not available"); return; } zfpm_g->message_format = ZFPM_MSG_FORMAT_PROTOBUF; return; } zlog_warn ("Unknown fpm format '%s'", format); } /** * fpm_remote_srv_write * * Module to write remote fpm connection * * Returns ZERO on success. */ int fpm_remote_srv_write (struct vty *vty ) { struct in_addr in; in.s_addr = zfpm_g->fpm_server; if (zfpm_g->fpm_server != FPM_DEFAULT_IP || zfpm_g->fpm_port != FPM_DEFAULT_PORT) vty_out (vty,"fpm connection ip %s port %d%s", inet_ntoa (in),zfpm_g->fpm_port,VTY_NEWLINE); return 0; } /** * zfpm_init * * One-time initialization of the Zebra FPM module. * * @param[in] port port at which FPM is running. * @param[in] enable TRUE if the zebra FPM module should be enabled * @param[in] format to use to talk to the FPM. Can be 'netink' or 'protobuf'. * * Returns TRUE on success. */ int zfpm_init (struct thread_master *master, int enable, uint16_t port, const char *format) { static int initialized = 0; if (initialized) { return 1; } initialized = 1; memset (zfpm_g, 0, sizeof (*zfpm_g)); zfpm_g->master = master; TAILQ_INIT(&zfpm_g->dest_q); zfpm_g->sock = -1; zfpm_g->state = ZFPM_STATE_IDLE; zfpm_stats_init (&zfpm_g->stats); zfpm_stats_init (&zfpm_g->last_ivl_stats); zfpm_stats_init (&zfpm_g->cumulative_stats); install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd); install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd); install_element (CONFIG_NODE, &fpm_remote_ip_cmd); install_element (CONFIG_NODE, &no_fpm_remote_ip_cmd); zfpm_init_message_format(format); /* * Disable FPM interface if no suitable format is available. */ if (zfpm_g->message_format == ZFPM_MSG_FORMAT_NONE) enable = 0; zfpm_g->enabled = enable; if (!enable) { return 1; } if (!zfpm_g->fpm_server) zfpm_g->fpm_server = FPM_DEFAULT_IP; if (!port) port = FPM_DEFAULT_PORT; zfpm_g->fpm_port = port; zfpm_g->obuf = stream_new (ZFPM_OBUF_SIZE); zfpm_g->ibuf = stream_new (ZFPM_IBUF_SIZE); zfpm_start_stats_timer (); zfpm_start_connect_timer ("initialized"); return 1; } quagga-1.2.4/zebra/zebra_fpm.h000066400000000000000000000023051325323223500162040ustar00rootroot00000000000000/* * Header file exported by the zebra FPM module to zebra. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_FPM_H #define _ZEBRA_FPM_H /* * Externs. */ extern int zfpm_init (struct thread_master *master, int enable, uint16_t port, const char *message_format); extern void zfpm_trigger_update (struct route_node *rn, const char *reason); #endif /* _ZEBRA_FPM_H */ quagga-1.2.4/zebra/zebra_fpm_dt.c000066400000000000000000000136241325323223500166740ustar00rootroot00000000000000/* * zebra_fpm_dt.c * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Developer tests for the zebra code that interfaces with the * forwarding plane manager. * * The functions here are built into developer builds of zebra (when * DEV_BUILD is defined), and can be called via the 'invoke' cli * command. * * For example: * * # invoke zebra function zfpm_dt_benchmark_protobuf_encode 100000 * */ #include #include "log.h" #include "vrf.h" #include "zebra/rib.h" #include "zebra_fpm_private.h" #include "qpb/qpb_allocator.h" #include "qpb/linear_allocator.h" #include "qpb/qpb.h" #include "fpm/fpm.pb-c.h" /* * Externs. */ extern int zfpm_dt_benchmark_netlink_encode (int argc, const char **argv); extern int zfpm_dt_benchmark_protobuf_encode (int argc, const char **argv); extern int zfpm_dt_benchmark_protobuf_decode (int argc, const char **argv); /* * zfpm_dt_find_route * * Selects a suitable rib destination for fpm interface tests. */ static int zfpm_dt_find_route (rib_dest_t **dest_p, struct rib **rib_p) { struct route_node *rnode; route_table_iter_t iter; struct route_table *table; rib_dest_t *dest; struct rib *rib; int ret; table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (!table) return 0; route_table_iter_init(&iter, table); while ((rnode = route_table_iter_next(&iter))) { dest = rib_dest_from_rnode (rnode); if (!dest) continue; rib = zfpm_route_for_update(dest); if (!rib) continue; if (rib->nexthop_active_num <= 0) continue; *dest_p = dest; *rib_p = rib; ret = 1; goto done; } ret = 0; done: route_table_iter_cleanup(&iter); return ret; } #ifdef HAVE_NETLINK /* * zfpm_dt_benchmark_netlink_encode */ int zfpm_dt_benchmark_netlink_encode (int argc, const char **argv) { int times, i, len; rib_dest_t *dest; struct rib *rib; char buf[4096]; times = 100000; if (argc > 0) { times = atoi(argv[0]); } if (!zfpm_dt_find_route(&dest, &rib)) { return 1; } for (i = 0; i < times; i++) { len = zfpm_netlink_encode_route(RTM_NEWROUTE, dest, rib, buf, sizeof(buf)); if (len <= 0) { return 2; } } return 0; } #endif /* HAVE_NETLINK */ #ifdef HAVE_PROTOBUF /* * zfpm_dt_benchmark_protobuf_encode */ int zfpm_dt_benchmark_protobuf_encode (int argc, const char **argv) { int times, i, len; rib_dest_t *dest; struct rib *rib; uint8_t buf[4096]; times = 100000; if (argc > 0) { times = atoi(argv[0]); } if (!zfpm_dt_find_route(&dest, &rib)) { return 1; } for (i = 0; i < times; i++) { len = zfpm_protobuf_encode_route(dest, rib, buf, sizeof(buf)); if (len <= 0) { return 2; } } return 0; } /* * zfpm_dt_log_fpm_message */ static void zfpm_dt_log_fpm_message (Fpm__Message *msg) { Fpm__AddRoute *add_route; Fpm__Nexthop *nexthop; struct prefix prefix; u_char family, nh_family; uint if_index; char *if_name; size_t i; char buf[INET6_ADDRSTRLEN]; union g_addr nh_addr; if (msg->type != FPM__MESSAGE__TYPE__ADD_ROUTE) return; zfpm_debug ("Add route message"); add_route = msg->add_route; if (!qpb_address_family_get (add_route->address_family, &family)) return; if (!qpb_l3_prefix_get (add_route->key->prefix, family, &prefix)) return; zfpm_debug ("Vrf id: %d, Prefix: %s/%d, Metric: %d", add_route->vrf_id, inet_ntop (family, &prefix.u.prefix, buf, sizeof (buf)), prefix.prefixlen, add_route->metric); /* * Go over nexthops. */ for (i = 0; i < add_route->n_nexthops; i++) { nexthop = add_route->nexthops[i]; if (!qpb_if_identifier_get (nexthop->if_id, &if_index, &if_name)) continue; if (nexthop->address) qpb_l3_address_get (nexthop->address, &nh_family, &nh_addr); zfpm_debug ("Nexthop - if_index: %d (%s), gateway: %s, ", if_index, if_name ? if_name : "name not specified", nexthop->address ? inet_ntoa (nh_addr.ipv4) : "None"); } } /* * zfpm_dt_benchmark_protobuf_decode */ int zfpm_dt_benchmark_protobuf_decode (int argc, const char **argv) { int times, i, len; rib_dest_t *dest; struct rib *rib; uint8_t msg_buf[4096]; QPB_DECLARE_STACK_ALLOCATOR (allocator, 8192); Fpm__Message *fpm_msg; QPB_INIT_STACK_ALLOCATOR (allocator); times = 100000; if (argc > 0) times = atoi(argv[0]); if (!zfpm_dt_find_route (&dest, &rib)) return 1; /* * Encode the route into the message buffer once only. */ len = zfpm_protobuf_encode_route (dest, rib, msg_buf, sizeof (msg_buf)); if (len <= 0) return 2; // Decode once, and display the decoded message fpm_msg = fpm__message__unpack(&allocator, len, msg_buf); if (fpm_msg) { zfpm_dt_log_fpm_message(fpm_msg); QPB_RESET_STACK_ALLOCATOR (allocator); } /* * Decode encoded message the specified number of times. */ for (i = 0; i < times; i++) { fpm_msg = fpm__message__unpack (&allocator, len, msg_buf); if (!fpm_msg) return 3; // fpm__message__free_unpacked(msg, NULL); QPB_RESET_STACK_ALLOCATOR (allocator); } return 0; } #endif /* HAVE_PROTOBUF */ quagga-1.2.4/zebra/zebra_fpm_netlink.c000066400000000000000000000247561325323223500177410ustar00rootroot00000000000000/* * Code for encoding/decoding FPM messages that are in netlink format. * * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "rib.h" #include "rt_netlink.h" #include "nexthop.h" #include "zebra_fpm_private.h" /* * addr_to_a * * Returns string representation of an address of the given AF. */ static inline const char * addr_to_a (u_char af, void *addr) { if (!addr) return ""; switch (af) { case AF_INET: return inet_ntoa (*((struct in_addr *) addr)); #ifdef HAVE_IPV6 case AF_INET6: return inet6_ntoa (*((struct in6_addr *) addr)); #endif default: return ""; } } /* * prefix_addr_to_a * * Convience wrapper that returns a human-readable string for the * address in a prefix. */ static const char * prefix_addr_to_a (struct prefix *prefix) { if (!prefix) return ""; return addr_to_a (prefix->family, &prefix->u.prefix); } /* * af_addr_size * * The size of an address in a given address family. */ static size_t af_addr_size (u_char af) { switch (af) { case AF_INET: return 4; #ifdef HAVE_IPV6 case AF_INET6: return 16; #endif default: assert(0); return 16; } } /* * netlink_nh_info_t * * Holds information about a single nexthop for netlink. These info * structures are transient and may contain pointers into rib * data structures for convenience. */ typedef struct netlink_nh_info_t_ { uint32_t if_index; union g_addr *gateway; /* * Information from the struct nexthop from which this nh was * derived. For debug purposes only. */ int recursive; enum nexthop_types_t type; } netlink_nh_info_t; /* * netlink_route_info_t * * A structure for holding information for a netlink route message. */ typedef struct netlink_route_info_t_ { uint16_t nlmsg_type; u_char rtm_type; uint32_t rtm_table; u_char rtm_protocol; u_char af; struct prefix *prefix; uint32_t *metric; int num_nhs; /* * Nexthop structures */ netlink_nh_info_t nhs[MULTIPATH_NUM]; union g_addr *pref_src; } netlink_route_info_t; /* * netlink_route_info_add_nh * * Add information about the given nexthop to the given route info * structure. * * Returns TRUE if a nexthop was added, FALSE otherwise. */ static int netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop, int recursive) { netlink_nh_info_t nhi; union g_addr *src; memset (&nhi, 0, sizeof (nhi)); src = NULL; if (ri->num_nhs >= (int) ZEBRA_NUM_OF (ri->nhs)) return 0; nhi.recursive = recursive; nhi.type = nexthop->type; nhi.if_index = nexthop->ifindex; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { nhi.gateway = &nexthop->gate; if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } #ifdef HAVE_IPV6 if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { nhi.gateway = &nexthop->gate; } #endif /* HAVE_IPV6 */ if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) { if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } if (!nhi.gateway && nhi.if_index == 0) return 0; /* * We have a valid nhi. Copy the structure over to the route_info. */ ri->nhs[ri->num_nhs] = nhi; ri->num_nhs++; if (src && !ri->pref_src) ri->pref_src = src; return 1; } /* * netlink_proto_from_route_type */ static u_char netlink_proto_from_route_type (int type) { switch (type) { case ZEBRA_ROUTE_KERNEL: case ZEBRA_ROUTE_CONNECT: return RTPROT_KERNEL; default: return RTPROT_ZEBRA; } } /* * netlink_route_info_fill * * Fill out the route information object from the given route. * * Returns TRUE on success and FALSE on failure. */ static int netlink_route_info_fill (netlink_route_info_t *ri, int cmd, rib_dest_t *dest, struct rib *rib) { struct nexthop *nexthop, *tnexthop; int recursing; int discard; memset (ri, 0, sizeof (*ri)); ri->prefix = rib_dest_prefix (dest); ri->af = rib_dest_af (dest); ri->nlmsg_type = cmd; ri->rtm_table = rib_dest_vrf (dest)->vrf_id; ri->rtm_protocol = RTPROT_UNSPEC; /* * An RTM_DELROUTE need not be accompanied by any nexthops, * particularly in our communication with the FPM. */ if (cmd == RTM_DELROUTE) goto skip; if (!rib) { zlog_err("netlink_route_info_fill RTM_ADDROUTE called without rib info"); return 0; } ri->rtm_protocol = netlink_proto_from_route_type (rib->type); if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) discard = 1; else discard = 0; if (cmd == RTM_NEWROUTE) { if (discard) { if (rib->flags & ZEBRA_FLAG_BLACKHOLE) ri->rtm_type = RTN_BLACKHOLE; else if (rib->flags & ZEBRA_FLAG_REJECT) ri->rtm_type = RTN_UNREACHABLE; else assert (0); } else ri->rtm_type = RTN_UNICAST; } ri->metric = &rib->metric; if (discard) { goto skip; } for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (ri->num_nhs >= MULTIPATH_NUM) break; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { netlink_route_info_add_nh (ri, nexthop, recursing); } } /* If there is no useful nexthop then return. */ if (ri->num_nhs == 0) { zfpm_debug ("netlink_encode_route(): No useful nexthop."); return 0; } skip: return 1; } /* * netlink_route_info_encode * * Returns the number of bytes written to the buffer. 0 or a negative * value indicates an error. */ static int netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf, size_t in_buf_len) { size_t bytelen; int nexthop_num = 0; size_t buf_offset; netlink_nh_info_t *nhi; struct { struct nlmsghdr n; struct rtmsg r; char buf[1]; } *req; req = (void *) in_buf; buf_offset = ((char *) req->buf) - ((char *) req); if (in_buf_len < buf_offset) { assert(0); return 0; } memset (req, 0, buf_offset); bytelen = af_addr_size (ri->af); req->n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req->n.nlmsg_type = ri->nlmsg_type; req->r.rtm_family = ri->af; req->r.rtm_table = ri->rtm_table; req->r.rtm_dst_len = ri->prefix->prefixlen; req->r.rtm_protocol = ri->rtm_protocol; req->r.rtm_scope = RT_SCOPE_UNIVERSE; addattr_l (&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, bytelen); req->r.rtm_type = ri->rtm_type; /* Metric. */ if (ri->metric) addattr32 (&req->n, in_buf_len, RTA_PRIORITY, *ri->metric); if (ri->num_nhs == 0) goto done; if (ri->num_nhs == 1) { nhi = &ri->nhs[0]; if (nhi->gateway) { addattr_l (&req->n, in_buf_len, RTA_GATEWAY, nhi->gateway, bytelen); } if (nhi->if_index) { addattr32 (&req->n, in_buf_len, RTA_OIF, nhi->if_index); } goto done; } /* * Multipath case. */ char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *) buf; struct rtnexthop *rtnh; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH (0); rtnh = RTA_DATA (rta); for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++) { nhi = &ri->nhs[nexthop_num]; rtnh->rtnh_len = sizeof (*rtnh); rtnh->rtnh_flags = 0; rtnh->rtnh_hops = 0; rtnh->rtnh_ifindex = 0; rta->rta_len += rtnh->rtnh_len; if (nhi->gateway) { rta_addattr_l (rta, sizeof (buf), RTA_GATEWAY, nhi->gateway, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; } if (nhi->if_index) { rtnh->rtnh_ifindex = nhi->if_index; } rtnh = RTNH_NEXT (rtnh); } assert (rta->rta_len > RTA_LENGTH (0)); addattr_l (&req->n, in_buf_len, RTA_MULTIPATH, RTA_DATA (rta), RTA_PAYLOAD (rta)); done: if (ri->pref_src) { addattr_l (&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, bytelen); } assert (req->n.nlmsg_len < in_buf_len); return req->n.nlmsg_len; } /* * zfpm_log_route_info * * Helper function to log the information in a route_info structure. */ static void zfpm_log_route_info (netlink_route_info_t *ri, const char *label) { netlink_nh_info_t *nhi; int i; zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label, nl_msg_type_to_str (ri->nlmsg_type), prefix_addr_to_a (ri->prefix), ri->prefix->prefixlen, nl_rtproto_to_str (ri->rtm_protocol), ri->metric ? *ri->metric : 0); for (i = 0; i < ri->num_nhs; i++) { nhi = &ri->nhs[i]; zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s", nhi->if_index, addr_to_a (ri->af, nhi->gateway), nhi->recursive ? "yes" : "no", nexthop_type_to_str (nhi->type)); } } /* * zfpm_netlink_encode_route * * Create a netlink message corresponding to the given route in the * given buffer space. * * Returns the number of bytes written to the buffer. 0 or a negative * value indicates an error. */ int zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib, char *in_buf, size_t in_buf_len) { netlink_route_info_t ri_space, *ri; ri = &ri_space; if (!netlink_route_info_fill (ri, cmd, dest, rib)) return 0; zfpm_log_route_info (ri, __FUNCTION__); return netlink_route_info_encode (ri, in_buf, in_buf_len); } quagga-1.2.4/zebra/zebra_fpm_private.h000066400000000000000000000033651325323223500177450ustar00rootroot00000000000000/* * Private header file for the zebra FPM module. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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_FPM_PRIVATE_H #define _ZEBRA_FPM_PRIVATE_H #include "zebra/debug.h" #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define zfpm_debug(...) \ do { \ if (IS_ZEBRA_DEBUG_FPM) zlog_debug("FPM: " __VA_ARGS__); \ } while(0) #elif defined __GNUC__ #define zfpm_debug(_args...) \ do { \ if (IS_ZEBRA_DEBUG_FPM) zlog_debug("FPM: " _args); \ } while(0) #else static inline void zfpm_debug(const char *format, ...) { return; } #endif /* * Externs */ extern int zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib, char *in_buf, size_t in_buf_len); extern int zfpm_protobuf_encode_route (rib_dest_t *dest, struct rib *rib, uint8_t *in_buf, size_t in_buf_len); extern struct rib *zfpm_route_for_update (rib_dest_t *dest); #endif /* _ZEBRA_FPM_PRIVATE_H */ quagga-1.2.4/zebra/zebra_fpm_protobuf.c000066400000000000000000000153511325323223500201240ustar00rootroot00000000000000/* * zebra_fpm_protobuf.c * * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; 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 "rib.h" #include "qpb/qpb.pb-c.h" #include "qpb/qpb.h" #include "qpb/qpb_allocator.h" #include "qpb/linear_allocator.h" #include "fpm/fpm_pb.h" #include "zebra_fpm_private.h" /* * create_delete_route_message */ static Fpm__DeleteRoute * create_delete_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, struct rib *rib) { Fpm__DeleteRoute *msg; msg = QPB_ALLOC(allocator, typeof(*msg)); if (!msg) { assert(0); return NULL; } fpm__delete_route__init(msg); msg->vrf_id = rib_dest_vrf(dest)->vrf_id; qpb_address_family_set(&msg->address_family, rib_dest_af(dest)); /* * XXX Hardcode subaddress family for now. */ msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST; msg->key = fpm_route_key_create (allocator, rib_dest_prefix(dest)); if (!msg->key) { assert(0); return NULL; } return msg; } /* * add_nexthop */ static inline int add_nexthop (qpb_allocator_t *allocator, Fpm__AddRoute *msg, rib_dest_t *dest, struct nexthop *nexthop) { uint32_t if_index; union g_addr *gateway, *src; gateway = src = NULL; if_index = nexthop->ifindex; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { gateway = &nexthop->gate; if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { gateway = &nexthop->gate; } if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) { if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } if (!gateway && if_index == 0) return 0; /* * We have a valid nexthop. */ { Fpm__Nexthop *pb_nh; pb_nh = QPB_ALLOC(allocator, typeof(*pb_nh)); if (!pb_nh) { assert(0); return 0; } fpm__nexthop__init(pb_nh); if (if_index != 0) { pb_nh->if_id = qpb_if_identifier_create (allocator, if_index); } if (gateway) { pb_nh->address = qpb_l3_address_create (allocator, gateway, rib_dest_af(dest)); } msg->nexthops[msg->n_nexthops++] = pb_nh; } // TODO: Use src. return 1; } /* * create_add_route_message */ static Fpm__AddRoute * create_add_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, struct rib *rib) { Fpm__AddRoute *msg; int discard; struct nexthop *nexthop, *tnexthop; int recursing; uint num_nhs, u; struct nexthop *nexthops[MAX (MULTIPATH_NUM, 64)]; msg = QPB_ALLOC(allocator, typeof(*msg)); if (!msg) { assert(0); return NULL; } fpm__add_route__init(msg); msg->vrf_id = rib_dest_vrf(dest)->vrf_id; qpb_address_family_set (&msg->address_family, rib_dest_af(dest)); /* * XXX Hardcode subaddress family for now. */ msg->sub_address_family = QPB__SUB_ADDRESS_FAMILY__UNICAST; msg->key = fpm_route_key_create (allocator, rib_dest_prefix(dest)); qpb_protocol_set (&msg->protocol, rib->type); if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) discard = 1; else discard = 0; if (discard) { if (rib->flags & ZEBRA_FLAG_BLACKHOLE) { msg->route_type = FPM__ROUTE_TYPE__BLACKHOLE; } else if (rib->flags & ZEBRA_FLAG_REJECT) { msg->route_type = FPM__ROUTE_TYPE__UNREACHABLE; } else { assert (0); } return msg; } else { msg->route_type = FPM__ROUTE_TYPE__NORMAL; } msg->metric = rib->metric; /* * Figure out the set of nexthops to be added to the message. */ num_nhs = 0; for (ALL_NEXTHOPS_RO (rib->nexthop, nexthop, tnexthop, recursing)) { if (MULTIPATH_NUM != 0 && num_nhs >= MULTIPATH_NUM) break; if (num_nhs >= ZEBRA_NUM_OF(nexthops)) break; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; nexthops[num_nhs] = nexthop; num_nhs++; } if (!num_nhs) { zfpm_debug ("netlink_encode_route(): No useful nexthop."); assert(0); return NULL; } /* * And add them to the message. */ if (!(msg->nexthops = qpb_alloc_ptr_array(allocator, num_nhs))) { assert(0); return NULL; } msg->n_nexthops = 0; for (u = 0; u < num_nhs; u++) { if (!add_nexthop(allocator, msg, dest, nexthops[u])) { assert(0); return NULL; } } assert(msg->n_nexthops == num_nhs); return msg; } /* * create_route_message */ static Fpm__Message * create_route_message (qpb_allocator_t *allocator, rib_dest_t *dest, struct rib *rib) { Fpm__Message *msg; msg = QPB_ALLOC(allocator, typeof(*msg)); if (!msg) { assert(0); return NULL; } fpm__message__init(msg); if (!rib) { msg->type = FPM__MESSAGE__TYPE__DELETE_ROUTE; msg->delete_route = create_delete_route_message(allocator, dest, rib); if (!msg->delete_route) { assert(0); return NULL; } return msg; } msg->type = FPM__MESSAGE__TYPE__ADD_ROUTE; msg->add_route = create_add_route_message(allocator, dest, rib); if (!msg->add_route) { assert(0); return NULL; } return msg; } /* * zfpm_protobuf_encode_route * * Create a protobuf message corresponding to the given route in the * given buffer space. * * Returns the number of bytes written to the buffer. 0 or a negative * value indicates an error. */ int zfpm_protobuf_encode_route (rib_dest_t *dest, struct rib *rib, uint8_t *in_buf, size_t in_buf_len) { Fpm__Message *msg; QPB_DECLARE_STACK_ALLOCATOR (allocator, 4096); size_t len; QPB_INIT_STACK_ALLOCATOR (allocator); msg = create_route_message(&allocator, dest, rib); if (!msg) { assert(0); return 0; } len = fpm__message__pack(msg, (uint8_t *) in_buf); assert(len <= in_buf_len); QPB_RESET_STACK_ALLOCATOR (allocator); return len; } quagga-1.2.4/zebra/zebra_rib.c000066400000000000000000002476111325323223500162040ustar00rootroot00000000000000/* 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 "linklist.h" #include "thread.h" #include "workqueue.h" #include "prefix.h" #include "routemap.h" #include "vrf.h" #include "nexthop.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_fpm.h" #include "zebra/zebra_rnh.h" /* Default rtm_table for all clients */ extern struct zebra_t zebrad; /* Hold time for RIB process, should be very minimal. * it is useful to able to set it otherwise for testing, hence exported * as global here for test-rig code. */ int rib_process_hold_time = 10; /* Each route type's string and default distance value. */ static const struct { int key; int distance; } route_info[ZEBRA_ROUTE_MAX] = { [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0}, [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0}, [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0}, [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1}, [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120}, [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120}, [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110}, [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110}, [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115}, [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */}, [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95}, [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10}, /* no entry/default: 150 */ }; /* RPF lookup behaviour */ static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG; static void __attribute__((format (printf, 4, 5))) _rnode_zlog(const char *_func, struct route_node *rn, int priority, const char *msgfmt, ...) { char prefix[PREFIX_STRLEN], buf[256]; char msgbuf[512]; va_list ap; va_start(ap, msgfmt); vsnprintf(msgbuf, sizeof(msgbuf), msgfmt, ap); va_end(ap); if (rn) { rib_table_info_t *info = rn->table->info; snprintf(buf, sizeof(buf), "%s%s vrf %u", prefix2str(&rn->p, prefix, sizeof(prefix)), info->safi == SAFI_MULTICAST ? " (MRIB)" : "", info->zvrf->vrf_id); } else { snprintf(buf, sizeof(buf), "{(route_node *) NULL}"); } zlog (NULL, priority, "%s: %s: %s", _func, buf, msgbuf); } #define rnode_debug(node, ...) \ _rnode_zlog(__func__, node, LOG_DEBUG, __VA_ARGS__) #define rnode_info(node, ...) \ _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__) /* Add nexthop to the end of a rib node's nexthop list */ void rib_nexthop_add (struct rib *rib, struct nexthop *nexthop) { nexthop_add(&rib->nexthop, nexthop); rib->nexthop_num++; } /* Delete specified nexthop from the list. */ static void rib_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--; } struct nexthop * rib_nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) { struct nexthop *nexthop; nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IFINDEX; nexthop->ifindex = ifindex; rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * rib_nexthop_ifname_add (struct rib *rib, char *ifname) { struct nexthop *nexthop; nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IFNAME; nexthop->ifname = XSTRDUP (MTYPE_TMP, ifname); rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * rib_nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) { struct nexthop *nexthop; nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV4; nexthop->gate.ipv4 = *ipv4; if (src) nexthop->src.ipv4 = *src; rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * rib_nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src, ifindex_t ifindex) { struct nexthop *nexthop; nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; nexthop->gate.ipv4 = *ipv4; if (src) nexthop->src.ipv4 = *src; nexthop->ifindex = ifindex; rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * rib_nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) { struct nexthop *nexthop; nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6; nexthop->gate.ipv6 = *ipv6; rib_nexthop_add (rib, nexthop); return nexthop; } static struct nexthop * rib_nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, char *ifname) { struct nexthop *nexthop; nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME; nexthop->gate.ipv6 = *ipv6; nexthop->ifname = XSTRDUP (MTYPE_TMP, ifname); rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * rib_nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, ifindex_t ifindex) { struct nexthop *nexthop; nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; rib_nexthop_add (rib, nexthop); return nexthop; } struct nexthop * rib_nexthop_blackhole_add (struct rib *rib) { struct nexthop *nexthop; nexthop = nexthop_new (); nexthop->type = NEXTHOP_TYPE_BLACKHOLE; SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE); rib_nexthop_add (rib, nexthop); return nexthop; } /* This method checks whether a recursive nexthop has at * least one resolved nexthop in the fib. */ int nexthop_has_fib_child(struct nexthop *nexthop) { struct nexthop *nh; if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) return 0; for (nh = nexthop->resolved; nh; nh = nh->next) if (CHECK_FLAG (nh->flags, NEXTHOP_FLAG_FIB)) return 1; return 0; } /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ static 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; int resolved; struct nexthop *newhop; struct nexthop *resolved_hop; if (nexthop->type == NEXTHOP_TYPE_IPV4) nexthop->ifindex = 0; if (set) { UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; rib->nexthop_mtu = 0; } /* 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 = zebra_vrf_table (AFI_IP, SAFI_UNICAST, rib->vrf_id); if (! table) return 0; rn = route_node_match (table, (struct prefix *) &p); while (rn) { route_unlock_node (rn); /* If lookup self prefix return immediately. */ if (rn == top) return 0; /* Pick up selected route. */ RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) 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 the longest prefix match for the nexthop yields * a blackhole, mark it as inactive. */ if (CHECK_FLAG (match->flags, ZEBRA_FLAG_BLACKHOLE) || CHECK_FLAG (match->flags, ZEBRA_FLAG_REJECT)) return 0; 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)) { resolved = 0; 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); resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); /* If the resolving route specifies a gateway, use it */ if (newhop->type == NEXTHOP_TYPE_IPV4 || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX || newhop->type == NEXTHOP_TYPE_IPV4_IFNAME) { resolved_hop->type = newhop->type; resolved_hop->gate.ipv4 = newhop->gate.ipv4; resolved_hop->ifindex = newhop->ifindex; } /* If the resolving route is an interface route, it * means the gateway we are looking up is connected * to that interface. Therefore, the resolved route * should have the original gateway as nexthop as it * is directly connected. */ if (newhop->type == NEXTHOP_TYPE_IFINDEX || newhop->type == NEXTHOP_TYPE_IFNAME) { resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX; resolved_hop->gate.ipv4 = nexthop->gate.ipv4; resolved_hop->ifindex = newhop->ifindex; } nexthop_add(&nexthop->resolved, resolved_hop); } resolved = 1; } if (resolved && set) rib->nexthop_mtu = match->mtu; return resolved; } else { return 0; } } } return 0; } /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ static 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; int resolved; struct nexthop *newhop; struct nexthop *resolved_hop; if (nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = 0; if (set) { UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; } /* 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 = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, rib->vrf_id); if (! table) return 0; rn = route_node_match (table, (struct prefix *) &p); while (rn) { route_unlock_node (rn); /* If lookup self prefix return immediately. */ if (rn == top) return 0; /* Pick up selected route. */ RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) 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 the longest prefix match for the nexthop yields * a blackhole, mark it as inactive. */ if (CHECK_FLAG (match->flags, ZEBRA_FLAG_BLACKHOLE) || CHECK_FLAG (match->flags, ZEBRA_FLAG_REJECT)) return 0; 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)) { resolved = 0; 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); resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); /* See nexthop_active_ipv4 for a description how the * resolved nexthop is constructed. */ if (newhop->type == NEXTHOP_TYPE_IPV6 || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) { resolved_hop->type = newhop->type; resolved_hop->gate.ipv6 = newhop->gate.ipv6; if (newhop->ifindex) { resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; resolved_hop->ifindex = newhop->ifindex; } } if (newhop->type == NEXTHOP_TYPE_IFINDEX || newhop->type == NEXTHOP_TYPE_IFNAME) { resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; resolved_hop->gate.ipv6 = nexthop->gate.ipv6; resolved_hop->ifindex = newhop->ifindex; } nexthop_add(&nexthop->resolved, resolved_hop); } resolved = 1; } return resolved; } else { return 0; } } } return 0; } struct rib * rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, struct route_node **rn_out, vrf_id_t vrf_id) { struct route_table *table; struct route_node *rn; struct rib *match; struct nexthop *newhop, *tnewhop; int recursing; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return 0; rn = route_node_match_ipv4 (table, &addr); while (rn) { route_unlock_node (rn); /* Pick up selected route. */ RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } /* If there is no selected route or matched route is EGP, go up tree. */ if (!match || (skip_bgp && (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) { int found = 0; for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) { found = 1; break; } if (!found) return NULL; } if (rn_out) *rn_out = rn; return match; } } return NULL; } struct rib * rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, vrf_id_t vrf_id) { struct rib *rib = NULL, *mrib = NULL, *urib = NULL; struct route_node *m_rn = NULL, *u_rn = NULL; int skip_bgp = 0; /* bool */ switch (ipv4_multicast_mode) { case MCAST_MRIB_ONLY: return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out, vrf_id); case MCAST_URIB_ONLY: return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out, vrf_id); case MCAST_NO_CONFIG: case MCAST_MIX_MRIB_FIRST: rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, vrf_id); if (!mrib) rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, vrf_id); break; case MCAST_MIX_DISTANCE: mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, vrf_id); urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, vrf_id); if (mrib && urib) rib = urib->distance < mrib->distance ? urib : mrib; else if (mrib) rib = mrib; else if (urib) rib = urib; break; case MCAST_MIX_PFXLEN: mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn, vrf_id); urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn, vrf_id); if (mrib && urib) rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; else if (mrib) rib = mrib; else if (urib) rib = urib; break; } if (rn_out) *rn_out = (rib == mrib) ? m_rn : u_rn; if (IS_ZEBRA_DEBUG_RIB) { char buf[BUFSIZ]; inet_ntop (AF_INET, &addr, buf, BUFSIZ); zlog_debug("%s: %s vrf %u: found %s, using %s", __func__, buf, vrf_id, mrib ? (urib ? "MRIB+URIB" : "MRIB") : urib ? "URIB" : "nothing", rib == urib ? "URIB" : rib == mrib ? "MRIB" : "none"); } return rib; } void multicast_mode_ipv4_set (enum multicast_mode mode) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug("%s: multicast lookup mode set (%d)", __func__, mode); ipv4_multicast_mode = mode; } enum multicast_mode multicast_mode_ipv4_get (void) { return ipv4_multicast_mode; } struct rib * rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) { struct route_table *table; struct route_node *rn; struct rib *match; struct nexthop *nexthop, *tnexthop; int recursing; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); 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); RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } if (! match || match->type == ZEBRA_ROUTE_BGP) return NULL; if (match->type == ZEBRA_ROUTE_CONNECT) return match; for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing)) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) return match; return NULL; } /* * This clone function, unlike its original rib_lookup_ipv4(), checks * if specified IPv4 route record (prefix/mask -> gate) exists in * the whole RIB and has ZEBRA_FLAG_SELECTED set. * * Return values: * -1: error * 0: exact match found * 1: a match was found with a different gate * 2: connected route found * 3: no matches found */ int rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate, vrf_id_t vrf_id) { struct route_table *table; struct route_node *rn; struct rib *match; struct nexthop *nexthop, *tnexthop; int recursing; int nexthops_active; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return ZEBRA_RIB_LOOKUP_ERROR; /* Scan the RIB table for exactly matching RIB entry. */ rn = route_node_lookup (table, (struct prefix *) p); /* No route for this prefix. */ if (! rn) return ZEBRA_RIB_NOTFOUND; /* Unlock node. */ route_unlock_node (rn); /* Find out if a "selected" RR for the discovered RIB entry exists ever. */ RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } /* None such found :( */ if (!match) return ZEBRA_RIB_NOTFOUND; if (match->type == ZEBRA_ROUTE_CONNECT) return ZEBRA_RIB_FOUND_CONNECTED; /* Ok, we have a cood candidate, let's check it's nexthop list... */ nexthops_active = 0; for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing)) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { nexthops_active = 1; if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate)) return ZEBRA_RIB_FOUND_EXACT; if (IS_ZEBRA_DEBUG_RIB) { char gate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN]; inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN); inet_ntop (AF_INET, &sockunion2ip(qgate), qgate_buf, INET_ADDRSTRLEN); zlog_debug ("%s: qgate == %s, %s == %s", __func__, qgate_buf, recursing ? "rgate" : "gate", gate_buf); } } if (nexthops_active) return ZEBRA_RIB_FOUND_NOGATE; return ZEBRA_RIB_NOTFOUND; } struct rib * rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) { struct prefix_ipv6 p; struct route_table *table; struct route_node *rn; struct rib *match; struct nexthop *newhop, *tnewhop; int recursing; /* Lookup table. */ table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); 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. */ RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) 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 (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) return match; return NULL; } } } return NULL; } #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) /* This function verifies reachability of one given nexthop, which can be * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored * in nexthop->flags field. If the 4th parameter, 'set', is non-zero, * nexthop->ifindex will be updated appropriately as well. * An existing route map can turn (otherwise active) nexthop into inactive, but * not vice versa. * * The return value is the final value of 'ACTIVE' flag. */ static unsigned nexthop_active_check (struct route_node *rn, struct rib *rib, struct nexthop *nexthop, int set) { rib_table_info_t *info = rn->table->info; struct interface *ifp; route_map_result_t ret = RMAP_MATCH; extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; struct route_map *rmap; int family; family = 0; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id); if (ifp && if_is_operative(ifp)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_IPV6_IFNAME: family = AFI_IP6; case NEXTHOP_TYPE_IFNAME: ifp = if_lookup_by_name_vrf (nexthop->ifname, rib->vrf_id); if (ifp && if_is_operative(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: family = AFI_IP; if (nexthop_active_ipv4 (rib, nexthop, set, rn)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_IPV6: family = AFI_IP6; 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: family = AFI_IP6; if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) { ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id); if (ifp && if_is_operative(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; case NEXTHOP_TYPE_BLACKHOLE: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) return 0; /* XXX: What exactly do those checks do? Do we support * e.g. IPv4 routes with IPv6 nexthops or vice versa? */ if (RIB_SYSTEM_ROUTE(rib) || (family == AFI_IP && rn->p.family != AF_INET) || (family == AFI_IP6 && rn->p.family != AF_INET6)) return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); /* The original code didn't determine the family correctly * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi * from the rib_table_info in those cases. * Possibly it may be better to use only the rib_table_info * in every case. */ if (!family) family = info->afi; rmap = 0; if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX && proto_rm[family][rib->type]) rmap = route_map_lookup_by_name (proto_rm[family][rib->type]); if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX]) rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]); if (rmap) { struct nexthop_vrfid nh_vrf = {nexthop, rib->vrf_id}; ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, &nh_vrf); } if (ret == RMAP_DENYMATCH) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); } /* Iterate over all nexthops of the given RIB entry and refresh their * ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any * nexthop is found to toggle the ACTIVE flag, the whole rib structure * is flagged with RIB_ENTRY_CHANGED. The 4th 'set' argument is * transparently passed to nexthop_active_check(). * * Return value is the new number of active nexthops. */ static int nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { struct nexthop *nexthop; unsigned int prev_active, new_active; ifindex_t prev_index; rib->nexthop_active_num = 0; for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; if ((new_active = nexthop_active_check (rn, rib, nexthop, set))) rib->nexthop_active_num++; if (prev_active != new_active || prev_index != nexthop->ifindex) SET_FLAG (rib->status, RIB_ENTRY_CHANGED); } return rib->nexthop_active_num; } static int rib_update_kernel (struct route_node *rn, struct rib *old, struct rib *new) { int ret = 0; struct nexthop *nexthop, *tnexthop; rib_table_info_t *info = rn->table->info; int recursing; if (info->safi != SAFI_UNICAST) { if (new) for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); if (old) for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); return 0; } /* * Make sure we update the FPM any time we send new information to * the kernel. */ zfpm_trigger_update (rn, "updating in kernel"); ret = kernel_route_rib (&rn->p, old, new); /* This condition is never met, if we are using rt_socket.c */ if (ret < 0 && new) { for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } else if (old && old != new) { for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } return ret; } /* Uninstall the route from kernel. */ static void rib_uninstall (struct route_node *rn, struct rib *rib) { rib_table_info_t *info = rn->table->info; if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "rib_uninstall"); redistribute_delete (&rn->p, rib); if (! RIB_SYSTEM_ROUTE (rib)) rib_update_kernel (rn, rib, NULL); UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); } } static void rib_unlink (struct route_node *, struct rib *); /* * rib_can_delete_dest * * Returns TRUE if the given dest can be deleted from the table. */ static int rib_can_delete_dest (rib_dest_t *dest) { if (dest->routes) { return 0; } /* * Don't delete the dest if we have to update the FPM about this * prefix. */ if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM) || CHECK_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM)) return 0; return 1; } /* * rib_gc_dest * * Garbage collect the rib dest corresponding to the given route node * if appropriate. * * Returns TRUE if the dest was deleted, FALSE otherwise. */ int rib_gc_dest (struct route_node *rn) { rib_dest_t *dest; dest = rib_dest_from_rnode (rn); if (!dest) return 0; if (!rib_can_delete_dest (dest)) return 0; if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "removing dest from table"); dest->rnode = NULL; XFREE (MTYPE_RIB_DEST, dest); rn->info = NULL; /* * Release the one reference that we keep on the route node. */ route_unlock_node (rn); return 1; } /* Check if 'alternate' RIB entry is better than 'current'. */ static struct rib * rib_choose_best (struct rib *current, struct rib *alternate) { if (current == NULL) return alternate; /* filter route selection in following order: * - connected beats other types * - lower distance beats higher * - lower metric beats higher for equal distance * - last, hence oldest, route wins tie break. */ /* Connected routes. Pick the last connected * route of the set of lowest metric connected routes. */ if (alternate->type == ZEBRA_ROUTE_CONNECT) { if (current->type != ZEBRA_ROUTE_CONNECT || alternate->metric <= current->metric) return alternate; return current; } if (current->type == ZEBRA_ROUTE_CONNECT) return current; /* higher distance loses */ if (alternate->distance < current->distance) return alternate; if (current->distance < alternate->distance) return current; /* metric tie-breaks equal distance */ if (alternate->metric <= current->metric) return alternate; return current; } /* Core function for processing routing information base. */ static void rib_process (struct route_node *rn) { struct rib *rib; struct rib *next; struct rib *old_selected = NULL; struct rib *new_selected = NULL; struct rib *old_fib = NULL; struct rib *new_fib = NULL; int installed = 0; struct nexthop *nexthop = NULL, *tnexthop; int recursing; rib_table_info_t *info; assert (rn); info = rn->table->info; RNODE_FOREACH_RIB (rn, rib) { UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { assert (old_selected == NULL); old_selected = rib; } if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { assert (old_fib == NULL); old_fib = rib; } /* Skip deleted entries from selection */ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; /* Skip unreachable nexthop. */ if (! nexthop_active_update (rn, rib, 0)) continue; /* Infinit distance. */ if (rib->distance == DISTANCE_INFINITY) continue; if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE)) new_fib = rib_choose_best(new_fib, rib); else new_selected = rib_choose_best(new_selected, rib); } /* RNODE_FOREACH_RIB_SAFE */ /* If no FIB override route, use the selected route also for FIB */ if (new_fib == NULL) new_fib = new_selected; /* After the cycle is finished, the following pointers will be set: * old_selected --- RIB entry currently having SELECTED * new_selected --- RIB entry that is newly SELECTED * old_fib --- RIB entry currently in kernel FIB * new_fib --- RIB entry that is newly to be in kernel FIB * * new_selected will get SELECTED flag, and is going to be redistributed * the zclients. new_fib (which can be new_selected) will be installed in kernel. */ /* Set real nexthops. */ if (new_fib) nexthop_active_update (rn, new_fib, 1); if (new_selected && new_selected != new_fib) nexthop_active_update (rn, new_selected, 1); /* Update kernel if FIB entry has changed */ if (old_fib != new_fib || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_CHANGED))) { if (old_fib && old_fib != new_fib) { if (! RIB_SYSTEM_ROUTE (old_fib) && (! new_fib || RIB_SYSTEM_ROUTE (new_fib))) rib_update_kernel (rn, old_fib, NULL); UNSET_FLAG (old_fib->status, RIB_ENTRY_SELECTED_FIB); } if (new_fib) { /* Install new or replace existing FIB entry */ SET_FLAG (new_fib->status, RIB_ENTRY_SELECTED_FIB); if (! RIB_SYSTEM_ROUTE (new_fib)) rib_update_kernel (rn, old_fib, new_fib); } if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "updating existing route"); } else if (old_fib == new_fib && new_fib && ! RIB_SYSTEM_ROUTE (new_fib)) { /* Housekeeping code to deal with race conditions in kernel with * linux netlink reporting interface up before IPv4 or IPv6 protocol * is ready to add routes. This makes sure routes are IN the kernel. */ for (ALL_NEXTHOPS_RO(new_fib->nexthop, nexthop, tnexthop, recursing)) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { installed = 1; break; } if (! installed) rib_update_kernel (rn, NULL, new_fib); } /* Redistribute SELECTED entry */ if (old_selected != new_selected || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED))) { if (old_selected) { if (! new_selected) redistribute_delete (&rn->p, old_selected); if (old_selected != new_selected) UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED); } if (new_selected) { /* Install new or replace existing redistributed entry */ SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED); redistribute_add (&rn->p, new_selected, old_selected); } } /* Remove all RIB entries queued for removal */ RNODE_FOREACH_RIB_SAFE (rn, rib, next) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "rn %p, removing rib %p", (void *)rn, (void *)rib); rib_unlink (rn, rib); } } if (IS_ZEBRA_DEBUG_RIB_Q) rnode_debug (rn, "rn %p dequeued", (void *)rn); /* * Check if the dest can be deleted now. */ rib_gc_dest (rn); } /* Take a list of route_node structs and return 1, if there was a record * picked from it and processed by rib_process(). Don't process more, * than one RN record; operate only in the specified sub-queue. */ static unsigned int process_subq (struct list * subq, u_char qindex) { struct listnode *lnode = listhead (subq); struct route_node *rnode; if (!lnode) return 0; rnode = listgetdata (lnode); rib_process (rnode); if (rnode->info) UNSET_FLAG (rib_dest_from_rnode (rnode)->flags, RIB_ROUTE_QUEUED (qindex)); #if 0 else { zlog_debug ("%s: called for route_node (%p, %d) with no ribs", __func__, rnode, rnode->lock); zlog_backtrace(LOG_DEBUG); } #endif route_unlock_node (rnode); list_delete_node (subq, lnode); return 1; } /* * All meta queues have been processed. Trigger next-hop evaluation. */ static void meta_queue_process_complete (struct work_queue *dummy) { zebra_evaluate_rnh_table(0, AF_INET); #ifdef HAVE_IPV6 zebra_evaluate_rnh_table(0, AF_INET6); #endif /* HAVE_IPV6 */ } /* Dispatch the meta queue by picking, processing and unlocking the next RN from * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data * is pointed to the meta queue structure. */ static wq_item_status meta_queue_process (struct work_queue *dummy, void *data) { struct meta_queue * mq = data; unsigned i; for (i = 0; i < MQ_SIZE; i++) if (process_subq (mq->subq[i], i)) { mq->size--; break; } return mq->size ? WQ_REQUEUE : WQ_SUCCESS; } /* * Map from rib types to queue type (priority) in meta queue */ static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = { [ZEBRA_ROUTE_SYSTEM] = 4, [ZEBRA_ROUTE_KERNEL] = 0, [ZEBRA_ROUTE_CONNECT] = 0, [ZEBRA_ROUTE_STATIC] = 1, [ZEBRA_ROUTE_RIP] = 2, [ZEBRA_ROUTE_RIPNG] = 2, [ZEBRA_ROUTE_OSPF] = 2, [ZEBRA_ROUTE_OSPF6] = 2, [ZEBRA_ROUTE_ISIS] = 2, [ZEBRA_ROUTE_BGP] = 3, [ZEBRA_ROUTE_HSLS] = 4, [ZEBRA_ROUTE_BABEL] = 2, [ZEBRA_ROUTE_NHRP] = 2, }; /* Look into the RN and queue it into one or more priority queues, * increasing the size for each data push done. */ static void rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) { struct rib *rib; RNODE_FOREACH_RIB (rn, rib) { u_char qindex = meta_queue_map[rib->type]; /* Invariant: at this point we always have rn->info set. */ if (CHECK_FLAG (rib_dest_from_rnode (rn)->flags, RIB_ROUTE_QUEUED (qindex))) { if (IS_ZEBRA_DEBUG_RIB_Q) rnode_debug (rn, "rn %p is already queued in sub-queue %u", (void *)rn, qindex); continue; } SET_FLAG (rib_dest_from_rnode (rn)->flags, RIB_ROUTE_QUEUED (qindex)); listnode_add (mq->subq[qindex], rn); route_lock_node (rn); mq->size++; if (IS_ZEBRA_DEBUG_RIB_Q) rnode_debug (rn, "queued rn %p into sub-queue %u", (void *)rn, qindex); } } /* Add route_node to work queue and schedule processing */ static void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { assert (zebra && rn); /* Pointless to queue a route_node with no RIB entries to add or remove */ if (!rnode_to_ribs (rn)) { zlog_debug ("%s: called for route_node (%p, %d) with no ribs", __func__, (void *)rn, rn->lock); zlog_backtrace(LOG_DEBUG); return; } if (IS_ZEBRA_DEBUG_RIB_Q) rnode_info (rn, "work queue added"); assert (zebra); if (zebra->ribq == NULL) { zlog_err ("%s: work_queue does not exist!", __func__); return; } /* * The RIB queue should normally be either empty or holding the only * work_queue_item element. In the latter case this element would * hold a pointer to the meta queue structure, which must be used to * actually queue the route nodes to process. So create the MQ * holder, if necessary, then push the work into it in any case. * This semantics was introduced after 0.99.9 release. */ if (!zebra->ribq->items->count) work_queue_add (zebra->ribq, zebra->mq); rib_meta_queue_add (zebra->mq, rn); if (IS_ZEBRA_DEBUG_RIB_Q) rnode_debug (rn, "rn %p queued", (void *)rn); return; } /* Create new meta queue. A destructor function doesn't seem to be necessary here. */ static struct meta_queue * meta_queue_new (void) { struct meta_queue *new; unsigned i; new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct meta_queue)); assert(new); for (i = 0; i < MQ_SIZE; i++) { new->subq[i] = list_new (); assert(new->subq[i]); } return new; } /* initialise zebra rib work queue */ static void rib_queue_init (struct zebra_t *zebra) { assert (zebra); if (! (zebra->ribq = work_queue_new (zebra->master, "route_node processing"))) { zlog_err ("%s: could not initialise work queue!", __func__); return; } /* fill in the work queue spec */ zebra->ribq->spec.workfunc = &meta_queue_process; zebra->ribq->spec.errorfunc = NULL; zebra->ribq->spec.completion_func = &meta_queue_process_complete; /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; zebra->ribq->spec.hold = rib_process_hold_time; if (!(zebra->mq = meta_queue_new ())) { zlog_err ("%s: could not initialise meta queue!", __func__); return; } return; } /* RIB updates are processed via a queue of pointers to route_nodes. * * The queue length is bounded by the maximal size of the routing table, * as a route_node will not be requeued, if already queued. * * RIBs are submitted via rib_addnode or rib_delnode which set minimal * state, or static_install_route (when an existing RIB is updated) * and then submit route_node to queue for best-path selection later. * Order of add/delete state changes are preserved for any given RIB. * * Deleted RIBs are reaped during best-path selection. * * rib_addnode * |-> rib_link or unset RIB_ENTRY_REMOVE |->Update kernel with * |-------->| | best RIB, if required * | | * static_install->|->rib_addqueue...... -> rib_process * | | * |-------->| |-> rib_unlink * |-> set RIB_ENTRY_REMOVE | * rib_delnode (RIB freed) * * The 'info' pointer of a route_node points to a rib_dest_t * ('dest'). Queueing state for a route_node is kept on the dest. The * dest is created on-demand by rib_link() and is kept around at least * as long as there are ribs hanging off it (@see rib_gc_dest()). * * Refcounting (aka "locking" throughout the GNU Zebra and Quagga code): * * - route_nodes: refcounted by: * - dest attached to route_node: * - managed by: rib_link/rib_gc_dest * - route_node processing queue * - managed by: rib_addqueue, rib_process. * */ /* Add RIB to head of the route node. */ static void rib_link (struct route_node *rn, struct rib *rib) { struct rib *head; rib_dest_t *dest; assert (rib && rn); if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib); dest = rib_dest_from_rnode (rn); if (!dest) { if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "adding dest to table"); dest = XCALLOC (MTYPE_RIB_DEST, sizeof (rib_dest_t)); route_lock_node (rn); /* rn route table reference */ rn->info = dest; dest->rnode = rn; } head = dest->routes; if (head) { head->prev = rib; } rib->next = head; dest->routes = rib; rib_queue_add (&zebrad, rn); } static void rib_addnode (struct route_node *rn, struct rib *rib) { /* RIB node has been un-removed before route-node is processed. * route_node must hence already be on the queue for processing.. */ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "rn %p, un-removed rib %p", (void *)rn, (void *)rib); UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); return; } rib_link (rn, rib); } /* * rib_unlink * * Detach a rib structure from a route_node. * * Note that a call to rib_unlink() should be followed by a call to * rib_gc_dest() at some point. This allows a rib_dest_t that is no * longer required to be deleted. */ static void rib_unlink (struct route_node *rn, struct rib *rib) { rib_dest_t *dest; assert (rn && rib); if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib); dest = rib_dest_from_rnode (rn); if (rib->next) rib->next->prev = rib->prev; if (rib->prev) rib->prev->next = rib->next; else { dest->routes = rib->next; } /* free RIB and nexthops */ nexthops_free(rib->nexthop); XFREE (MTYPE_RIB, rib); } static void rib_delnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_RIB) rnode_debug (rn, "rn %p, rib %p, removing", (void *)rn, (void *)rib); SET_FLAG (rib->status, RIB_ENTRY_REMOVED); rib_queue_add (&zebrad, rn); } int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, ifindex_t ifindex, vrf_id_t vrf_id, int table_id, u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi) { struct rib *rib; struct rib *same = NULL; struct route_table *table; struct route_node *rn; struct nexthop *nexthop; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, safi, vrf_id); 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) { if ((unsigned)type >= array_size(route_info)) distance = 150; else 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. */ RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (rib->type != type) continue; if (rib->type != ZEBRA_ROUTE_CONNECT) { same = rib; break; } /* Duplicate connected route comes in. */ else if ((nexthop = rib->nexthop) && nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex && !CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { rib->refcnt++; return 0 ; } } /* Allocate new rib structure. */ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); rib->type = type; rib->distance = distance; rib->flags = flags; rib->metric = metric; rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table_id; rib->nexthop_num = 0; rib->uptime = time (NULL); /* Nexthop settings. */ if (gate) { if (ifindex) rib_nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); else rib_nexthop_ipv4_add (rib, gate, src); } else rib_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.*/ if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: calling rib_addnode (%p, %p)", __func__, (void *)rn, (void *)rib); rib_addnode (rn, rib); /* Free implicit route.*/ if (same) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: calling rib_delnode (%p, %p)", __func__, (void *)rn, (void *)rib); rib_delnode (rn, same); } route_unlock_node (rn); return 0; } /* This function dumps the contents of a given RIB entry into * standard debug log. Calling function name and IP prefix in * question are passed as 1st and 2nd arguments. */ void _rib_dump (const char * func, union prefix46constptr pp, const struct rib * rib) { const struct prefix *p = pp.p; char straddr[PREFIX_STRLEN]; struct nexthop *nexthop, *tnexthop; int recursing; zlog_debug ("%s: dumping RIB entry %p for %s vrf %u", func, (void *)rib, prefix2str(p, straddr, sizeof(straddr)), rib->vrf_id); zlog_debug ( "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d", func, rib->refcnt, (unsigned long) rib->uptime, rib->type, rib->table ); zlog_debug ( "%s: metric == %u, distance == %u, flags == %u, status == %u", func, rib->metric, rib->distance, rib->flags, rib->status ); zlog_debug ( "%s: nexthop_num == %u, nexthop_active_num == %u, nexthop_fib_num == %u", func, rib->nexthop_num, rib->nexthop_active_num, rib->nexthop_fib_num ); for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { inet_ntop (p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN); zlog_debug ( "%s: %s %s with flags %s%s%s", func, (recursing ? " NH" : "NH"), straddr, (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""), (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "") ); } zlog_debug ("%s: dump complete", func); } /* This is an exported helper to rtm_read() to dump the strange * RIB entry found by rib_lookup_ipv4_route() */ void rib_lookup_and_dump (struct prefix_ipv4 * p) { struct route_table *table; struct route_node *rn; struct rib *rib; char prefix_buf[INET_ADDRSTRLEN]; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) { zlog_err ("%s: zebra_vrf_table() returned NULL", __func__); return; } /* Scan the RIB table for exactly matching RIB entry. */ rn = route_node_lookup (table, (struct prefix *) p); /* No route for this prefix. */ if (! rn) { zlog_debug ("%s: lookup failed for %s", __func__, prefix2str((struct prefix*) p, prefix_buf, sizeof(prefix_buf))); return; } /* Unlock node. */ route_unlock_node (rn); /* let's go */ RNODE_FOREACH_RIB (rn, rib) { zlog_debug ( "%s: rn %p, rib %p: %s, %s", __func__, (void *)rn, (void *)rib, (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") ); rib_dump (p, rib); } } int rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) { struct route_table *table; struct route_node *rn; struct rib *same; struct nexthop *nexthop; int ret = 0; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id); 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. */ RNODE_FOREACH_RIB (rn, same) { if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) continue; if (same->type == rib->type && same->table == rib->table && same->type != ZEBRA_ROUTE_CONNECT) 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); ret = 1; if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", __func__, (void *)rn, (void *)rib); rib_dump (p, rib); } /* Free implicit route.*/ if (same) { if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", __func__, (void *)rn, (void *)same); rib_dump (p, same); } rib_delnode (rn, same); ret = -1; } route_unlock_node (rn); return ret; } /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id, safi_t safi) { struct route_table *table; struct route_node *rn; struct rib *rib; struct rib *fib = NULL; struct rib *same = NULL; struct nexthop *nexthop, *tnexthop; int recursing; char buf1[PREFIX_STRLEN]; char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return 0; /* Apply mask. */ apply_mask_ipv4 (p); if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u via %s ifindex %d", prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntoa (*gate), ifindex); else zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u ifindex %d", prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex); } /* Lookup route node. */ rn = route_node_lookup (table, (struct prefix *) p); if (! rn) { if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib", prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex); else zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib", prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex); } return ZEBRA_ERR_RTNOEXIST; } /* Lookup same type route. */ RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) fib = rib; if (rib->type != type) continue; if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && nexthop->type == NEXTHOP_TYPE_IFINDEX) { if (nexthop->ifindex != ifindex) continue; if (rib->refcnt) { rib->refcnt--; route_unlock_node (rn); route_unlock_node (rn); return 0; } same = rib; break; } /* Make sure that the route found has the same gateway. */ else { if (gate == NULL) { same = rib; break; } for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate)) { same = rib; break; } if (same) break; } } /* If same type of route can't be found and this message is from kernel. */ if (! same) { if (fib && type == ZEBRA_ROUTE_KERNEL && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("Zebra route %s/%d was deleted by others from kernel", inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen); } /* This means someone else, other than Zebra, has deleted * a Zebra router from the kernel. We will add it back */ rib_update_kernel(rn, NULL, fib); } else { if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) zlog_debug ("route %s vrf %u via %s ifindex %d type %d " "doesn't exist in rib", prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex, type); else zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib", prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex, type); } route_unlock_node (rn); return ZEBRA_ERR_RTNOEXIST; } } if (same) rib_delnode (rn, same); route_unlock_node (rn); return 0; } /* Install static route into rib. */ static void static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) { struct rib *rib; struct route_node *rn; struct route_table *table; /* Lookup table. */ table = zebra_vrf_table (afi, safi, si->vrf_id); if (! table) return; /* Lookup existing route */ rn = route_node_get (table, p); RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) break; } if (rib) { /* if tag value changed , update old value in RIB */ if (rib->tag != si->tag) rib->tag = si->tag; /* Same distance static route is there. Update it with new nexthop. */ route_unlock_node (rn); switch (si->type) { case STATIC_IPV4_GATEWAY: rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); break; case STATIC_IPV4_IFNAME: rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV4_BLACKHOLE: rib_nexthop_blackhole_add (rib); break; case STATIC_IPV6_GATEWAY: rib_nexthop_ipv6_add (rib, &si->addr.ipv6); break; case STATIC_IPV6_IFNAME: rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); break; } rib_queue_add (&zebrad, rn); } else { /* This is new static route. */ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); rib->type = ZEBRA_ROUTE_STATIC; rib->distance = si->distance; rib->metric = 0; rib->vrf_id = si->vrf_id; rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; rib->tag = si->tag; switch (si->type) { case STATIC_IPV4_GATEWAY: rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); break; case STATIC_IPV4_IFNAME: rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV4_BLACKHOLE: rib_nexthop_blackhole_add (rib); break; case STATIC_IPV6_GATEWAY: rib_nexthop_ipv6_add (rib, &si->addr.ipv6); break; case STATIC_IPV6_IFNAME: rib_nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); break; } /* Save the flags of this static routes (reject, blackhole) */ rib->flags = si->flags; /* Link this rib to the tree. */ rib_addnode (rn, rib); } } static int static_nexthop_same (struct nexthop *nexthop, struct static_route *si) { if (nexthop->type == NEXTHOP_TYPE_IPV4 && si->type == STATIC_IPV4_GATEWAY && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4)) return 1; if (nexthop->type == NEXTHOP_TYPE_IFNAME && si->type == STATIC_IPV4_IFNAME && strcmp (nexthop->ifname, si->ifname) == 0) return 1; if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE && si->type == STATIC_IPV4_BLACKHOLE) return 1; if (nexthop->type == NEXTHOP_TYPE_IPV6 && si->type == STATIC_IPV6_GATEWAY && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.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->addr.ipv6) && strcmp (nexthop->ifname, si->ifname) == 0) return 1; return 0; } /* Uninstall static route from RIB. */ static void static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) { struct route_node *rn; struct rib *rib; struct nexthop *nexthop; struct route_table *table; /* Lookup table. */ table = zebra_vrf_table (afi, safi, si->vrf_id); if (! table) return; /* Lookup existing route with type and distance. */ rn = route_node_lookup (table, p); if (! rn) return; RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance && rib->tag == si->tag) break; } if (! rib) { route_unlock_node (rn); return; } /* Lookup nexthop. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (static_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); else { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) rib_uninstall (rn, rib); rib_nexthop_delete (rib, nexthop); nexthop_free (nexthop); rib_queue_add (&zebrad, rn); } /* Unlock node. */ route_unlock_node (rn); } int static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, const char *ifname, u_char flags, route_tag_t tag, u_char distance, vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; struct static_route *si; struct static_route *pp; struct static_route *cp; struct static_route *update = NULL; struct zebra_vrf *zvrf = vrf_info_get (vrf_id); struct route_table *stable = zvrf->stable[AFI_IP][safi]; 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->addr.ipv4)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { if (distance == si->distance && tag == si->tag) { route_unlock_node (rn); return 0; } else update = si; } } /* Distance or tag changed. */ if (update) static_delete_ipv4_safi (safi, p, gate, ifname, update->tag, update->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; si->tag = tag; si->flags = flags; si->vrf_id = vrf_id; if (gate) si->addr.ipv4 = *gate; if (ifname) si->ifname = XSTRDUP (MTYPE_TMP, 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->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr)) break; if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.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_route (AFI_IP, safi, p, si); return 1; } int static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, const char *ifname, route_tag_t tag, u_char distance, vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; struct static_route *si; struct route_table *stable; /* Lookup table. */ stable = zebra_vrf_static_table (AFI_IP, safi, 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->addr.ipv4)) && (! ifname || strcmp (ifname, si->ifname) == 0) && (! tag || (tag == si->tag))) break; /* Can't find static route. */ if (! si) { route_unlock_node (rn); return 0; } /* Install into rib. */ static_uninstall_route (AFI_IP, safi, 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; route_unlock_node (rn); /* Free static route configuration. */ if (ifname) XFREE (0, si->ifname); XFREE (MTYPE_STATIC_ROUTE, si); route_unlock_node (rn); return 1; } int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id, int table_id, u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi) { struct rib *rib; struct rib *same = NULL; struct route_table *table; struct route_node *rn; struct nexthop *nexthop; /* Lookup table. */ table = zebra_vrf_table (AFI_IP6, safi, vrf_id); if (! table) return 0; /* Make sure mask is applied. */ apply_mask_ipv6 (p); /* Set default distance by route type. */ if (!distance) distance = route_info[type].distance; 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. */ RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (rib->type != type) continue; if (rib->type != ZEBRA_ROUTE_CONNECT) { same = rib; break; } else if ((nexthop = rib->nexthop) && nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex) { rib->refcnt++; return 0; } } /* Allocate new rib structure. */ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); rib->type = type; rib->distance = distance; rib->flags = flags; rib->metric = metric; rib->mtu = mtu; rib->vrf_id = vrf_id; rib->table = table_id; rib->nexthop_num = 0; rib->uptime = time (NULL); /* Nexthop settings. */ if (gate) { if (ifindex) rib_nexthop_ipv6_ifindex_add (rib, gate, ifindex); else rib_nexthop_ipv6_add (rib, gate); } else rib_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); if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", __func__, (void *)rn, (void *)rib); rib_dump (p, rib); } /* Free implicit route.*/ if (same) { if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", __func__, (void *)rn, (void *)same); rib_dump (p, same); } rib_delnode (rn, same); } route_unlock_node (rn); return 0; } int rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi) { struct route_table *table; struct route_node *rn; struct rib *same = NULL; struct nexthop *nexthop; int ret = 0; if (!rib) return 0; /* why are we getting called with NULL rib */ /* Lookup table. */ table = zebra_vrf_table (AFI_IP6, safi, rib->vrf_id); if (! table) return 0; /* Make sure mask is applied. */ apply_mask_ipv6 (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. */ RNODE_FOREACH_RIB (rn, same) { if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) { continue; } if (same->type != rib->type) { continue; } if (same->table != rib->table) { continue; } if (same->type != ZEBRA_ROUTE_CONNECT) { 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); ret = 1; /* Free implicit route.*/ if (same) { if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", __func__, rn, same); rib_dump ((struct prefix *)p, same); } rib_delnode (rn, same); ret = -1; } route_unlock_node (rn); return ret; } /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id, safi_t safi) { struct route_table *table; struct route_node *rn; struct rib *rib; struct rib *fib = NULL; struct rib *same = NULL; struct nexthop *nexthop, *tnexthop; int recursing; char buf1[PREFIX_STRLEN]; char buf2[INET6_ADDRSTRLEN]; /* Apply mask. */ apply_mask_ipv6 (p); /* Lookup table. */ table = zebra_vrf_table (AFI_IP6, safi, vrf_id); 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_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib", prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex); else zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib", prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex); } return ZEBRA_ERR_RTNOEXIST; } /* Lookup same type route. */ RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) fib = rib; if (rib->type != type) continue; if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && nexthop->type == NEXTHOP_TYPE_IFINDEX) { if (nexthop->ifindex != ifindex) continue; if (rib->refcnt) { rib->refcnt--; route_unlock_node (rn); route_unlock_node (rn); return 0; } same = rib; break; } /* Make sure that the route found has the same gateway. */ else { if (gate == NULL) { same = rib; break; } for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) if (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate)) { same = rib; break; } if (same) break; } } /* If same type of route can't be found and this message is from kernel. */ if (! same) { if (fib && type == ZEBRA_ROUTE_KERNEL && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("Zebra route %s/%d was deleted by others from kernel", inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen); } /* This means someone else, other than Zebra, has deleted a Zebra * route from the kernel. We will add it back */ rib_update_kernel(rn, NULL, fib); } else { if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) zlog_debug ("route %s vrf %u via %s ifindex %d type %d " "doesn't exist in rib", prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex, type); else zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib", prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex, type); } route_unlock_node (rn); return ZEBRA_ERR_RTNOEXIST; } } if (same) rib_delnode (rn, same); route_unlock_node (rn); return 0; } /* Add static route into static route configuration. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char flags, route_tag_t tag, u_char distance, vrf_id_t vrf_id) { struct route_node *rn; struct static_route *si; struct static_route *pp; struct static_route *cp; struct static_route *update = NULL; struct zebra_vrf *zvrf = vrf_info_get (vrf_id); struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]; if (! stable) return -1; if (!gate && (type == STATIC_IPV6_GATEWAY || type == STATIC_IPV6_GATEWAY_IFNAME)) return -1; if (!ifname && (type == STATIC_IPV6_GATEWAY_IFNAME || type == STATIC_IPV6_IFNAME)) 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 (type == si->type && tag == si->tag && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { if (distance == si->distance) { route_unlock_node (rn); return 0; } else update = si; } } if (update) static_delete_ipv6(p, type, gate, ifname, tag, update->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; si->tag = tag; si->flags = flags; si->vrf_id = vrf_id; switch (type) { case STATIC_IPV6_GATEWAY: si->addr.ipv6 = *gate; break; case STATIC_IPV6_IFNAME: si->ifname = XSTRDUP (MTYPE_TMP, ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: si->addr.ipv6 = *gate; si->ifname = XSTRDUP (MTYPE_TMP, 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_route (AFI_IP6, SAFI_UNICAST, 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, const char *ifname, route_tag_t tag, u_char distance, vrf_id_t vrf_id) { struct route_node *rn; struct static_route *si; struct route_table *stable; /* Lookup table. */ stable = zebra_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->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0) && (! tag || (tag == si->tag))) break; /* Can't find static route. */ if (! si) { route_unlock_node (rn); return 0; } /* Install into rib. */ static_uninstall_route (AFI_IP6, SAFI_UNICAST, 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. */ if (ifname) XFREE (0, si->ifname); XFREE (MTYPE_STATIC_ROUTE, si); return 1; } /* RIB update function. */ void rib_update (vrf_id_t vrf_id) { struct route_node *rn; struct route_table *table; table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (rn)) rib_queue_add (&zebrad, rn); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (rn)) rib_queue_add (&zebrad, rn); } /* Remove all routes which comes from non main table. */ static 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)) RNODE_FOREACH_RIB_SAFE (rn, rib, next) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (rib->table != zebrad.rtm_table_default && rib->table != RT_TABLE_MAIN) rib_delnode (rn, rib); } } /* Delete all routes from non main table. */ void rib_weed_tables (void) { vrf_iter_t iter; struct zebra_vrf *zvrf; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) { rib_weed_table (zvrf->table[AFI_IP][SAFI_UNICAST]); rib_weed_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); } } #if 0 /* Delete self installed routes after zebra is relaunched. */ static 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)) RNODE_FOREACH_RIB_SAFE (rn, rib, next) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (rib->type == ZEBRA_ROUTE_KERNEL && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) { ret = rib_update_kernel (rn, rib, NULL); if (! ret) rib_delnode (rn, rib); } } } #endif /* Sweep all RIB tables. */ void rib_sweep_route (void) { vrf_iter_t iter; struct zebra_vrf *zvrf; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) { rib_weed_table (zvrf->table[AFI_IP][SAFI_UNICAST]); rib_weed_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); } } /* Remove specific by protocol routes from 'table'. */ static unsigned long rib_score_proto_table (u_char proto, struct route_table *table) { struct route_node *rn; struct rib *rib; struct rib *next; unsigned long n = 0; if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB_SAFE (rn, rib, next) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (rib->type == proto) { rib_delnode (rn, rib); n++; } } return n; } /* Remove specific by protocol routes. */ unsigned long rib_score_proto (u_char proto) { vrf_iter_t iter; struct zebra_vrf *zvrf; unsigned long cnt = 0; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) cnt += rib_score_proto_table (proto, zvrf->table[AFI_IP][SAFI_UNICAST]) +rib_score_proto_table (proto, zvrf->table[AFI_IP6][SAFI_UNICAST]); return cnt; } /* Close RIB and clean up kernel routes. */ void rib_close_table (struct route_table *table) { struct route_node *rn; rib_table_info_t *info = table->info; struct rib *rib; if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, NULL); if (! RIB_SYSTEM_ROUTE (rib)) rib_update_kernel (rn, rib, NULL); } } /* Close all RIB tables. */ void rib_close (void) { vrf_iter_t iter; struct zebra_vrf *zvrf; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) { rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); } } /* Routing information base initialize. */ void rib_init (void) { rib_queue_init (&zebrad); } /* * vrf_id_get_next * * Get the first vrf id that is greater than the given vrf id if any. * * Returns TRUE if a vrf id was found, FALSE otherwise. */ static inline int vrf_id_get_next (vrf_id_t vrf_id, vrf_id_t *next_id_p) { vrf_iter_t iter = vrf_iterator (vrf_id); struct zebra_vrf *zvrf = vrf_iter2info (iter); /* The same one ? Then find out the next. */ if (zvrf && (zvrf->vrf_id == vrf_id)) zvrf = vrf_iter2info (vrf_next (iter)); if (zvrf) { *next_id_p = zvrf->vrf_id; return 1; } return 0; } /* * rib_tables_iter_next * * Returns the next table in the iteration. */ struct route_table * rib_tables_iter_next (rib_tables_iter_t *iter) { struct route_table *table; /* * Array that helps us go over all AFI/SAFI combinations via one * index. */ static struct { afi_t afi; safi_t safi; } afi_safis[] = { { AFI_IP, SAFI_UNICAST }, { AFI_IP, SAFI_MULTICAST }, { AFI_IP6, SAFI_UNICAST }, { AFI_IP6, SAFI_MULTICAST }, }; table = NULL; switch (iter->state) { case RIB_TABLES_ITER_S_INIT: iter->vrf_id = VRF_DEFAULT; iter->afi_safi_ix = -1; /* Fall through */ case RIB_TABLES_ITER_S_ITERATING: iter->afi_safi_ix++; while (1) { while (iter->afi_safi_ix < (int) ZEBRA_NUM_OF (afi_safis)) { table = zebra_vrf_table (afi_safis[iter->afi_safi_ix].afi, afi_safis[iter->afi_safi_ix].safi, iter->vrf_id); if (table) break; iter->afi_safi_ix++; } /* * Found another table in this vrf. */ if (table) break; /* * Done with all tables in the current vrf, go to the next * one. */ if (!vrf_id_get_next (iter->vrf_id, &iter->vrf_id)) break; iter->afi_safi_ix = 0; } break; case RIB_TABLES_ITER_S_DONE: return NULL; } if (table) iter->state = RIB_TABLES_ITER_S_ITERATING; else iter->state = RIB_TABLES_ITER_S_DONE; return table; } /* Lookup VRF by identifier. */ struct zebra_vrf * zebra_vrf_lookup (vrf_id_t vrf_id) { return vrf_info_lookup (vrf_id); } /* * Create a routing table for the specific AFI/SAFI in the given VRF. */ static void zebra_vrf_table_create (struct zebra_vrf *zvrf, afi_t afi, safi_t safi) { rib_table_info_t *info; struct route_table *table; assert (!zvrf->table[afi][safi]); table = route_table_init (); zvrf->table[afi][safi] = table; info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); info->zvrf = zvrf; info->afi = afi; info->safi = safi; table->info = info; } /* Allocate new zebra VRF. */ struct zebra_vrf * zebra_vrf_alloc (vrf_id_t vrf_id) { struct zebra_vrf *zvrf; #ifdef HAVE_NETLINK char nl_name[64]; #endif zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf)); /* Allocate routing table and static table. */ zebra_vrf_table_create (zvrf, AFI_IP, SAFI_UNICAST); zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_UNICAST); zvrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); zvrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); zebra_vrf_table_create (zvrf, AFI_IP, SAFI_MULTICAST); zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_MULTICAST); zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); zvrf->rnh_table[AFI_IP] = route_table_init(); zvrf->rnh_table[AFI_IP6] = route_table_init(); /* Set VRF ID */ zvrf->vrf_id = vrf_id; #ifdef HAVE_NETLINK /* Initialize netlink sockets */ snprintf (nl_name, 64, "netlink-listen (vrf %u)", vrf_id); zvrf->netlink.sock = -1; zvrf->netlink.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name); snprintf (nl_name, 64, "netlink-cmd (vrf %u)", vrf_id); zvrf->netlink_cmd.sock = -1; zvrf->netlink_cmd.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name); #endif return zvrf; } /* Lookup the routing table in an enabled VRF. */ struct route_table * zebra_vrf_table (afi_t afi, safi_t safi, vrf_id_t vrf_id) { struct zebra_vrf *zvrf = vrf_info_lookup (vrf_id); if (!zvrf) return NULL; if (afi >= AFI_MAX || safi >= SAFI_MAX) return NULL; return zvrf->table[afi][safi]; } /* Lookup the static routing table in a VRF. */ struct route_table * zebra_vrf_static_table (afi_t afi, safi_t safi, vrf_id_t vrf_id) { struct zebra_vrf *zvrf = vrf_info_lookup (vrf_id); if (!zvrf) return NULL; if (afi >= AFI_MAX || safi >= SAFI_MAX) return NULL; return zvrf->stable[afi][safi]; } quagga-1.2.4/zebra/zebra_rnh.c000066400000000000000000000361651325323223500162170ustar00rootroot00000000000000/* Zebra next hop tracking code * Copyright (C) 2013 Cumulus Networks, 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 "prefix.h" #include "table.h" #include "memory.h" #include "str.h" #include "command.h" #include "if.h" #include "log.h" #include "sockunion.h" #include "linklist.h" #include "thread.h" #include "workqueue.h" #include "prefix.h" #include "routemap.h" #include "stream.h" #include "nexthop.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_rnh.h" #define lookup_rnh_table(v, f) \ ({ \ struct zebra_vrf *zvrf; \ struct route_table *t = NULL; \ zvrf = zebra_vrf_lookup(v); \ if (zvrf) \ t = zvrf->rnh_table[family2afi(f)]; \ t; \ }) static void free_state(struct rib *rib); static void copy_state(struct rnh *rnh, struct rib *rib); static int compare_state(struct rib *r1, struct rib *r2); static int send_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id); static void print_rnh(struct route_node *rn, struct vty *vty); char * rnh_str (struct rnh *rnh, char *buf, int size) { prefix2str(&(rnh->node->p), buf, size); return buf; } struct rnh * zebra_add_rnh (struct prefix *p, vrf_id_t vrfid) { struct route_table *table; struct route_node *rn; struct rnh *rnh = NULL; if (IS_ZEBRA_DEBUG_NHT) { char buf[INET6_ADDRSTRLEN]; prefix2str(p, buf, INET6_ADDRSTRLEN); zlog_debug("add rnh %s in vrf %d", buf, vrfid); } table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); if (!table) { zlog_debug("add_rnh: rnh table not found\n"); return NULL; } /* Make it sure prefixlen is applied to the prefix. */ apply_mask (p); /* Lookup (or add) route node.*/ rn = route_node_get (table, p); if (!rn->info) { rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); rnh->client_list = list_new(); route_lock_node (rn); rn->info = rnh; rnh->node = rn; } route_unlock_node (rn); return (rn->info); } struct rnh * zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid) { struct route_table *table; struct route_node *rn; table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p)); if (!table) return NULL; /* Make it sure prefixlen is applied to the prefix. */ apply_mask (p); /* Lookup route node.*/ rn = route_node_lookup (table, p); if (!rn) return NULL; route_unlock_node (rn); return (rn->info); } void zebra_delete_rnh (struct rnh *rnh) { struct route_node *rn; if (!rnh || !(rn = rnh->node)) return; if (IS_ZEBRA_DEBUG_NHT) { char buf[INET6_ADDRSTRLEN]; zlog_debug("delete rnh %s", rnh_str(rnh, buf, INET6_ADDRSTRLEN)); } list_free(rnh->client_list); free_state(rnh->state); XFREE(MTYPE_RNH, rn->info); rn->info = NULL; route_unlock_node (rn); return; } void zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) { if (IS_ZEBRA_DEBUG_NHT) { char buf[INET6_ADDRSTRLEN]; zlog_debug("client %s registers rnh %s", zebra_route_string(client->proto), rnh_str(rnh, buf, INET6_ADDRSTRLEN)); } if (!listnode_lookup(rnh->client_list, client)) { listnode_add(rnh->client_list, client); send_client(rnh, client, vrf_id); } } void zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client) { if (IS_ZEBRA_DEBUG_NHT) { char buf[INET6_ADDRSTRLEN]; zlog_debug("client %s unregisters rnh %s", zebra_route_string(client->proto), rnh_str(rnh, buf, INET6_ADDRSTRLEN)); } listnode_delete(rnh->client_list, client); if (list_isempty(rnh->client_list)) zebra_delete_rnh(rnh); } int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) { struct route_table *ptable; struct route_table *ntable; struct route_node *prn; struct route_node *nrn; struct rnh *rnh; struct zserv *client; struct listnode *node; struct rib *rib; ntable = lookup_rnh_table(vrfid, family); if (!ntable) { zlog_debug("evaluate_rnh_table: rnh table not found\n"); return -1; } ptable = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid); if (!ptable) { zlog_debug("evaluate_rnh_table: prefix table not found\n"); return -1; } for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) { if (!nrn->info) continue; rnh = nrn->info; prn = route_node_match(ptable, &nrn->p); if (!prn) rib = NULL; else { RNODE_FOREACH_RIB(prn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (! CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { if (rib->type == ZEBRA_ROUTE_CONNECT) break; if (rib->type == ZEBRA_ROUTE_NHRP) { struct nexthop *nexthop; for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) break; if (nexthop) break; } } else break; } } if (compare_state(rib, rnh->state)) { if (IS_ZEBRA_DEBUG_NHT) { char bufn[INET6_ADDRSTRLEN]; char bufp[INET6_ADDRSTRLEN]; prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); if (prn) prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); else strcpy(bufp, "null"); zlog_debug("rnh %s resolved through route %s - sending " "nexthop %s event to clients", bufn, bufp, rib ? "reachable" : "unreachable"); } copy_state(rnh, rib); for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) send_client(rnh, client, vrfid); } } return 1; } int zebra_dispatch_rnh_table (vrf_id_t vrfid, int family, struct zserv *client) { struct route_table *ntable; struct route_node *nrn; struct rnh *rnh; ntable = lookup_rnh_table(vrfid, family); if (!ntable) { zlog_debug("dispatch_rnh_table: rnh table not found\n"); return -1; } for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) { if (!nrn->info) continue; rnh = nrn->info; if (IS_ZEBRA_DEBUG_NHT) { char bufn[INET6_ADDRSTRLEN]; prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn, rnh->state ? "reachable" : "unreachable", zebra_route_string(client->proto)); } send_client(rnh, client, vrfid); } return 1; } void zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty) { struct route_table *table; struct route_node *rn; table = lookup_rnh_table(vrfid, af); if (!table) { zlog_debug("print_rnhs: rnh table not found\n"); return; } for (rn = route_top(table); rn; rn = route_next(rn)) if (rn->info) print_rnh(rn, vty); } int zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client) { struct route_table *ntable; struct route_node *nrn; struct rnh *rnh; ntable = lookup_rnh_table(vrfid, family); if (!ntable) { zlog_debug("cleanup_rnh_client: rnh table not found\n"); return -1; } for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) { if (!nrn->info) continue; rnh = nrn->info; if (IS_ZEBRA_DEBUG_NHT) { char bufn[INET6_ADDRSTRLEN]; prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); zlog_debug("rnh %s - cleaning state for client %s", bufn, zebra_route_string(client->proto)); } zebra_remove_rnh_client(rnh, client); } return 1; } /** * free_state - free up the rib structure associated with the rnh. */ static void free_state (struct rib *rib) { struct nexthop *nexthop, *next; if (!rib) return; /* free RIB and nexthops */ for (nexthop = rib->nexthop; nexthop; nexthop = next) { next = nexthop->next; nexthop_free (nexthop); } XFREE (MTYPE_RIB, rib); } /** * copy_nexthop - copy a nexthop to the rib structure. */ static void rib_copy_nexthop (struct rib *state, struct nexthop *nh) { struct nexthop *nexthop; nexthop = nexthop_new(); nexthop->flags = nh->flags; nexthop->type = nh->type; nexthop->ifindex = nh->ifindex; if (nh->ifname) nexthop->ifname = XSTRDUP(0, nh->ifname); memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr)); memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr)); rib_nexthop_add(state, nexthop); } static void copy_state (struct rnh *rnh, struct rib *rib) { struct rib *state; struct nexthop *nh; if (rnh->state) { free_state(rnh->state); rnh->state = NULL; } if (!rib) return; state = XCALLOC (MTYPE_RIB, sizeof (struct rib)); state->type = rib->type; state->metric = rib->metric; for (nh = rib->nexthop; nh; nh = nh->next) rib_copy_nexthop(state, nh); rnh->state = state; } static int compare_state (struct rib *r1, struct rib *r2) { struct nexthop *nh1; struct nexthop *nh2; u_char found_nh = 0; if (!r1 && !r2) return 0; if ((!r1 && r2) || (r1 && !r2)) return 1; if (r1->metric != r2->metric) return 1; if (r1->nexthop_num != r2->nexthop_num) return 1; /* We need to verify that the nexthops for r1 match the nexthops for r2. * Since it is possible for a rib entry to have the same nexthop multiple * times (Example: [a,a]) we need to keep track of which r2 nexthops we have * already used as a match against a r1 nexthop. We track this * via NEXTHOP_FLAG_MATCHED. Clear this flag for all r2 nexthops when you * are finished. * * TRUE: r1 [a,b], r2 [a,b] * TRUE: r1 [a,b], r2 [b,a] * FALSE: r1 [a,b], r2 [a,c] * FALSE: r1 [a,a], r2 [a,b] */ for (nh1 = r1->nexthop; nh1; nh1 = nh1->next) { found_nh = 0; for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) { if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) continue; if (nexthop_same_no_recurse(nh1, nh2)) { SET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); found_nh = 1; break; } } if (!found_nh) { for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); return 1; } } for (nh2 = r2->nexthop; nh2; nh2 = nh2->next) if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED)) UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED); return 0; } static int send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) { struct stream *s; struct rib *rib; unsigned long nump; u_char num; struct nexthop *nexthop; struct route_node *rn; rn = rnh->node; rib = rnh->state; /* Get output stream. */ s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id); stream_putw(s, rn->p.family); stream_put_prefix (s, &rn->p); if (rib) { stream_putl (s, rib->metric); num = 0; nump = stream_get_endp(s); stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) && ! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { 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; case ZEBRA_NEXTHOP_IPV4_IFINDEX: case ZEBRA_NEXTHOP_IPV4_IFNAME: stream_put_in_addr (s, &nexthop->gate.ipv4); stream_putl (s, nexthop->ifindex); break; #ifdef HAVE_IPV6 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; #endif /* HAVE_IPV6 */ default: /* do nothing */ 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)); client->nh_last_upd_time = quagga_time(NULL); client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE; return zebra_server_send_message(client); } static void print_nh (struct nexthop *nexthop, struct vty *vty) { char buf[BUFSIZ]; 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_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, " 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"); break; default: break; } vty_out(vty, "%s", VTY_NEWLINE); } static void print_rnh (struct route_node *rn, struct vty *vty) { struct rnh *rnh; struct nexthop *nexthop; struct listnode *node; struct zserv *client; char buf[BUFSIZ]; rnh = rn->info; vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), VTY_NEWLINE); if (rnh->state) { vty_out(vty, " resolved via %s%s", zebra_route_string(rnh->state->type), VTY_NEWLINE); for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next) print_nh(nexthop, vty); } else vty_out(vty, " unresolved%s%s", CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "", VTY_NEWLINE); vty_out(vty, " Client list:"); for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) vty_out(vty, " %s(fd %d)", zebra_route_string(client->proto), client->sock); vty_out(vty, "%s", VTY_NEWLINE); } quagga-1.2.4/zebra/zebra_rnh.h000066400000000000000000000034651325323223500162210ustar00rootroot00000000000000/* * Zebra next hop tracking header * Copyright (C) 2013 Cumulus Networks, 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. */ #ifndef _ZEBRA_RNH_H #define _ZEBRA_RNH_H #include "prefix.h" #include "vty.h" /* Nexthop structure. */ struct rnh { u_char flags; #define ZEBRA_NHT_CONNECTED 0x1 struct rib *state; struct list *client_list; struct route_node *node; }; extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid); extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid); extern void zebra_delete_rnh(struct rnh *rnh); extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id_t); extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client); extern int zebra_evaluate_rnh_table(vrf_id_t vrfid, int family); extern int zebra_dispatch_rnh_table(vrf_id_t vrfid, int family, struct zserv *cl); extern void zebra_print_rnh_table(vrf_id_t vrfid, int family, struct vty *vty); extern char *rnh_str(struct rnh *rnh, char *buf, int size); extern int zebra_cleanup_rnh_client(vrf_id_t vrf, int family, struct zserv *client); #endif /*_ZEBRA_RNH_H */ quagga-1.2.4/zebra/zebra_rnh_null.c000066400000000000000000000003661325323223500172430ustar00rootroot00000000000000#include #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/zebra_rnh.h" int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) { return 0; } void zebra_print_rnh_table (vrf_id_t vrfid, int family, struct vty *vty) {} quagga-1.2.4/zebra/zebra_routemap.c000066400000000000000000000444241325323223500172610ustar00rootroot00000000000000/* zebra routemap. * Copyright (C) 2006 IBM Corporation * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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 "rib.h" #include "routemap.h" #include "command.h" #include "filter.h" #include "plist.h" #include "vrf.h" #include "nexthop.h" #include "zebra/zserv.h" /* Add zebra route map rule */ static int zebra_route_match_add(struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete zebra route map rule. */ static int zebra_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Add zebra route map rule. */ static int zebra_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete zebra route map rule. */ static int zebra_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Zebra Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Zebra Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct nexthop_vrfid *nh_vrf; struct nexthop *nexthop; char *ifname = rule; ifindex_t ifindex; if (type == RMAP_ZEBRA) { if (strcasecmp(ifname, "any") == 0) return RMAP_MATCH; nh_vrf = object; if (!nh_vrf) return RMAP_NOMATCH; ifindex = ifname2ifindex_vrf (ifname, nh_vrf->vrf_id); if (ifindex == 0) return RMAP_NOMATCH; nexthop = nh_vrf->nexthop; if (!nexthop) return RMAP_NOMATCH; if (nexthop->ifindex == ifindex) return RMAP_MATCH; } return RMAP_NOMATCH; } /* Route map `match interface' match statement. `arg' is IFNAME value */ static void * route_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `match interface' value. */ static 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 }; DEFUN (match_interface, match_interface_cmd, "match interface WORD", MATCH_STR "match first hop interface of route\n" "Interface name\n") { return zebra_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 zebra_route_match_delete (vty, vty->index, "interface", NULL); return zebra_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 zebra_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 zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL); return zebra_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 zebra_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 zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); return zebra_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 zebra_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 zebra_route_match_delete (vty, vty->index, "ip address", NULL); return zebra_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 zebra_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 zebra_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); return zebra_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_src, set_src_cmd, "set src A.B.C.D", SET_STR "src address for route\n" "src address\n") { struct in_addr src; struct interface *pif = NULL; vrf_iter_t iter; if (inet_pton(AF_INET, argv[0], &src) <= 0) { vty_out (vty, "%% not a local address%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((pif = if_lookup_exact_address_vrf (src, vrf_iter2id (iter))) != NULL) break; if (!pif) { vty_out (vty, "%% not a local address%s", VTY_NEWLINE); return CMD_WARNING; } return zebra_route_set_add (vty, vty->index, "src", argv[0]); } DEFUN (no_set_src, no_set_src_cmd, "no set src", NO_STR SET_STR "Source address for route\n") { if (argc == 0) return zebra_route_set_delete (vty, vty->index, "src", NULL); return zebra_route_set_delete (vty, vty->index, "src", argv[0]); } ALIAS (no_set_src, no_set_src_val_cmd, "no set src (A.B.C.D)", NO_STR SET_STR "src address for route\n" "src address\n") /*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ /* `match ip next-hop IP_ACCESS_LIST' */ /* Match function return 1 if match is success else return zero. */ static 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 nexthop *nexthop; struct nexthop_vrfid *nh_vrf; struct prefix_ipv4 p; if (type == RMAP_ZEBRA) { nh_vrf = object; nexthop = nh_vrf->nexthop; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: /* Interface routes can't match ip next-hop */ return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; p.prefix = nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; default: return RMAP_NOMATCH; } 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. */ static void * route_match_ip_next_hop_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `. */ static void route_match_ip_next_hop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip next-hop matching. */ static 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' */ static 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 nexthop *nexthop; struct nexthop_vrfid *nh_vrf; struct prefix_ipv4 p; if (type == RMAP_ZEBRA) { nh_vrf = object; nexthop = nh_vrf->nexthop; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: /* Interface routes can't match ip next-hop */ return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; p.prefix = nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; default: return RMAP_NOMATCH; } 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; } static void * route_match_ip_next_hop_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_next_hop_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static 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. */ static 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_ZEBRA) { 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. */ static void * route_match_ip_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_address_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ static 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' */ static 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_ZEBRA) { 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; } static void * route_match_ip_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_address_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static 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 src A.B.C.D' */ /* Set src. */ static route_map_result_t route_set_src (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { if (type == RMAP_ZEBRA) { struct nexthop_vrfid *nh_vrf; nh_vrf = object; nh_vrf->nexthop->src = *(union g_addr *)rule; } return RMAP_OKAY; } /* set src compilation. */ static void * route_set_src_compile (const char *arg) { union g_addr src, *psrc; if (inet_pton(AF_INET, arg, &src.ipv4) != 1 #ifdef HAVE_IPV6 && inet_pton(AF_INET6, arg, &src.ipv6) != 1 #endif /* HAVE_IPV6 */ ) return NULL; psrc = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union g_addr)); *psrc = src; return psrc; } /* Free route map's compiled `set src' value. */ static void route_set_src_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set src rule structure. */ static struct route_map_rule_cmd route_set_src_cmd = { "src", route_set_src, route_set_src_compile, route_set_src_free, }; void zebra_route_map_init () { route_map_init (); route_map_init_vty (); 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_src_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_src_cmd); install_element (RMAP_NODE, &no_set_src_cmd); } quagga-1.2.4/zebra/zebra_snmp.c000066400000000000000000000361271325323223500164030ustar00rootroot00000000000000/* 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. */ /* * Currently SNMP is only running properly for MIBs in the default VRF. */ #include #ifdef HAVE_SNMP #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "command.h" #include "smux.h" #include "table.h" #include "vrf.h" #include "zebra/rib.h" #include "zebra/zserv.h" #define IPFWMIB 1,3,6,1,2,1,4,24 /* 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 extern struct zebra_t zebrad; oid ipfw_oid [] = { IPFWMIB }; /* Hook functions. */ static u_char * ipFwNumber (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char * ipFwTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char * ipCidrNumber (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char * ipCidrTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); 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}} }; static 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 = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return NULL; /* Return number of routing entries. */ result = 0; for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) result++; return (u_char *)&result; } static 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 = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return 0; /* Return number of routing entries. */ result = 0; for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) result++; return (u_char *)&result; } static 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; } static 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; } static 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 */ } } static 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; } static 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 != (unsigned) v->namelen + 10)) return; table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) return; /* Get INDEX information out of OID. * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop */ if (*objid_len > (unsigned) v->namelen) oid2in_addr (objid + v->namelen, MIN(4, *objid_len - v->namelen), &dest); if (*objid_len > (unsigned) v->namelen + 4) proto = objid[v->namelen + 4]; if (*objid_len > (unsigned) v->namelen + 5) policy = objid[v->namelen + 5]; if (*objid_len > (unsigned) 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 >= (unsigned) 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)) { RNODE_FOREACH_RIB (*np, *rib) { 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) RNODE_FOREACH_RIB (np2, rib2) 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 */ RNODE_FOREACH_RIB (np2, rib2) { 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; } static 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; if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; 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; } static u_char * ipCidrTable (struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; switch (v->magic) { case IPCIDRROUTEDEST: break; default: return NULL; break; } return NULL; } void zebra_snmp_init () { smux_init (zebrad.master); REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid); } #endif /* HAVE_SNMP */ quagga-1.2.4/zebra/zebra_vty.c000066400000000000000000005231711325323223500162500ustar00rootroot00000000000000/* 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 "memory.h" #include "if.h" #include "prefix.h" #include "command.h" #include "table.h" #include "rib.h" #include "vrf.h" #include "nexthop.h" #include "zebra/zserv.h" #include "zebra/zebra_rnh.h" static int do_show_ip_route(struct vty *vty, safi_t safi, vrf_id_t vrf_id); static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast); static void vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib); /* General function for static route. */ static int zebra_static_ipv4_safi (struct vty *vty, safi_t safi, int add_cmd, const char *dest_str, const char *mask_str, const char *gate_str, const char *flag_str, const char *tag_str, const char *distance_str, const char *vrf_id_str) { int ret; u_char distance; struct prefix p; struct in_addr gate; struct in_addr mask; const char *ifname; u_char flag = 0; route_tag_t tag = 0; vrf_id_t vrf_id = VRF_DEFAULT; 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; /* tag */ if (tag_str) tag = atoi (tag_str); /* VRF id */ if (vrf_id_str) VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str); /* tag */ if (tag_str) tag = atoi(tag_str); /* Null0 static route. */ if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)) { if (flag_str) { vty_out (vty, "%% can not have flag %s with Null0%s", flag_str, VTY_NEWLINE); return CMD_WARNING; } if (add_cmd) static_add_ipv4_safi (safi, &p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, tag, distance, vrf_id); else static_delete_ipv4_safi (safi, &p, NULL, NULL, tag, distance, vrf_id); return CMD_SUCCESS; } /* Route flags */ if (flag_str) { switch(flag_str[0]) { case 'r': case 'R': /* XXX */ SET_FLAG (flag, ZEBRA_FLAG_REJECT); break; case 'b': case 'B': /* XXX */ SET_FLAG (flag, ZEBRA_FLAG_BLACKHOLE); break; default: vty_out (vty, "%% Malformed flag %s %s", flag_str, VTY_NEWLINE); return CMD_WARNING; } } if (gate_str == NULL) { if (add_cmd) static_add_ipv4_safi (safi, &p, NULL, NULL, flag, tag, distance, vrf_id); else static_delete_ipv4_safi (safi, &p, NULL, NULL, tag, distance, vrf_id); 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_safi (safi, &p, ifname ? NULL : &gate, ifname, flag, tag, distance, vrf_id); else static_delete_ipv4_safi (safi, &p, ifname ? NULL : &gate, ifname, tag, distance, vrf_id); return CMD_SUCCESS; } /* Static unicast routes for multicast RPF lookup. */ DEFUN (ip_mroute_dist, ip_mroute_dist_cmd, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n") { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], NULL, NULL, argc > 2 ? argv[2] : NULL, NULL); } ALIAS (ip_mroute_dist, ip_mroute_cmd, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n") DEFUN (ip_mroute_dist_vrf, ip_mroute_dist_vrf_cmd, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255> " VRF_CMD_STR, IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n" VRF_CMD_HELP_STR) { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 1, argv[0], NULL, argv[1], NULL, NULL, argc > 3 ? argv[2] : NULL, argc > 3 ? argv[3] : argv[2]); } ALIAS (ip_mroute_dist_vrf, ip_mroute_vrf_cmd, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) "VRF_CMD_STR, IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" VRF_CMD_HELP_STR) DEFUN (no_ip_mroute_dist, no_ip_mroute_dist_cmd, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n") { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], NULL, NULL, argc > 2 ? argv[2] : NULL, NULL); } ALIAS (no_ip_mroute_dist, no_ip_mroute_cmd, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", NO_STR IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n") DEFUN (no_ip_mroute_dist_vrf, no_ip_mroute_dist_vrf_cmd, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255> " VRF_CMD_STR, IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n" VRF_CMD_HELP_STR) { VTY_WARN_EXPERIMENTAL(); return zebra_static_ipv4_safi(vty, SAFI_MULTICAST, 0, argv[0], NULL, argv[1], NULL, NULL, argc > 3 ? argv[2] : NULL, argc > 3 ? argv[3] : argv[2]); } ALIAS (no_ip_mroute_dist_vrf, no_ip_mroute_vrf_cmd, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) " VRF_CMD_STR, NO_STR IP_STR "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" VRF_CMD_HELP_STR) DEFUN (ip_multicast_mode, ip_multicast_mode_cmd, "ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", IP_STR "Multicast options\n" "RPF lookup behavior\n" "Lookup in unicast RIB only\n" "Lookup in multicast RIB only\n" "Try multicast RIB first, fall back to unicast RIB\n" "Lookup both, use entry with lower distance\n" "Lookup both, use entry with longer prefix\n") { VTY_WARN_EXPERIMENTAL(); if (!strncmp (argv[0], "u", 1)) multicast_mode_ipv4_set (MCAST_URIB_ONLY); else if (!strncmp (argv[0], "mrib-o", 6)) multicast_mode_ipv4_set (MCAST_MRIB_ONLY); else if (!strncmp (argv[0], "mrib-t", 6)) multicast_mode_ipv4_set (MCAST_MIX_MRIB_FIRST); else if (!strncmp (argv[0], "low", 3)) multicast_mode_ipv4_set (MCAST_MIX_DISTANCE); else if (!strncmp (argv[0], "lon", 3)) multicast_mode_ipv4_set (MCAST_MIX_PFXLEN); else { vty_out (vty, "Invalid mode specified%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (no_ip_multicast_mode, no_ip_multicast_mode_cmd, "no ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", NO_STR IP_STR "Multicast options\n" "RPF lookup behavior\n" "Lookup in unicast RIB only\n" "Lookup in multicast RIB only\n" "Try multicast RIB first, fall back to unicast RIB\n" "Lookup both, use entry with lower distance\n" "Lookup both, use entry with longer prefix\n") { multicast_mode_ipv4_set (MCAST_NO_CONFIG); return CMD_SUCCESS; } ALIAS (no_ip_multicast_mode, no_ip_multicast_mode_noarg_cmd, "no ip multicast rpf-lookup-mode", NO_STR IP_STR "Multicast options\n" "RPF lookup behavior\n") DEFUN (show_ip_rpf, show_ip_rpf_cmd, "show ip rpf", SHOW_STR IP_STR "Display RPF information for multicast source\n") { vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); VTY_WARN_EXPERIMENTAL(); return do_show_ip_route(vty, SAFI_MULTICAST, vrf_id); } ALIAS (show_ip_rpf, show_ip_rpf_vrf_cmd, "show ip rpf " VRF_CMD_STR, SHOW_STR IP_STR "Display RPF information for multicast source\n" VRF_CMD_HELP_STR) DEFUN (show_ip_rpf_addr, show_ip_rpf_addr_cmd, "show ip rpf A.B.C.D", SHOW_STR IP_STR "Display RPF information for multicast source\n" "IP multicast source address (e.g. 10.0.0.0)\n") { struct in_addr addr; struct route_node *rn; struct rib *rib; vrf_id_t vrf_id = VRF_DEFAULT; int ret; if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); VTY_WARN_EXPERIMENTAL(); ret = inet_aton (argv[0], &addr); if (ret == 0) { vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } rib = rib_match_ipv4_multicast (addr, &rn, vrf_id); if (rib) vty_show_ip_route_detail (vty, rn, 1); else vty_out (vty, "%% No match for RPF lookup%s", VTY_NEWLINE); return CMD_SUCCESS; } ALIAS (show_ip_rpf_addr, show_ip_rpf_addr_vrf_cmd, "show ip rpf A.B.C.D " VRF_CMD_STR, SHOW_STR IP_STR "Display RPF information for multicast source\n" "IP multicast source address (e.g. 10.0.0.0)\n" VRF_CMD_HELP_STR) DEFUN (show_ip_rpf_vrf_all, show_ip_rpf_vrf_all_cmd, "show ip rpf " VRF_ALL_CMD_STR, SHOW_STR IP_STR "Display RPF information for multicast source\n" VRF_ALL_CMD_HELP_STR) { struct zebra_vrf *zvrf; struct route_table *table; struct route_node *rn; struct rib *rib; vrf_iter_t iter; int first = 1; VTY_WARN_EXPERIMENTAL(); for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP][SAFI_MULTICAST]) == NULL) continue; /* Show all IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (first) { vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } DEFUN (show_ip_rpf_addr_vrf_all, show_ip_rpf_addr_vrf_all_cmd, "show ip rpf A.B.C.D " VRF_ALL_CMD_STR, SHOW_STR IP_STR "Display RPF information for multicast source\n" "IP multicast source address (e.g. 10.0.0.0)\n" VRF_ALL_CMD_HELP_STR) { struct in_addr addr; struct route_node *rn; vrf_iter_t iter; int ret; VTY_WARN_EXPERIMENTAL(); ret = inet_aton (argv[0], &addr); if (ret == 0) { vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if (rib_match_ipv4_multicast (addr, &rn, vrf_iter2id (iter))) vty_show_ip_route_detail (vty, rn, 1); } 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_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], NULL, NULL, NULL, NULL); } DEFUN (ip_route_tag, ip_route_tag_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", 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" "Set tag for this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], NULL, argv[2], NULL, NULL); } DEFUN (ip_route_tag_vrf, ip_route_tag_vrf_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], NULL, argv[2], NULL, argv[3]); } DEFUN (ip_route_flags, ip_route_flags_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], argv[2], NULL, NULL, NULL); } DEFUN (ip_route_flags_tag, ip_route_flags_tag_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], argv[2], argv[3], NULL, NULL); } DEFUN (ip_route_flags_tag_vrf, ip_route_flags_tag_vrf_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>" VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], argv[2], argv[3], NULL, argv[4]); } DEFUN (ip_route_flags2, ip_route_flags2_cmd, "ip route A.B.C.D/M (reject|blackhole)", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, argv[1], NULL, NULL, NULL); } DEFUN (ip_route_flags2_tag, ip_route_flags2_tag_cmd, "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, argv[1], argv[2], NULL, NULL); } DEFUN (ip_route_flags2_tag_vrf, ip_route_flags2_tag_vrf_cmd, "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, argv[1], argv[2], NULL, argv[3]); } /* 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_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], NULL, NULL, NULL, NULL); } DEFUN (ip_route_mask_tag, ip_route_mask_tag_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", 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" "Set tag for this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL); } DEFUN (ip_route_mask_tag_vrf, ip_route_mask_tag_vrf_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]); } DEFUN (ip_route_mask_flags, ip_route_mask_flags_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL, NULL); } DEFUN (ip_route_mask_flags_tag, ip_route_mask_flags_tag_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, NULL); } DEFUN (ip_route_mask_flags_tag_vrf, ip_route_mask_flags_tag_vrf_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>" VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, argv[5]); } DEFUN (ip_route_mask_flags2, ip_route_mask_flags2_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole)", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL, NULL); } DEFUN (ip_route_mask_flags2_tag, ip_route_mask_flags2_tag_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, NULL); } DEFUN (ip_route_mask_flags2_tag_vrf, ip_route_mask_flags2_tag_vrf_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, argv[4]); } /* 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_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], NULL, NULL, argv[2], NULL); } DEFUN (ip_route_tag_distance, ip_route_tag_distance_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], NULL, argv[2], argv[3], NULL); } DEFUN (ip_route_tag_distance_vrf, ip_route_tag_distance_vrf_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], NULL, argv[2], argv[3], argv[4]); } DEFUN (ip_route_flags_distance, ip_route_flags_distance_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], argv[2], NULL, argv[3], NULL); } DEFUN (ip_route_flags_tag_distance, ip_route_flags_tag_distance_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], argv[2], argv[3], argv[4], NULL); } DEFUN (ip_route_flags_tag_distance_vrf, ip_route_flags_tag_distance_vrf_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], argv[2], argv[3], argv[4], argv[5]); } DEFUN (ip_route_flags_distance2, ip_route_flags_distance2_cmd, "ip route A.B.C.D/M (reject|blackhole) <1-255>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, argv[1], NULL, argv[2], NULL); } DEFUN (ip_route_flags_tag_distance2, ip_route_flags_tag_distance2_cmd, "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, argv[1], argv[2], argv[3], NULL); } DEFUN (ip_route_flags_tag_distance2_vrf, ip_route_flags_tag_distance2_vrf_cmd, "ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, argv[1], argv[2], argv[3], argv[4]); } 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_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3], NULL); } DEFUN (ip_route_mask_tag_distance, ip_route_mask_tag_distance_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL); } DEFUN (ip_route_mask_tag_distance_vrf, ip_route_mask_tag_distance_vrf_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]); } DEFUN (ip_route_mask_flags_tag_distance, ip_route_mask_flags_tag_distance_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); } DEFUN (ip_route_mask_flags_tag_distance_vrf, ip_route_mask_flags_tag_distance_vrf_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); } DEFUN (ip_route_mask_flags_distance, ip_route_mask_flags_distance_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], NULL); } DEFUN (ip_route_mask_flags_distance2, ip_route_mask_flags_distance2_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3], NULL); } DEFUN (ip_route_mask_flags_tag_distance2, ip_route_mask_flags_tag_distance2_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL); } DEFUN (ip_route_mask_flags_tag_distance2_vrf, ip_route_mask_flags_tag_distance2_vrf_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Set tag for this route\n" "Tag value\n" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]); } 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_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], NULL, NULL, NULL, NULL); } DEFUN (no_ip_route_tag, no_ip_route_tag_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", 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" "Tag of this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], NULL, argv[2], NULL, NULL); } DEFUN (no_ip_route_tag_vrf, no_ip_route_tag_vrf_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295>" VRF_CMD_STR, 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" "Tag of this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], NULL, argv[2], NULL, argv[3]); } ALIAS (no_ip_route, no_ip_route_flags_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") ALIAS (no_ip_route_tag, no_ip_route_flags_tag_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n") DEFUN (no_ip_route_flags2, no_ip_route_flags2_cmd, "no ip route A.B.C.D/M (reject|blackhole)", NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, NULL, NULL, NULL, NULL); } DEFUN (no_ip_route_flags2_tag, no_ip_route_flags2_tag_cmd, "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, NULL, argv[1], NULL, NULL); } DEFUN (no_ip_route_flags2_tag_vrf, no_ip_route_flags2_tag_vrf_cmd, "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, NULL, argv[1], NULL, argv[2]); } 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_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL, NULL); } DEFUN (no_ip_route_mask_tag, no_ip_route_mask_tag_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295>", 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" "Tag of this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL); } ALIAS (no_ip_route_mask, no_ip_route_mask_flags_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") ALIAS (no_ip_route_mask_tag, no_ip_route_mask_flags_tag_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295>", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n") DEFUN (no_ip_route_mask_flags2, no_ip_route_mask_flags2_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole)", NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, NULL, NULL, NULL, NULL); } DEFUN (no_ip_route_mask_flags2_tag, no_ip_route_mask_flags2_tag_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>", NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL); } DEFUN (no_ip_route_mask_flags2_tag_vrf, no_ip_route_mask_flags2_tag_vrf_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]); } 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_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], NULL, NULL, argv[2], NULL); } DEFUN (no_ip_route_tag_distance, no_ip_route_tag_distance_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <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" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], NULL, argv[2], argv[3], NULL); } DEFUN (no_ip_route_tag_distance_vrf, no_ip_route_tag_distance_vrf_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" VRF_CMD_STR, 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" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], NULL, argv[2], argv[3], argv[4]); } DEFUN (no_ip_route_flags_distance, no_ip_route_flags_distance_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], argv[2], NULL, argv[3], NULL); } DEFUN (no_ip_route_flags_tag_distance, no_ip_route_flags_tag_distance_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], argv[2], argv[3], argv[4], NULL); } DEFUN (no_ip_route_flags_tag_distance_vrf, no_ip_route_flags_tag_distance_vrf_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], argv[2], argv[3], argv[4], argv[5]); } DEFUN (no_ip_route_flags_distance2, no_ip_route_flags_distance2_cmd, "no ip route A.B.C.D/M (reject|blackhole) <1-255>", NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, argv[1], NULL, argv[2], NULL); } DEFUN (no_ip_route_flags_tag_distance2, no_ip_route_flags_tag_distance2_cmd, "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, argv[1], argv[2] , argv[3], NULL); } DEFUN (no_ip_route_flags_tag_distance2_vrf, no_ip_route_flags_tag_distance2_vrf_cmd, "no ip route A.B.C.D/M (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, argv[1], argv[2] , argv[3], argv[4]); } 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_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3], NULL); } DEFUN (no_ip_route_mask_tag_distance, no_ip_route_mask_tag_distance_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <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" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL); } DEFUN (no_ip_route_mask_tag_distance_vrf, no_ip_route_mask_tag_distance_vrf_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-4294967295> <1-255>" VRF_CMD_STR, 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" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]); } DEFUN (no_ip_route_mask_flags_distance, no_ip_route_mask_flags_distance_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], NULL); } DEFUN (no_ip_route_mask_flags_tag_distance, no_ip_route_mask_flags_tag_distance_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); } DEFUN (no_ip_route_mask_flags_tag_distance_vrf, no_ip_route_mask_flags_tag_distance_vrf_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); } DEFUN (no_ip_route_mask_flags_distance2, no_ip_route_mask_flags_distance2_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3], NULL); } DEFUN (ip_route_vrf, ip_route_vrf_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " VRF_CMD_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" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], NULL, NULL, NULL, argv[2]); } DEFUN (ip_route_flags_vrf, ip_route_flags_vrf_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) " VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], argv[2], NULL, NULL, argv[3]); } DEFUN (ip_route_flags2_vrf, ip_route_flags2_vrf_cmd, "ip route A.B.C.D/M (reject|blackhole) " VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, argv[1], NULL, NULL, argv[2]); } /* Mask as A.B.C.D format. */ DEFUN (ip_route_mask_vrf, ip_route_mask_vrf_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " VRF_CMD_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" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], NULL, NULL, NULL, argv[3]); } DEFUN (ip_route_mask_flags_vrf, ip_route_mask_flags_vrf_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) " VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL, argv[4]); } DEFUN (ip_route_mask_flags2_vrf, ip_route_mask_flags2_vrf_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole) " VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL, argv[3]); } /* Distance option value. */ DEFUN (ip_route_distance_vrf, ip_route_distance_vrf_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255> " VRF_CMD_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" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], NULL, NULL, argv[2], argv[3]); } DEFUN (ip_route_flags_distance_vrf, ip_route_flags_distance_vrf_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, argv[1], argv[2], NULL, argv[3], argv[4]); } DEFUN (ip_route_flags_distance2_vrf, ip_route_flags_distance2_vrf_cmd, "ip route A.B.C.D/M (reject|blackhole) <1-255> " VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], NULL, NULL, argv[1], NULL, argv[2], argv[3]); } DEFUN (ip_route_mask_distance_vrf, ip_route_mask_distance_vrf_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255> " VRF_CMD_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" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3], argv[4]); } DEFUN (ip_route_mask_flags_distance_vrf, ip_route_mask_flags_distance_vrf_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], argv[5]); } DEFUN (ip_route_mask_flags_distance2_vrf, ip_route_mask_flags_distance2_vrf_cmd, "ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255> " VRF_CMD_STR, IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3], argv[4]); } DEFUN (no_ip_route_vrf, no_ip_route_vrf_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], NULL, NULL, NULL, (argc > 3) ? argv[3] : argv[2]); } ALIAS (no_ip_route_vrf, no_ip_route_flags_vrf_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) " VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) DEFUN (no_ip_route_flags2_vrf, no_ip_route_flags2_vrf_cmd, "no ip route A.B.C.D/M (reject|blackhole) " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, NULL, NULL, NULL, argv[2]); } DEFUN (no_ip_route_mask_vrf, no_ip_route_mask_vrf_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL, (argc > 4) ? argv[4] : argv[3]); } ALIAS (no_ip_route_mask_vrf, no_ip_route_mask_flags_vrf_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) " VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) DEFUN (no_ip_route_mask_flags2_vrf, no_ip_route_mask_flags2_vrf_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole) " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, NULL, NULL, NULL, argv[2]); } DEFUN (no_ip_route_distance_vrf, no_ip_route_distance_vrf_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255> " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], NULL, NULL, argv[2], argv[3]); } DEFUN (no_ip_route_flags_distance_vrf, no_ip_route_flags_distance_vrf_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, argv[1], argv[2], NULL, argv[3], argv[4]); } DEFUN (no_ip_route_flags_distance2_vrf, no_ip_route_flags_distance2_vrf_cmd, "no ip route A.B.C.D/M (reject|blackhole) <1-255> " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], NULL, NULL, argv[1], NULL, argv[2], argv[3]); } DEFUN (no_ip_route_mask_distance_vrf, no_ip_route_mask_distance_vrf_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255> " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3], argv[4]); } DEFUN (no_ip_route_mask_flags_distance_vrf, no_ip_route_mask_flags_distance_vrf_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], argv[5]); } DEFUN (no_ip_route_mask_flags_distance2_vrf, no_ip_route_mask_flags_distance2_vrf_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255> " VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3], argv[4]); } DEFUN (no_ip_route_mask_flags_tag_distance2, no_ip_route_mask_flags_tag_distance2_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>", NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n") { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL); } DEFUN (no_ip_route_mask_flags_tag_distance2_vrf, no_ip_route_mask_flags_tag_distance2_vrf_cmd, "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Tag of this route\n" "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR) { return zebra_static_ipv4_safi (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]); } char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; /* "any" == ZEBRA_ROUTE_MAX */ DEFUN (ip_protocol, ip_protocol_cmd, "ip protocol PROTO route-map ROUTE-MAP", NO_STR "Apply route map to PROTO\n" "Protocol name\n" "Route map name\n") { int i; if (strcasecmp(argv[0], "any") == 0) i = ZEBRA_ROUTE_MAX; else i = proto_name2num(argv[0]); if (i < 0) { vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", VTY_NEWLINE); return CMD_WARNING; } if (proto_rm[AFI_IP][i]) XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]); proto_rm[AFI_IP][i] = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[1]); return CMD_SUCCESS; } DEFUN (no_ip_protocol, no_ip_protocol_cmd, "no ip protocol PROTO", NO_STR "Remove route map from PROTO\n" "Protocol name\n") { int i; if (strcasecmp(argv[0], "any") == 0) i = ZEBRA_ROUTE_MAX; else i = proto_name2num(argv[0]); if (i < 0) { vty_out (vty, "invalid protocol name \"%s\"%s", argv[0] ? argv[0] : "", VTY_NEWLINE); return CMD_WARNING; } if (proto_rm[AFI_IP][i]) XFREE (MTYPE_ROUTE_MAP_NAME, proto_rm[AFI_IP][i]); proto_rm[AFI_IP][i] = NULL; return CMD_SUCCESS; } /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) { struct rib *rib; struct nexthop *nexthop, *tnexthop; int recursing; char buf[PREFIX_STRLEN]; RNODE_FOREACH_RIB (rn, rib) { const char *mcast_info = ""; if (mcast) { rib_table_info_t *info = rn->table->info; mcast_info = (info->safi == SAFI_MULTICAST) ? " using Multicast RIB" : " using Unicast RIB"; } vty_out (vty, "Routing entry for %s%s%s", prefix2str (&rn->p, buf, sizeof(buf)), mcast_info, VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (rib->mtu) vty_out (vty, ", mtu %u", rib->mtu); vty_out (vty, ", tag %d", rib->tag); vty_out (vty, ", vrf %u", rib->vrf_id); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE)) vty_out (vty, ", fib-override"); if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) vty_out (vty, ", fib"); if (rib->refcnt) vty_out (vty, ", refcnt %ld", rib->refcnt); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) vty_out (vty, ", blackhole"); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) vty_out (vty, ", reject"); 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_RIPNG || rib->type == ZEBRA_ROUTE_OSPF || rib->type == ZEBRA_ROUTE_OSPF6 || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS || rib->type == ZEBRA_ROUTE_NHRP || 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 (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { vty_out (vty, " %c%c%s", CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? '>' : ' ', CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', recursing ? " " : ""); 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_vrf (nexthop->ifindex, rib->vrf_id)); break; 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, sizeof(buf))); if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) vty_out (vty, ", %s", nexthop->ifname); else if (nexthop->ifindex) vty_out (vty, ", via %s", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " directly connected, %s", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IFNAME: vty_out (vty, " directly connected, %s", nexthop->ifname); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out (vty, " directly connected, Null0"); break; default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) vty_out (vty, " onlink"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out (vty, " (recursive)"); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: if (nexthop->src.ipv4.s_addr) { if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, sizeof buf)) vty_out (vty, ", src %s", buf); } break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFNAME: if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, sizeof buf)) vty_out (vty, ", src %s", buf); } break; #endif /* HAVE_IPV6 */ default: break; } vty_out (vty, "%s", VTY_NEWLINE); } vty_out (vty, "%s", VTY_NEWLINE); } } static void vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) { struct nexthop *nexthop, *tnexthop; int recursing; int len = 0; char buf[BUFSIZ]; /* Nexthop information. */ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (nexthop == rib->nexthop) { /* Prefix information. */ len = vty_out (vty, "%c%c%c %s", zebra_route_char (rib->type), CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ', CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', prefix2str (&rn->p, buf, sizeof buf)); /* 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); if (rib->vrf_id != VRF_DEFAULT) len += vty_out (vty, " [vrf %u]", rib->vrf_id); } else vty_out (vty, " %c%*c", CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', len - 3 + (2 * recursing), ' '); 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_vrf (nexthop->ifindex, rib->vrf_id)); break; 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_vrf (nexthop->ifindex, rib->vrf_id)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " is directly connected, %s", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); 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"); break; default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) vty_out (vty, " onlink"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out (vty, " (recursive)"); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: if (nexthop->src.ipv4.s_addr) { if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, sizeof buf)) vty_out (vty, ", src %s", buf); } break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFNAME: if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, sizeof buf)) vty_out (vty, ", src %s", buf); } break; #endif /* HAVE_IPV6 */ default: break; } if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) vty_out (vty, ", bh"); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) vty_out (vty, ", rej"); if (rib->type == ZEBRA_ROUTE_RIP || rib->type == ZEBRA_ROUTE_RIPNG || rib->type == ZEBRA_ROUTE_OSPF || rib->type == ZEBRA_ROUTE_OSPF6 || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS || rib->type == ZEBRA_ROUTE_NHRP || 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); } } DEFUN (show_ip_route, show_ip_route_cmd, "show ip route", SHOW_STR IP_STR "IP routing table\n") { vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); return do_show_ip_route(vty, SAFI_UNICAST, vrf_id); } static int do_show_ip_route(struct vty *vty, safi_t safi, vrf_id_t vrf_id) { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return CMD_SUCCESS; /* Show all IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (first) { vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ip_route, show_ip_route_vrf_cmd, "show ip route " VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" VRF_CMD_HELP_STR) DEFUN (show_ip_nht, show_ip_nht_cmd, "show ip nht", SHOW_STR IP_STR "IP nexthop tracking table\n") { zebra_print_rnh_table(0, AF_INET, vty); return CMD_SUCCESS; } DEFUN (show_ipv6_nht, show_ipv6_nht_cmd, "show ipv6 nht", SHOW_STR IP_STR "IPv6 nexthop tracking table\n") { zebra_print_rnh_table(0, AF_INET6, vty); return CMD_SUCCESS; } DEFUN (show_ip_route_tag, show_ip_route_tag_cmd, "show ip route tag <1-4294967295>", SHOW_STR IP_STR "IP routing table\n" "Show only routes with tag\n" "Tag value\n") { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; route_tag_t tag = 0; vrf_id_t vrf_id = VRF_DEFAULT; if (argv[0]) tag = atoi(argv[0]); if (argc == 2) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show all IPv4 routes with matching tag value. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (rib->tag != tag) continue; if (first) { vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ip_route_tag, show_ip_route_tag_vrf_cmd, "show ip route tag <1-4294967295>" VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Show only routes with tag\n" "Tag value\n" VRF_CMD_HELP_STR) 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; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix (argv[0], &p); if (! ret) { vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (prefix_match (&p, &rn->p)) { if (first) { vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ip_route_prefix_longer, show_ip_route_prefix_longer_vrf_cmd, "show ip route A.B.C.D/M longer-prefixes " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) 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; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { 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); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } ALIAS (show_ip_route_supernets, show_ip_route_supernets_vrf_cmd, "show ip route supernets-only " VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Show supernet entries only\n" VRF_CMD_HELP_STR) DEFUN (show_ip_route_protocol, show_ip_route_protocol_cmd, "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" QUAGGA_IP_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; vrf_id_t vrf_id = VRF_DEFAULT; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (rib->type == type) { if (first) { vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ip_route_protocol, show_ip_route_protocol_vrf_cmd, "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA " " VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" QUAGGA_IP_REDIST_HELP_STR_ZEBRA VRF_CMD_HELP_STR) 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; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) { vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); 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, 0); route_unlock_node (rn); return CMD_SUCCESS; } ALIAS (show_ip_route_addr, show_ip_route_addr_vrf_cmd, "show ip route A.B.C.D " VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Network in the IP routing table to display\n" VRF_CMD_HELP_STR) 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; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) { vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); 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); if (rn) route_unlock_node (rn); return CMD_WARNING; } vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); return CMD_SUCCESS; } ALIAS (show_ip_route_prefix, show_ip_route_prefix_vrf_cmd, "show ip route A.B.C.D/M " VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "IP prefix /, e.g., 35.0.0.0/8\n" VRF_CMD_HELP_STR) static void vty_show_ip_route_summary (struct vty *vty, struct route_table *table) { struct route_node *rn; struct rib *rib; struct nexthop *nexthop; #define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX #define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1) u_int32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1]; u_int32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1]; u_int32_t i; memset (&rib_cnt, 0, sizeof(rib_cnt)); memset (&fib_cnt, 0, sizeof(fib_cnt)); for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { rib_cnt[ZEBRA_ROUTE_TOTAL]++; rib_cnt[rib->type]++; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) || nexthop_has_fib_child(nexthop)) { fib_cnt[ZEBRA_ROUTE_TOTAL]++; fib_cnt[rib->type]++; } if (rib->type == ZEBRA_ROUTE_BGP && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) { rib_cnt[ZEBRA_ROUTE_IBGP]++; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) || nexthop_has_fib_child(nexthop)) fib_cnt[ZEBRA_ROUTE_IBGP]++; } } vty_out (vty, "%-20s %-20s %s (vrf %u)%s", "Route Source", "Routes", "FIB", ((rib_table_info_t *)table->info)->zvrf->vrf_id, VTY_NEWLINE); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (rib_cnt[i] > 0) { if (i == ZEBRA_ROUTE_BGP) { vty_out (vty, "%-20s %-20d %-20d %s", "ebgp", rib_cnt[ZEBRA_ROUTE_BGP] - rib_cnt[ZEBRA_ROUTE_IBGP], fib_cnt[ZEBRA_ROUTE_BGP] - fib_cnt[ZEBRA_ROUTE_IBGP], VTY_NEWLINE); vty_out (vty, "%-20s %-20d %-20d %s", "ibgp", rib_cnt[ZEBRA_ROUTE_IBGP], fib_cnt[ZEBRA_ROUTE_IBGP], VTY_NEWLINE); } else vty_out (vty, "%-20s %-20d %-20d %s", zebra_route_string(i), rib_cnt[i], fib_cnt[i], VTY_NEWLINE); } } vty_out (vty, "------%s", VTY_NEWLINE); vty_out (vty, "%-20s %-20d %-20d %s", "Totals", rib_cnt[ZEBRA_ROUTE_TOTAL], fib_cnt[ZEBRA_ROUTE_TOTAL], VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); } /* * Implementation of the ip route summary prefix command. * * This command prints the primary prefixes that have been installed by various * protocols on the box. * */ static void vty_show_ip_route_summary_prefix (struct vty *vty, struct route_table *table) { struct route_node *rn; struct rib *rib; struct nexthop *nexthop; #define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX #define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1) u_int32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1]; u_int32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1]; u_int32_t i; int cnt; memset (&rib_cnt, 0, sizeof(rib_cnt)); memset (&fib_cnt, 0, sizeof(fib_cnt)); for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { /* * In case of ECMP, count only once. */ cnt = 0; for (nexthop = rib->nexthop; (!cnt && nexthop); nexthop = nexthop->next) { cnt++; rib_cnt[ZEBRA_ROUTE_TOTAL]++; rib_cnt[rib->type]++; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { fib_cnt[ZEBRA_ROUTE_TOTAL]++; fib_cnt[rib->type]++; } if (rib->type == ZEBRA_ROUTE_BGP && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) { rib_cnt[ZEBRA_ROUTE_IBGP]++; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) fib_cnt[ZEBRA_ROUTE_IBGP]++; } } } vty_out (vty, "%-20s %-20s %s (vrf %u)%s", "Route Source", "Prefix Routes", "FIB", ((rib_table_info_t *)table->info)->zvrf->vrf_id, VTY_NEWLINE); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (rib_cnt[i] > 0) { if (i == ZEBRA_ROUTE_BGP) { vty_out (vty, "%-20s %-20d %-20d %s", "ebgp", rib_cnt[ZEBRA_ROUTE_BGP] - rib_cnt[ZEBRA_ROUTE_IBGP], fib_cnt[ZEBRA_ROUTE_BGP] - fib_cnt[ZEBRA_ROUTE_IBGP], VTY_NEWLINE); vty_out (vty, "%-20s %-20d %-20d %s", "ibgp", rib_cnt[ZEBRA_ROUTE_IBGP], fib_cnt[ZEBRA_ROUTE_IBGP], VTY_NEWLINE); } else vty_out (vty, "%-20s %-20d %-20d %s", zebra_route_string(i), rib_cnt[i], fib_cnt[i], VTY_NEWLINE); } } vty_out (vty, "------%s", VTY_NEWLINE); vty_out (vty, "%-20s %-20d %-20d %s", "Totals", rib_cnt[ZEBRA_ROUTE_TOTAL], fib_cnt[ZEBRA_ROUTE_TOTAL], VTY_NEWLINE); vty_out (vty, "%s", 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 route_table *table; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; vty_show_ip_route_summary (vty, table); return CMD_SUCCESS; } ALIAS (show_ip_route_summary, show_ip_route_summary_vrf_cmd, "show ip route summary " VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Summary of all routes\n" VRF_CMD_HELP_STR) /* Show route summary prefix. */ DEFUN (show_ip_route_summary_prefix, show_ip_route_summary_prefix_cmd, "show ip route summary prefix", SHOW_STR IP_STR "IP routing table\n" "Summary of all routes\n" "Prefix routes\n") { struct route_table *table; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; vty_show_ip_route_summary_prefix (vty, table); return CMD_SUCCESS; } ALIAS (show_ip_route_summary_prefix, show_ip_route_summary_prefix_vrf_cmd, "show ip route summary prefix " VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Summary of all routes\n" "Prefix routes\n" VRF_CMD_HELP_STR) DEFUN (show_ip_route_vrf_all, show_ip_route_vrf_all_cmd, "show ip route " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IP routing table\n" VRF_ALL_CMD_HELP_STR) { struct route_table *table; struct route_node *rn; struct rib *rib; struct zebra_vrf *zvrf; vrf_iter_t iter; int first = 1; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) continue; /* Show all IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (first) { vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } DEFUN (show_ip_route_prefix_longer_vrf_all, show_ip_route_prefix_longer_vrf_all_cmd, "show ip route A.B.C.D/M longer-prefixes " VRF_ALL_CMD_STR, 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" VRF_ALL_CMD_HELP_STR) { struct route_table *table; struct route_node *rn; struct rib *rib; struct prefix p; struct zebra_vrf *zvrf; vrf_iter_t iter; int ret; int first = 1; ret = str2prefix (argv[0], &p); if (! ret) { vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) continue; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (prefix_match (&p, &rn->p)) { if (first) { vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } DEFUN (show_ip_route_supernets_vrf_all, show_ip_route_supernets_vrf_all_cmd, "show ip route supernets-only " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Show supernet entries only\n" VRF_ALL_CMD_HELP_STR) { struct route_table *table; struct route_node *rn; struct rib *rib; struct zebra_vrf *zvrf; vrf_iter_t iter; u_int32_t addr; int first = 1; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) continue; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { 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); first = 0; } vty_show_ip_route (vty, rn, rib); } } } return CMD_SUCCESS; } DEFUN (show_ip_route_protocol_vrf_all, show_ip_route_protocol_vrf_all_cmd, "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA " " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IP routing table\n" QUAGGA_IP_REDIST_HELP_STR_ZEBRA VRF_ALL_CMD_HELP_STR) { int type; struct route_table *table; struct route_node *rn; struct rib *rib; struct zebra_vrf *zvrf; vrf_iter_t iter; int first = 1; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) continue; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (rib->type == type) { if (first) { vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } DEFUN (show_ip_route_addr_vrf_all, show_ip_route_addr_vrf_all_cmd, "show ip route A.B.C.D " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Network in the IP routing table to display\n" VRF_ALL_CMD_HELP_STR) { int ret; struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; struct zebra_vrf *zvrf; vrf_iter_t iter; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) { vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) continue; rn = route_node_match (table, (struct prefix *) &p); if (! rn) continue; vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); } return CMD_SUCCESS; } DEFUN (show_ip_route_prefix_vrf_all, show_ip_route_prefix_vrf_all_cmd, "show ip route A.B.C.D/M " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "IP prefix /, e.g., 35.0.0.0/8\n" VRF_ALL_CMD_HELP_STR) { int ret; struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; struct zebra_vrf *zvrf; vrf_iter_t iter; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) { vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP][SAFI_UNICAST]) == NULL) continue; rn = route_node_match (table, (struct prefix *) &p); if (! rn) continue; if (rn->p.prefixlen != p.prefixlen) { route_unlock_node (rn); continue; } vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); } return CMD_SUCCESS; } DEFUN (show_ip_route_summary_vrf_all, show_ip_route_summary_vrf_all_cmd, "show ip route summary " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Summary of all routes\n" VRF_ALL_CMD_HELP_STR) { struct zebra_vrf *zvrf; vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) vty_show_ip_route_summary (vty, zvrf->table[AFI_IP][SAFI_UNICAST]); return CMD_SUCCESS; } DEFUN (show_ip_route_summary_prefix_vrf_all, show_ip_route_summary_prefix_vrf_all_cmd, "show ip route summary prefix " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IP routing table\n" "Summary of all routes\n" "Prefix routes\n" VRF_ALL_CMD_HELP_STR) { struct zebra_vrf *zvrf; vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) vty_show_ip_route_summary_prefix (vty, zvrf->table[AFI_IP][SAFI_UNICAST]); return CMD_SUCCESS; } /* Write IPv4 static route configuration. */ static int static_config_ipv4 (struct vty *vty, safi_t safi, const char *cmd) { struct route_node *rn; struct static_route *si; struct route_table *stable; struct zebra_vrf *zvrf; vrf_iter_t iter; int write; write = 0; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (stable = zvrf->stable[AFI_IP][safi]) == NULL) continue; for (rn = route_top (stable); rn; rn = route_next (rn)) for (si = rn->info; si; si = si->next) { vty_out (vty, "%s %s/%d", cmd, inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); switch (si->type) { case STATIC_IPV4_GATEWAY: vty_out (vty, " %s", inet_ntoa (si->addr.ipv4)); break; case STATIC_IPV4_IFNAME: vty_out (vty, " %s", si->ifname); break; case STATIC_IPV4_BLACKHOLE: vty_out (vty, " Null0"); break; } /* flags are incompatible with STATIC_IPV4_BLACKHOLE */ if (si->type != STATIC_IPV4_BLACKHOLE) { if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) vty_out (vty, " %s", "reject"); if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) vty_out (vty, " %s", "blackhole"); } if (si->tag) vty_out (vty, " tag %d", si->tag); if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); if (si->vrf_id != VRF_DEFAULT) vty_out (vty, " vrf %u", si->vrf_id); vty_out (vty, "%s", VTY_NEWLINE); write = 1; } } return write; } DEFUN (show_ip_protocol, show_ip_protocol_cmd, "show ip protocol", SHOW_STR IP_STR "IP protocol filtering status\n") { int i; vty_out(vty, "Protocol : route-map %s", VTY_NEWLINE); vty_out(vty, "------------------------%s", VTY_NEWLINE); for (i=0;i", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Set tag for this route\n" "Tag value\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL); } DEFUN (ipv6_route_tag_vrf, ipv6_route_tag_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]); } DEFUN (ipv6_route_flags, ipv6_route_flags_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL, NULL); } DEFUN (ipv6_route_flags_tag, ipv6_route_flags_tag_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, NULL); } DEFUN (ipv6_route_flags_tag_vrf, ipv6_route_flags_tag_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>" VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL, argv[4]); } 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, NULL, NULL, NULL); } DEFUN (ipv6_route_ifname_tag, ipv6_route_ifname_tag_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Set tag for this route\n" "Tag value\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL); } DEFUN (ipv6_route_ifname_tag_vrf, ipv6_route_ifname_tag_vrf_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]); } DEFUN (ipv6_route_ifname_flags, ipv6_route_ifname_flags_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL, NULL); } DEFUN (ipv6_route_ifname_flags_tag, ipv6_route_ifname_flags_tag_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>", IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, NULL); } DEFUN (ipv6_route_ifname_flags_tag_vrf, ipv6_route_ifname_flags_tag_vrf_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>" VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL, argv[5]); } DEFUN (ipv6_route_pref, ipv6_route_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], NULL, NULL, NULL, argv[2], NULL); } DEFUN (ipv6_route_pref_tag, ipv6_route_pref_tag_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3], NULL); } DEFUN (ipv6_route_pref_tag_vrf, ipv6_route_pref_tag_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <1-255>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3], argv[4]); } DEFUN (ipv6_route_flags_pref, ipv6_route_flags_pref_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3], NULL); } DEFUN (ipv6_route_flags_pref_tag, ipv6_route_flags_pref_tag_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL); } DEFUN (ipv6_route_flags_pref_tag_vrf, ipv6_route_flags_pref_tag_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]); } 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], NULL, NULL, argv[3], NULL); } DEFUN (ipv6_route_ifname_pref_tag, ipv6_route_ifname_pref_tag_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL); } DEFUN (ipv6_route_ifname_pref_tag_vrf, ipv6_route_ifname_pref_tag_vrf_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <1-255>" VRF_CMD_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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]); } DEFUN (ipv6_route_ifname_flags_pref, ipv6_route_ifname_flags_pref_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], NULL); } DEFUN (ipv6_route_ifname_flags_pref_tag, ipv6_route_ifname_flags_pref_tag_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); } DEFUN (ipv6_route_ifname_flags_pref_tag_vrf, ipv6_route_ifname_flags_pref_tag_vrf_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); } DEFUN (no_ipv6_route, no_ipv6_route_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], NULL, NULL, NULL, NULL, NULL); } DEFUN (no_ipv6_route_tag, no_ipv6_route_tag_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>", 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" "Set tag for this route\n" "Tag value\n") { return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, NULL); } DEFUN (no_ipv6_route_tag_vrf, no_ipv6_route_tag_vrf_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295>" VRF_CMD_STR, 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" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL, argv[3]); } ALIAS (no_ipv6_route, no_ipv6_route_flags_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") ALIAS (no_ipv6_route_tag, no_ipv6_route_flags_tag_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295>", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") 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, NULL, NULL, NULL); } DEFUN (no_ipv6_route_ifname_tag, no_ipv6_route_ifname_tag_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>", 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" "Set tag for this route\n" "Tag value\n") { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, NULL); } DEFUN (no_ipv6_route_ifname_tag_vrf, no_ipv6_route_ifname_tag_vrf_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295>" VRF_CMD_STR, 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" "Set tag for this route\n" "Tag value\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL, argv[4]); } ALIAS (no_ipv6_route_ifname, no_ipv6_route_ifname_flags_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") ALIAS (no_ipv6_route_ifname_tag, no_ipv6_route_ifname_flags_tag_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295>", 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n") DEFUN (no_ipv6_route_pref, no_ipv6_route_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], NULL, NULL, NULL, argv[2], NULL); } DEFUN (no_ipv6_route_pref_tag, no_ipv6_route_pref_tag_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3], NULL); } DEFUN (no_ipv6_route_pref_tag_vrf, no_ipv6_route_pref_tag_vrf_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-4294967295> <1-255>" VRF_CMD_STR, 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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3], argv[4]); } DEFUN (no_ipv6_route_flags_pref, no_ipv6_route_flags_pref_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") { /* We do not care about argv[2] */ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3], NULL); } DEFUN (no_ipv6_route_flags_pref_tag, no_ipv6_route_flags_pref_tag_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") { /* We do not care about argv[2] */ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], NULL); } DEFUN (no_ipv6_route_flags_pref_tag_vrf, no_ipv6_route_flags_pref_tag_vrf_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { /* We do not care about argv[2] */ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]); } 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], NULL, NULL, argv[3], NULL); } DEFUN (no_ipv6_route_ifname_pref_tag, no_ipv6_route_ifname_pref_tag_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], NULL); } DEFUN (no_ipv6_route_ifname_pref_tag_vrf, no_ipv6_route_ifname_pref_tag_vrf_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-4294967295> <1-255>" VRF_CMD_STR, 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" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4], argv[5]); } DEFUN (no_ipv6_route_ifname_flags_pref, no_ipv6_route_ifname_flags_pref_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], NULL); } DEFUN (no_ipv6_route_ifname_flags_pref_tag, no_ipv6_route_ifname_flags_pref_tag_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n") { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); } DEFUN (no_ipv6_route_ifname_flags_pref_tag_vrf, no_ipv6_route_ifname_flags_pref_tag_vrf_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-4294967295> <1-255>" VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Set tag for this route\n" "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); } DEFUN (ipv6_route_vrf, ipv6_route_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " VRF_CMD_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" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, NULL, argv[2]); } DEFUN (ipv6_route_flags_vrf, ipv6_route_flags_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) " VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL, argv[3]); } DEFUN (ipv6_route_ifname_vrf, ipv6_route_ifname_vrf_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE " VRF_CMD_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" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, NULL, argv[3]); } DEFUN (ipv6_route_ifname_flags_vrf, ipv6_route_ifname_flags_vrf_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) " VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL, argv[4]); } DEFUN (ipv6_route_pref_vrf, ipv6_route_pref_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255> " VRF_CMD_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" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, argv[2], argv[3]); } DEFUN (ipv6_route_flags_pref_vrf, ipv6_route_flags_pref_vrf_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3], argv[4]); } DEFUN (ipv6_route_ifname_pref_vrf, ipv6_route_ifname_pref_vrf_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255> " VRF_CMD_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" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3], argv[4]); } DEFUN (ipv6_route_ifname_flags_pref_vrf, ipv6_route_ifname_flags_pref_vrf_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255> " VRF_CMD_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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], argv[5]); } DEFUN (no_ipv6_route_vrf, no_ipv6_route_vrf_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL, (argc > 3) ? argv[3] : argv[2]); } ALIAS (no_ipv6_route_vrf, no_ipv6_route_flags_vrf_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) " VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) DEFUN (no_ipv6_route_ifname_vrf, no_ipv6_route_ifname_vrf_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL, (argc > 4) ? argv[4] : argv[3]); } ALIAS (no_ipv6_route_ifname_vrf, no_ipv6_route_ifname_flags_vrf_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) " VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" VRF_CMD_HELP_STR) DEFUN (no_ipv6_route_pref_vrf, no_ipv6_route_pref_vrf_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255> " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, argv[2], argv[3]); } DEFUN (no_ipv6_route_flags_pref_vrf, no_ipv6_route_flags_pref_vrf_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255> " VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { /* We do not care about argv[2] */ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3], argv[4]); } DEFUN (no_ipv6_route_ifname_pref_vrf, no_ipv6_route_ifname_pref_vrf_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255> " VRF_CMD_STR, 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" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3], argv[4]); } DEFUN (no_ipv6_route_ifname_flags_pref_vrf, no_ipv6_route_ifname_flags_pref_vrf_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255> " VRF_CMD_STR, 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" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR) { return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4], argv[5]); } 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; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show all IPv6 route. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ipv6_route, show_ipv6_route_vrf_cmd, "show ipv6 route " VRF_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" VRF_CMD_HELP_STR) DEFUN (show_ipv6_route_tag, show_ipv6_route_tag_cmd, "show ipv6 route tag <1-4294967295>", SHOW_STR IP_STR "IPv6 routing table\n" "Show only routes with tag\n" "Tag value\n") { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; route_tag_t tag = 0; vrf_id_t vrf_id = VRF_DEFAULT; if (argv[0]) tag = atoi(argv[0]); if (argc == 2) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show all IPv6 routes with matching tag value. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (rib->tag != tag) continue; if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ipv6_route_tag, show_ipv6_route_tag_vrf_cmd, "show ipv6 route tag <1-4294967295>" VRF_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "Show only routes with tag\n" "Tag value\n" VRF_CMD_HELP_STR) 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; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix (argv[0], &p); if (! ret) { vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (prefix_match (&p, &rn->p)) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ipv6_route_prefix_longer, show_ipv6_route_prefix_longer_vrf_cmd, "show ipv6 route X:X::X:X/M longer-prefixes " VRF_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 prefix\n" "Show route matching the specified Network/Mask pair only\n" VRF_CMD_HELP_STR) DEFUN (show_ipv6_route_protocol, show_ipv6_route_protocol_cmd, "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" QUAGGA_IP6_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; vrf_id_t vrf_id = VRF_DEFAULT; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (rib->type == type) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ipv6_route_protocol, show_ipv6_route_protocol_vrf_cmd, "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA " " VRF_CMD_STR, SHOW_STR IP_STR "IP routing table\n" QUAGGA_IP6_REDIST_HELP_STR_ZEBRA VRF_CMD_HELP_STR) 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; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix_ipv6 (argv[0], &p); if (ret <= 0) { vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); 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, 0); route_unlock_node (rn); return CMD_SUCCESS; } ALIAS (show_ipv6_route_addr, show_ipv6_route_addr_vrf_cmd, "show ipv6 route X:X::X:X " VRF_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 Address\n" VRF_CMD_HELP_STR) 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; vrf_id_t vrf_id = VRF_DEFAULT; ret = str2prefix_ipv6 (argv[0], &p); if (ret <= 0) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); 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); if (rn) route_unlock_node (rn); return CMD_WARNING; } vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); return CMD_SUCCESS; } ALIAS (show_ipv6_route_prefix, show_ipv6_route_prefix_vrf_cmd, "show ipv6 route X:X::X:X/M " VRF_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 prefix\n" VRF_CMD_HELP_STR) /* Show route summary. */ DEFUN (show_ipv6_route_summary, show_ipv6_route_summary_cmd, "show ipv6 route summary", SHOW_STR IP_STR "IPv6 routing table\n" "Summary of all IPv6 routes\n") { struct route_table *table; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; vty_show_ip_route_summary (vty, table); return CMD_SUCCESS; } ALIAS (show_ipv6_route_summary, show_ipv6_route_summary_vrf_cmd, "show ipv6 route summary " VRF_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "Summary of all IPv6 routes\n" VRF_CMD_HELP_STR) /* Show ipv6 route summary prefix. */ DEFUN (show_ipv6_route_summary_prefix, show_ipv6_route_summary_prefix_cmd, "show ipv6 route summary prefix", SHOW_STR IP_STR "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Prefix routes\n") { struct route_table *table; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return CMD_SUCCESS; vty_show_ip_route_summary_prefix (vty, table); return CMD_SUCCESS; } ALIAS (show_ipv6_route_summary_prefix, show_ipv6_route_summary_prefix_vrf_cmd, "show ipv6 route summary prefix " VRF_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Prefix routes\n" VRF_CMD_HELP_STR) /* * Show IPv6 mroute command.Used to dump * the Multicast routing table. */ DEFUN (show_ipv6_mroute, show_ipv6_mroute_cmd, "show ipv6 mroute", SHOW_STR IP_STR "IPv6 Multicast routing table\n") { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; vrf_id_t vrf_id = VRF_DEFAULT; if (argc > 0) VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]); table = zebra_vrf_table (AFI_IP6, SAFI_MULTICAST, vrf_id); if (! table) return CMD_SUCCESS; /* Show all IPv6 route. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } return CMD_SUCCESS; } ALIAS (show_ipv6_mroute, show_ipv6_mroute_vrf_cmd, "show ipv6 mroute " VRF_CMD_STR, SHOW_STR IP_STR "IPv6 Multicast routing table\n" VRF_CMD_HELP_STR) DEFUN (show_ipv6_route_vrf_all, show_ipv6_route_vrf_all_cmd, "show ipv6 route " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" VRF_ALL_CMD_HELP_STR) { struct route_table *table; struct route_node *rn; struct rib *rib; struct zebra_vrf *zvrf; vrf_iter_t iter; int first = 1; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) continue; /* Show all IPv6 route. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } DEFUN (show_ipv6_route_prefix_longer_vrf_all, show_ipv6_route_prefix_longer_vrf_all_cmd, "show ipv6 route X:X::X:X/M longer-prefixes " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 prefix\n" "Show route matching the specified Network/Mask pair only\n" VRF_ALL_CMD_HELP_STR) { struct route_table *table; struct route_node *rn; struct rib *rib; struct prefix p; struct zebra_vrf *zvrf; vrf_iter_t iter; int ret; int first = 1; ret = str2prefix (argv[0], &p); if (! ret) { vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) continue; /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (prefix_match (&p, &rn->p)) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } DEFUN (show_ipv6_route_protocol_vrf_all, show_ipv6_route_protocol_vrf_all_cmd, "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA " " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IP routing table\n" QUAGGA_IP6_REDIST_HELP_STR_ZEBRA VRF_ALL_CMD_HELP_STR) { int type; struct route_table *table; struct route_node *rn; struct rib *rib; struct zebra_vrf *zvrf; vrf_iter_t iter; int first = 1; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) continue; /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (rib->type == type) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } DEFUN (show_ipv6_route_addr_vrf_all, show_ipv6_route_addr_vrf_all_cmd, "show ipv6 route X:X::X:X " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 Address\n" VRF_ALL_CMD_HELP_STR) { int ret; struct prefix_ipv6 p; struct route_table *table; struct route_node *rn; struct zebra_vrf *zvrf; vrf_iter_t iter; ret = str2prefix_ipv6 (argv[0], &p); if (ret <= 0) { vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) continue; rn = route_node_match (table, (struct prefix *) &p); if (! rn) continue; vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); } return CMD_SUCCESS; } DEFUN (show_ipv6_route_prefix_vrf_all, show_ipv6_route_prefix_vrf_all_cmd, "show ipv6 route X:X::X:X/M " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 prefix\n" VRF_ALL_CMD_HELP_STR) { int ret; struct prefix_ipv6 p; struct route_table *table; struct route_node *rn; struct zebra_vrf *zvrf; vrf_iter_t iter; ret = str2prefix_ipv6 (argv[0], &p); if (ret <= 0) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) continue; rn = route_node_match (table, (struct prefix *) &p); if (! rn) continue; if (rn->p.prefixlen != p.prefixlen) { route_unlock_node (rn); continue; } vty_show_ip_route_detail (vty, rn, 0); route_unlock_node (rn); } return CMD_SUCCESS; } /* Show route summary. */ DEFUN (show_ipv6_route_summary_vrf_all, show_ipv6_route_summary_vrf_all_cmd, "show ipv6 route summary " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "Summary of all IPv6 routes\n" VRF_ALL_CMD_HELP_STR) { struct zebra_vrf *zvrf; vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) vty_show_ip_route_summary (vty, zvrf->table[AFI_IP6][SAFI_UNICAST]); return CMD_SUCCESS; } DEFUN (show_ipv6_mroute_vrf_all, show_ipv6_mroute_vrf_all_cmd, "show ipv6 mroute " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IPv6 Multicast routing table\n" VRF_ALL_CMD_HELP_STR) { struct route_table *table; struct route_node *rn; struct rib *rib; struct zebra_vrf *zvrf; vrf_iter_t iter; int first = 1; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (table = zvrf->table[AFI_IP6][SAFI_UNICAST]) == NULL) continue; /* Show all IPv6 route. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); } } return CMD_SUCCESS; } DEFUN (show_ipv6_route_summary_prefix_vrf_all, show_ipv6_route_summary_prefix_vrf_all_cmd, "show ipv6 route summary prefix " VRF_ALL_CMD_STR, SHOW_STR IP_STR "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Prefix routes\n" VRF_ALL_CMD_HELP_STR) { struct zebra_vrf *zvrf; vrf_iter_t iter; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) if ((zvrf = vrf_iter2info (iter)) != NULL) vty_show_ip_route_summary_prefix (vty, zvrf->table[AFI_IP6][SAFI_UNICAST]); return CMD_SUCCESS; } /* Write IPv6 static route configuration. */ static int static_config_ipv6 (struct vty *vty) { struct route_node *rn; struct static_route *si; int write; char buf[BUFSIZ]; struct route_table *stable; struct zebra_vrf *zvrf; vrf_iter_t iter; write = 0; for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) { if ((zvrf = vrf_iter2info (iter)) == NULL || (stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]) == NULL) continue; for (rn = route_top (stable); rn; rn = route_next (rn)) for (si = rn->info; si; si = si->next) { vty_out (vty, "ipv6 route %s", prefix2str (&rn->p, buf, sizeof buf)); switch (si->type) { case STATIC_IPV6_GATEWAY: vty_out (vty, " %s", inet_ntop (AF_INET6, &si->addr.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->addr.ipv6, buf, BUFSIZ), si->ifname); break; } if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) vty_out (vty, " %s", "reject"); if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) vty_out (vty, " %s", "blackhole"); if (si->tag) vty_out (vty, " tag %d", si->tag); if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); if (si->vrf_id != VRF_DEFAULT) vty_out (vty, " vrf %u", si->vrf_id); vty_out (vty, "%s", VTY_NEWLINE); write = 1; } } return write; } /* Static ip route configuration write function. */ static int zebra_ip_config (struct vty *vty) { int write = 0; write += static_config_ipv4 (vty, SAFI_UNICAST, "ip route"); write += static_config_ipv4 (vty, SAFI_MULTICAST, "ip mroute"); #ifdef HAVE_IPV6 write += static_config_ipv6 (vty); #endif /* HAVE_IPV6 */ return write; } static int config_write_vty(struct vty *vty) { int i; enum multicast_mode ipv4_multicast_mode = multicast_mode_ipv4_get (); if (ipv4_multicast_mode != MCAST_NO_CONFIG) vty_out (vty, "ip multicast rpf-lookup-mode %s%s", ipv4_multicast_mode == MCAST_URIB_ONLY ? "urib-only" : ipv4_multicast_mode == MCAST_MRIB_ONLY ? "mrib-only" : ipv4_multicast_mode == MCAST_MIX_MRIB_FIRST ? "mrib-then-urib" : ipv4_multicast_mode == MCAST_MIX_DISTANCE ? "lower-distance" : "longer-prefix", VTY_NEWLINE); for (i=0;i #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 "privs.h" #include "network.h" #include "buffer.h" #include "vrf.h" #include "nexthop.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" #include "zebra/zebra_rnh.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; extern struct zebra_t zebrad; static void zebra_event (enum event event, int sock, struct zserv *client); extern struct zebra_privs_t zserv_privs; static void zebra_client_close (struct zserv *client); static int zserv_delayed_close(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); client->t_suicide = NULL; zebra_client_close(client); return 0; } /* When client connects, it sends hello message * with promise to send zebra routes of specific type. * Zebra stores a socket fd of the client into * this array. And use it to clean up routes that * client didn't remove for some reasons after closing * connection. */ static int route_type_oaths[ZEBRA_ROUTE_MAX]; static int zserv_flush_data(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); client->t_write = NULL; if (client->t_suicide) { zebra_client_close(client); return -1; } switch (buffer_flush_available(client->wb, client->sock)) { case BUFFER_ERROR: zlog_warn("%s: buffer_flush_available failed on zserv client fd %d, " "closing", __func__, client->sock); zebra_client_close(client); break; case BUFFER_PENDING: client->t_write = thread_add_write(zebrad.master, zserv_flush_data, client, client->sock); break; case BUFFER_EMPTY: break; } client->last_write_time = quagga_time(NULL); return 0; } int zebra_server_send_message(struct zserv *client) { if (client->t_suicide) return -1; stream_set_getp(client->obuf, 0); client->last_write_cmd = stream_getw_from(client->obuf, 4); switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf), stream_get_endp(client->obuf))) { case BUFFER_ERROR: zlog_warn("%s: buffer_write failed to zserv client fd %d, closing", __func__, client->sock); /* Schedule a delayed close since many of the functions that call this one do not check the return code. They do not allow for the possibility that an I/O error may have caused the client to be deleted. */ client->t_suicide = thread_add_event(zebrad.master, zserv_delayed_close, client, 0); return -1; case BUFFER_EMPTY: THREAD_OFF(client->t_write); break; case BUFFER_PENDING: THREAD_WRITE_ON(zebrad.master, client->t_write, zserv_flush_data, client, client->sock); break; } client->last_write_time = quagga_time(NULL); return 0; } void zserv_create_header (struct stream *s, uint16_t cmd, vrf_id_t vrf_id) { /* length placeholder, caller can update */ stream_putw (s, ZEBRA_HEADER_SIZE); stream_putc (s, ZEBRA_HEADER_MARKER); stream_putc (s, ZSERV_VERSION); stream_putw (s, vrf_id); stream_putw (s, cmd); } static void zserv_encode_interface (struct stream *s, struct interface *ifp) { /* Interface information. */ stream_put (s, ifp->name, INTERFACE_NAMSIZ); stream_putl (s, ifp->ifindex); stream_putc (s, ifp->status); stream_putq (s, ifp->flags); stream_putl (s, ifp->metric); stream_putl (s, ifp->mtu); stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); stream_putl (s, ifp->ll_type); stream_putl (s, ifp->hw_addr_len); if (ifp->hw_addr_len) stream_put (s, ifp->hw_addr, ifp->hw_addr_len); zlog_info("Try to set TE Link Param"); /* Then, Traffic Engineering parameters if any */ if (HAS_LINK_PARAMS(ifp) && IS_LINK_PARAMS_SET(ifp->link_params)) { stream_putc (s, 1); zebra_interface_link_params_write (s, ifp); } else stream_putc (s, 0); /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); } /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */ /* * This function is called in the following situations: * - in response to a 3-byte ZEBRA_INTERFACE_ADD request * from the client. * - at startup, when zebra figures out the available interfaces * - when an interface is added (where support for * RTM_IFANNOUNCE or AF_NETLINK sockets is available), or when * an interface is marked IFF_UP (i.e., an RTM_IFINFO message is * received) */ int zsend_interface_add (struct zserv *client, struct interface *ifp) { struct stream *s; /* Check this client need interface information. */ if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id)) return 0; s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface (s, ifp); client->ifadd_cnt++; return zebra_server_send_message(client); } /* 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 (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id)) return 0; s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface (s, ifp); client->ifdel_cnt++; return zebra_server_send_message (client); } int zsend_interface_link_params (struct zserv *client, struct interface *ifp) { struct stream *s; /* Check this client need interface information. */ if (! client->ifinfo) return 0; if (!ifp->link_params) return 0; s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); /* Add Interface Index */ stream_putl (s, ifp->ifindex); /* Then TE Link Parameters */ if (zebra_interface_link_params_write (s, ifp) == 0) return 0; /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); return zebra_server_send_message (client); } /* Interface address is added/deleted. Send ZEBRA_INTERFACE_ADDRESS_ADD or * ZEBRA_INTERFACE_ADDRESS_DELETE to the client. * * A ZEBRA_INTERFACE_ADDRESS_ADD is sent in the following situations: * - in response to a 3-byte ZEBRA_INTERFACE_ADD request * from the client, after the ZEBRA_INTERFACE_ADD has been * sent from zebra to the client * - redistribute new address info to all clients in the following situations * - at startup, when zebra figures out the available interfaces * - when an interface is added (where support for * RTM_IFANNOUNCE or AF_NETLINK sockets is available), or when * an interface is marked IFF_UP (i.e., an RTM_IFINFO message is * received) * - for the vty commands "ip address A.B.C.D/M [|